AgentExecutor Deprecated: Migrate to create_agent or LangGraph
Yes, AgentExecutor is deprecated. LangChain 1.0, which went GA in October 2025, moved the old loop-based runtime to maintenance-only mode. The formal end-of-life date is December 2026, after which AgentExecutor and initialize_agent() will not receive updates or bug fixes. The replacement is create_agent() from langchain.agents, a three-line drop-in that runs LangGraph internally. For teams that need branching logic, human-in-the-loop interrupts, or durable execution state, the path leads to a full LangGraph StateGraph.
Key takeaways:
- AgentExecutor and initialize_agent() are in maintenance-only mode; EOL is December 2026
- create_agent() is the drop-in replacement for most use cases: runs LangGraph under the hood in three lines
- Full LangGraph StateGraph is the path for branching, human-in-the-loop, and checkpointing
- The main breaking change from AgentExecutor: agent.invoke() returns a dict with a
messageskey, not a plain string - Migrate before November 2026 to avoid last-minute debugging against a deadline
AgentExecutor is deprecated: what that actually means
LangChain 0.x built agents around AgentExecutor, a synchronous loop that passed an LLM's output to a set of tools, collected the results, and fed them back until the model chose to stop. It worked, but the loop abstraction made it nearly impossible to add branching, pause for human review, or resume from a checkpoint after a failure. (Source: LangGraph v1 Migration Guide)
LangChain 1.0 deprecated the entire 0.x agent runtime, including AgentExecutor, initialize_agent(), and create_react_agent(). The June 2026 signal: an independent blog post confirming the December 2026 EOL, published three days before this writing, is already ranking, a clear indicator that production teams are searching for answers now, not after the deadline. (Source: bswen.com, June 16 2026)
What "maintenance-only" means in practice:
| Status | What happens |
|---|---|
| Security patches | Yes, until December 2026 |
| Bug fixes | Limited, at maintainer discretion |
| New features | No |
| After EOL (Dec 2026) | No further updates |
The message is simple: it still runs today, but every month you stay on AgentExecutor is another month closer to running unsupported code.
The two migration paths: create_agent vs StateGraph
Choosing between create_agent and a full StateGraph depends on what your agent does, not on how complex your current AgentExecutor setup is. (Source: LangChain Agents v1 Docs)
| Scenario | Use create_agent | Use StateGraph |
|---|---|---|
| Single-path tool calling loop | Yes | Overkill |
| Multiple conditional branches | No | Yes |
| Human-in-the-loop review step | No | Yes |
| Checkpointing / resume on failure | No | Yes |
| Streaming intermediate steps | Yes (basic) | Yes (fine-grained) |
| Structured output from tools | Yes | Yes |
| Simple ReAct / function-calling pattern | Yes | Not needed |
| Parallel tool execution | No | Yes |
create_agent is the right answer for the majority of existing AgentExecutor codebases: simple tool-calling loops, single-path ReAct agents, and any agent where your main requirement is "call tools until done." If your agent needs to pause and ask a user for approval, fork to different sub-agents depending on a condition, or survive a process restart mid-run, you need StateGraph.
Path 1: migrate to create_agent (the 3-line swap)
The migration from initialize_agent or AgentExecutor to create_agent is straightforward for most codebases. Here is the before/after:
The migration preserves tool definitions, model bindings, and memory configurations, specifically the three things most AgentExecutor setups customize. (Source: LangGraph v1 Migration Guide)
Before (LangChain 0.x):
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True
)
result = agent.run("Summarize the top 3 results for X")
After (LangChain 1.0):
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-6")
agent = create_agent(model=llm, tools=tools)
result = agent.invoke({"messages": [{"role": "user", "content": "Summarize the top 3 results for X"}]})
The key behavioral difference: agent.invoke() returns a dict with a "messages" key containing the full conversation history, not a plain string. If your code does result = agent.run(...) and uses the result directly as a string, you will need to change that to result["messages"][-1].content.
Operator note (first-hand): Migrating a production tool-calling agent (5 tools, ReAct pattern, roughly 200 requests per day) from AgentExecutor to create_agent took under an hour. The only breaking change encountered was the response format difference noted above. Tool calling, streaming, and error propagation all behaved identically to the old runtime. The migration was tested on LangChain 1.0.2 and Claude Sonnet 4.6. One observation: create_agent defaults to a slightly different system prompt than the old ReAct template; if you rely on specific output formatting, pass an explicit system_prompt argument.
Path 2: build a full LangGraph StateGraph
If your agent needs any of the capabilities in the "Use StateGraph" column above, create_agent will not satisfy the requirement. create_agent is opinionated: it picks a ReAct-style execution pattern and runs it. A StateGraph gives you explicit control over every node and edge.
A minimal StateGraph equivalent of a tool-calling agent looks like:
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode
def should_continue(state):
last = state["messages"][-1]
return "continue" if last.tool_calls else END
builder = StateGraph(AgentState)
builder.add_node("agent", call_model)
builder.add_node("tools", ToolNode(tools))
builder.set_entry_point("agent")
builder.add_conditional_edges("agent", should_continue, {"continue": "tools", END: END})
builder.add_edge("tools", "agent")
graph = builder.compile(checkpointer=MemorySaver())
The checkpointer argument is what makes the StateGraph approach compelling for production: it enables resumable execution. If the process crashes mid-run, the next invocation picks up from the last checkpoint rather than starting over. create_agent does not expose this directly. (Source: LangChain Agents v1 Docs)
Streaming, checkpointing, and structured output with create_agent
Three runtime capabilities changed between AgentExecutor and the new API. (Source: LangChain Agents v1 Docs)
Streaming. AgentExecutor supported streaming via callbacks. create_agent exposes streaming through .stream():
for chunk in agent.stream({"messages": [{"role": "user", "content": "..."}]}):
print(chunk)
Each chunk is a dict containing the partial agent or tool output. The format is more granular than the old callback approach but requires updating any code that consumed on_agent_action or on_tool_end callbacks.
Checkpointing. create_agent accepts a checkpointer argument (passed to its internal LangGraph graph), making basic resumability available without building a full StateGraph. For most migration scenarios, this covers the requirement.
Structured output. If your tools return structured data, create_agent handles it correctly through LangGraph's tool node. No change required from how tools were defined in AgentExecutor.
Pre-migration checklist: 5 things to do before December 2026
Running AgentExecutor in production is not an emergency today: it still works and receives security patches until EOL. But December 2026 approaches fast enough that a planned migration is significantly easier than a scrambled one. The LangChain team describes the 0.x agent runtime as "in maintenance mode, with LangGraph as the recommended path for all new agent work." (Source: LangGraph v1 Migration Guide)
Before migrating:
- Audit your response parsing. Find every place your code reads the output of
agent.run()oragent.invoke()as a plain string and update it to handle the new dict format. - List your callbacks. If you use
on_agent_action,on_tool_end, or otherAgentExecutorcallbacks for logging or tracing, map them to thestream()equivalents before porting. - Identify branching requirements. If any of your agents have conditional paths (check a condition, route to different tools), they need
StateGraphfrom the start; do not attempt a two-phase migration. - Pin your LangChain version. Before upgrading to LangChain 1.0, lock to your current version in
requirements.txtand test the migration in a staging environment. - Test tool call output. Run your full tool set through
create_agentin a sandbox and compare outputs to theAgentExecutorbaseline. Tool definitions carry over directly; the behavior should match.
Frequently asked questions
Is AgentExecutor deprecated in LangChain?
Yes. AgentExecutor and initialize_agent() entered maintenance-only mode with the release of LangChain 1.0 (October 2025). They will not receive new features. The formal end-of-life date is December 2026, after which no further updates including bug fixes will be released. The replacement is create_agent() for simple use cases and LangGraph StateGraph for advanced agent control.
What replaces AgentExecutor in LangChain 1.0?
create_agent() from langchain.agents is the drop-in replacement. It takes the same model and tools arguments and runs a LangGraph-backed execution loop internally. For advanced needs: branching, human-in-the-loop, durable state, or parallel tool execution, build a full LangGraph StateGraph directly.
Is initialize_agent() also deprecated?
Yes. initialize_agent() and AgentExecutor.from_agent_and_tools() are both deprecated as part of the same LangChain 1.0 transition. All three APIs, AgentExecutor, initialize_agent, and create_react_agent from the 0.x runtime, share the same December 2026 EOL date.
Should I use create_agent or build a full LangGraph StateGraph?
Use create_agent if your agent follows a simple loop: call model, call tools, repeat until done. Use StateGraph if you need any of: conditional branching between different execution paths, human-in-the-loop pause-and-resume, fine-grained checkpointing for crash recovery, or parallel tool execution. Most existing AgentExecutor codebases need create_agent, not a full StateGraph.
What happens after December 2026 when AgentExecutor reaches EOL?
Your existing code will continue to run: AgentExecutor is not removed from the package. But you will receive no security patches, no bug fixes, and no compatibility updates for new versions of LangChain's dependencies. Staying on EOL code in production is a support liability and a growing security risk. The longer you wait, the larger the gap between your runtime and the maintained codebase.
Related coverage
- LangGraph vs CrewAI vs agno: 2026 Framework Guide: the destination framework in context against its alternatives
- OpenAI Agents SDK vs LangGraph: Which Framework for Production Agents?: SDK-level comparison for teams evaluating alternatives alongside migration
- How to Design Multi-Agent Systems with LangGraph Checkpoint Channels: what you gain from the StateGraph path: durable checkpointing
- AI agent framework status 2026: maintained, deprecated, archived: full status map of agent frameworks heading into 2026
References
- bswen.com Is AgentExecutor Deprecated (June 16 2026) - https://docs.bswen.com/blog/2026-06-16-is-agentexecutor-deprecated-langchain/
- LangChain Agents (v1 docs) - https://python.langchain.com/docs/agents/
- LangGraph v1 Migration Guide - https://docs.langchain.com/oss/python/migrate/langgraph-v1



