Course Content
LangChain Mastery
7 sections · 109 lessons
What is the role of the agent executor in LangChain?
What you need to know
Two parts: decider and runner
It helps to split an agent into two pieces:
- The agent (the decider): the model plus prompt plus tool schemas. Given the conversation so far, it returns one decision — call these tools, or answer.
- The executor (the runner): code that calls the decider, runs the chosen tool, records the result, and calls the decider again.
The model never runs anything. Every tool execution, every retry and every limit lives in the runner.
What AgentExecutor did
1# Legacy: LangChain 0.x, now in langchain-classic2from langchain_classic.agents import AgentExecutor, create_tool_calling_agent34agent = create_tool_calling_agent(llm, tools, prompt) # prompt needs agent_scratchpad5executor = AgentExecutor(6 agent=agent, tools=tools,7 max_iterations=6, # stop runaway loops8 max_execution_time=30, # wall-clock cap, seconds9 handle_parsing_errors=True,10 return_intermediate_steps=True,11)12executor.invoke({"input": "Is SKU X200 in stock?"})Its responsibilities: run the loop, look up tools by name, keep the scratchpad (the list of past actions and observations fed back into the prompt), stop on limits, and optionally return the intermediate steps.
The current equivalent
1from langchain.agents import create_agent2from langchain.agents.middleware import ModelCallLimitMiddleware34agent = create_agent(5 model, tools=tools,6 system_prompt="You are a store assistant.",7 middleware=[ModelCallLimitMiddleware(run_limit=6, exit_behavior="end")],8)9agent.invoke({"messages": [{"role": "user", "content": "Is SKU X200 in stock?"}]},10 config={"recursion_limit": 20})The runner is now a LangGraph graph with a model node and a tools node. The scratchpad is simply the messages list in the graph state.
AgentExecutor option | LangChain 1.x equivalent |
|---|---|
max_iterations | ModelCallLimitMiddleware(run_limit=...) or recursion_limit |
max_execution_time | a timeout around invoke, plus per-tool timeouts |
handle_parsing_errors | not needed: native tool calls are not parsed from text |
return_intermediate_steps | the returned messages list already contains every step |
memory= | a checkpointer plus a thread_id |
| (not available) | human approval, streaming each step, resuming after a crash |
One detail worth knowing: LangGraph's default recursion_limit is very high (10,007 steps in LangGraph 1.2; it was 25 in early versions), far above the 15 iterations AgentExecutor allowed by default. Set a limit yourself; the default will not save your bill.
A real-life example
A help-centre support bot built in 2024 used AgentExecutor with max_iterations=6. Two problems kept coming up: when a pod restarted mid-conversation the agent lost everything, and the team could not add "ask a human before issuing a refund over Rs 2,000".
They migrated to create_agent with a Postgres checkpointer and HumanInTheLoopMiddleware on the issue_refund tool. The loop logic did not change — same tools, same prompt — but the graph now saves state after every step. A restart resumes from the last checkpoint, and a refund pauses the run until a support lead approves it in the dashboard. They kept a ModelCallLimitMiddleware(run_limit=6) to match the old iteration cap.
Follow-up questions to expect
- "What is the agent scratchpad?" — The running record of tool calls and their results that is sent back to the model each step; in
create_agentit is just the message list. - "Why move off
AgentExecutor?" — It is legacy and has no persistence, interrupts or step-by-step streaming; the LangGraph runtime has all three. - "What happens when the limit is hit?" — With
exit_behavior="end"the run stops and returns what it has; with"error"it raises, so you can show a fallback message.