如果你在网上搜「LangChain 教程」,大概率会搜到三套长得完全不一样的代码:initialize_agent、AgentExecutor、create_react_agent,还有新出现的 create_agent。这不是四个并行的选择,而是一条弃用时间线:前三套都已弃用或进入维护模式,LangChain 1.x 的标准写法是 langchain.agents 里的 create_agent,官方建议在 2026 年 12 月前完成旧代码迁移。本篇带你把最常见的三类旧写法逐段迁到新 API,顺带把持久化、人工审批这些以前很难加的能力一次性配齐。
先理解:三套旧 API 与新标准的关系
迁移之前先把关系图理清,不然很容易改到一半发现改错了对象:
| API | 现状 | 迁移方向 |
|---|---|---|
| initialize_agent(2023) | 已弃用 | 直接改写为 create_agent |
| AgentExecutor(2023-2024) | 维护模式,官方建议 2026 年 12 月前迁走 | 改写为 create_agent;底层从 Python 黑盒循环换成 LangGraph 图运行时 |
| create_react_agent(langgraph.prebuilt) | 已弃用,由 create_agent 取代 | 统一入口改到 langchain.agents.create_agent,钩子参数改用 Middleware 表达 |
| create_agent(langchain.agents) | 现行标准 | ——;需要更细控制时再下沉到 LangGraph StateGraph |
这次重构的本质变化是运行时:AgentExecutor 是一个黑盒 Python 循环,会话绑定、难持久化、难干预;create_agent 构建出的智能体跑在 LangGraph 图运行时上,持久化、流式、断点恢复、人工介入都是一等公民。所以迁移不只是换个函数名——换来的是一整层新能力。
版本敏感,先对齐再动手。LangChain 与 LangGraph 自 2025 年 10 月双双 GA 1.0 后承诺语义化版本,但周边包(langchain-community、各家集成包)版本组合很多,本文写作时主线在 langchain-core 1.4.x、LangGraph 1.2.x 一带。API 签名以你安装版本的官方文档为准,遇到参数对不上先查文档而不是硬猜。另外 1.x 要求 Python 3.10+,3.9 及以下需要先升解释器。
Step 1:升级依赖,盘点存量旧写法
# 升级主包(建议在虚拟环境里做)
pip install -U langchain langgraph
# 确认版本
python -c "import langchain, langgraph; print(langchain.__version__, langgraph.__version__)"
# 盘点项目里的旧 API 用点(迁移清单)
# Linux / macOS
grep -rn "AgentExecutor\|initialize_agent\|create_react_agent" --include="*.py" .
# Windows PowerShell
Select-String -Path .\*\*.py -Pattern "AgentExecutor|initialize_agent|create_react_agent"
把 grep 出来的文件逐个登记成迁移清单,按「先跑通一个最小智能体 → 再逐文件改写」的顺序推进。不要试图一口气全改——新旧行为有差异(输入输出结构变了),一个文件一个文件改、改完立刻跑回归,比大爆炸式重写稳得多。
pip install -U langchain-community。主包与社区包版本错位是升级后 import 报错的常见根因。Step 2:写一个 create_agent 最小可用版
from langchain.agents import create_agent
# 工具就是普通 Python 函数,写清类型标注与 docstring
# (docstring 是模型判断「什么时候调这个工具」的依据,别偷懒)
def get_weather(city: str) -> str:
"""查询指定城市今天的天气。"""
# 这里换成你的真实数据源
return city + " 今天晴,25 度"
def search_notes(query: str) -> str:
"""在团队笔记库里检索相关内容。"""
return "(检索结果示意)"
agent = create_agent(
model="openai:gpt-4o-mini", # 字符串简写或任意 ChatModel 实例
tools=[get_weather, search_notes],
system_prompt="你是团队助手,回答前先用工具查证,查不到就直说。",
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "北京今天适合户外团建吗?"}]}
)
print(result["messages"][-1].content)
预期效果:模型先调 get_weather(可能再调 search_notes),拿到工具结果后给出结论。注意输入输出结构的变化——输入输出统一走 messages,不再有 0.x 时代 {"input": ...} / {"output": ...} 那种扁平结构。后续所有改写都围绕这一点。
Step 3:迁移 AgentExecutor / initialize_agent 旧代码
# ---------- 旧写法(0.x,不要再学网上 2023 年教程里的这种) ----------
from langchain.agents import AgentExecutor, create_openai_tools_agent
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, max_iterations=5, verbose=True)
result = executor.invoke({"input": "北京天气怎么样?"})
print(result["output"])
# ---------- 新写法(1.x) ----------
from langchain.agents import create_agent
agent = create_agent(
model=llm,
tools=tools,
system_prompt="你是团队助手。", # 替代过去的 prompt 模板拼装
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "北京天气怎么样?"}]},
# 循环上限从 max_iterations 变为递归上限配置
config={"recursion_limit": 30},
)
print(result["messages"][-1].content)
改写时的三个对照点:其一,提示词不再用 PromptTemplate 拼装进 agent 工厂,直接给 system_prompt;其二,循环上限从 max_iterations 换成图运行时的 recursion_limit;其三,verbose 日志换成了 agent.stream()——想看中间步骤,用流式输出观察每个节点的进出,信息量比旧的 verbose 大得多。
别漏改调用方的输入输出结构。迁移最常翻车的位置不在工厂函数,而在调用方:所有 invoke({"input": ...}) 和 result["output"] 都要改成 messages 形态。只改构建、不改调用,报错会以「messages 字段不存在」的形式出现在运行期。
Step 4:迁移 create_react_agent,钩子参数换成 Middleware
# ---------- 旧写法(langgraph.prebuilt) ----------
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model, tools,
pre_model_hook=my_hook, # 调模型前干预
post_model_hook=my_other_hook, # 调模型后干预
state_modifier=system_prompt,
)
# ---------- 新写法(1.x):统一入口 + Middleware ----------
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
agent = create_agent(
model, tools,
system_prompt="你是团队助手。",
middleware=[
# 官方内置中间件之一:历史过长自动摘要压缩
SummarizationMiddleware(model=llm, max_tokens_before_summary=4000),
# 自定义中间件类实现 before_model / after_model 等钩子
MyLoggingMiddleware(),
],
)
Middleware 是这次重构里含金量最高的设计:每个中间件只管一件事(日志、审批、摘要、限流容错),在智能体循环的固定时机挂钩子,彼此自由组合。过去写在 pre_model_hook 里的逻辑,搬到自定义 Middleware 的 before_model 方法里,行为等价但可复用可测试。官方还提供 create_deep_agent,把文件系统、摘要、子代理、提示缓存这类长任务常用件预装成一套中间件栈,长流程任务可以直接用它起步。
Step 5:给智能体接上跨轮次持久化
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="openai:gpt-4o-mini",
tools=[search_notes],
system_prompt="你是团队助手。",
checkpointer=InMemorySaver(), # 本地开发用;生产换数据库实现
)
cfg = {"configurable": {"thread_id": "user-1024"}}
agent.invoke({"messages": [{"role": "user", "content": "记住:我们周五发版"}]}, cfg)
agent.invoke({"messages": [{"role": "user", "content": "发版是哪天来着?"}]}, cfg)
# 模型能答出「周五」——同 thread_id 的历史被自动带上
0.x 时代的 ConversationBufferMemory 之类记忆类全部退役,统一收敛为 checkpointer 机制:每轮结束后状态存进 checkpoint,下一轮凭 thread_id 续上。thread_id 决定隔离边界——一个用户一个 ID、一个会话一个 ID,按业务语义起名,别图省事全用同一个。生产环境把 InMemorySaver 换成数据库后端的 checkpointer(重启不丢、可多进程共享);部署到 LangSmith 平台时会自动配好,本地才需要显式传。
Step 6:把人工审批做成中间件
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
agent = create_agent(
model=llm,
tools=[read_report, send_email, delete_record], # 一写一删,都属高危
system_prompt="你是运维助手。",
middleware=[
HumanInTheLoopMiddleware(
# 对指定工具启用人工审批:调用前中断,等人批准或拒绝
interrupt_on={
"send_email": True, # 每次发信都要人确认
"delete_record": True, # 删除操作同样拦下
},
),
],
checkpointer=checkpointer, # 人工介入必须配持久化,中断状态要能存取
)
跑起来后的行为:模型决定调 send_email 时,运行中断并抛出审批请求,由你的界面(CLI、Web、企业IM 都行)转给值班人;批准后从断点续跑,拒绝则把「人类否决」作为结果回给模型。这就是图运行时带来的能力——0.x 的黑盒循环里,这种「中途暂停等人」要么做不了,要么得自己 hack 执行器。
人工审批的名字在版本间变过:早期 LangGraph 版本里的 HumanInterruptConfig / HumanInterrupt 等命名已被 InterruptOnConfig 一类新命名取代,不同小版本的参数形态有差异。以你安装版本的官方文档为准,报 ImportError 时优先怀疑类名过时。
Step 7:判断什么时候直接下沉到 LangGraph
出现以下任一需求时,跳过 create_agent,直接写 LangGraph:
□ 并行执行:多个节点同时跑,需要 Send API 手动派发
□ Supervisor-Worker 多智能体:自定义子图与跨图通信
□ 复杂分支:路由逻辑超出「模型决定调哪个工具」的范畴
□ 精细重试:要对单个节点做独立的错误处理与补偿
官方建议的路径(也是社区验证过的经验):
先用 create_agent 起步 → 遇到上面这些情况再下沉 StateGraph
这不是绕路,而是被设计好的演进路径
下沉时状态用显式的 TypedDict 定义,每个节点读状态、改状态,边和条件边决定流向;把 Step 5 的 checkpointer 机制带过去,持久化语义完全一致。此前站内已有 LangGraph 有状态工作流的专篇,这里不展开图 API 细节,只强调一条判断标准:「模型在循环里自主调工具」用 create_agent,「你要精确控制每一步怎么走」用 StateGraph。两者共用一套运行时,互相迁移的成本不高,不必一步到位。
常见问题速查
| 你遇到的现象 | 大概率原因 & 解决 |
|---|---|
| ImportError: cannot import AgentExecutor | 装到了 1.x 但代码还是 0.x 写法。按 Step 3 对照表改写,别试图从 1.x 里「找回」旧类 |
| 报错 messages 字段不存在 | 调用方还在用 {"input": ...} 旧结构。输入输出统一改成 messages 形态 |
| 升级后 import langchain_community 各类报错 | 主包与社区包版本错位。pip install -U langchain-community 对齐后重装 |
| GraphRecursionError | 递归上限被打满。核对 recursion_limit 配置,同时检查是否出现工具反复调用的死循环 |
| 多轮对话没有记忆 | 没配 checkpointer,或每次 invoke 用了不同的 thread_id |
| 人工审批不生效 | 中间件没挂上、工具名拼写不一致,或没配 checkpointer(中断状态存不下) |
| Python 3.9 装不上 1.x | 1.x 要求 Python 3.10+。先升解释器再迁代码 |