进阶 📋 7 个步骤 第 478 / 481 篇

LangChain 1.x 实操迁移:从 AgentExecutor 与 create_react_agent 迁到 create_agent

LangChain 1.x 迁移实操:create_agent 标准工厂、AgentExecutor 对照改写、create_react_agent 钩子转 Middleware、checkpointer 持久化与 thread_id、人工审批中间件与 StateGraph 下沉判断。

2026.09.27· 24 分钟阅读· 约 2929 字· 🔗 LangChain 1.x / 🧱 create_agent

如果你在网上搜「LangChain 教程」,大概率会搜到三套长得完全不一样的代码:initialize_agent、AgentExecutor、create_react_agent,还有新出现的 create_agent。这不是四个并行的选择,而是一条弃用时间线:前三套都已弃用或进入维护模式,LangChain 1.x 的标准写法是 langchain.agents 里的 create_agent,官方建议在 2026 年 12 月前完成旧代码迁移。本篇带你把最常见的三类旧写法逐段迁到新 API,顺带把持久化、人工审批这些以前很难加的能力一次性配齐。

🎯 适合人群:手上有跑着的 LangChain 0.x 代码(AgentExecutor / initialize_agent / create_react_agent 任一形态)、准备升级到 1.x 的 Python 开发者。需要 Python 3.10+ 环境与大模型 API Key。

先理解:三套旧 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:升级依赖,盘点存量旧写法

1 装齐 1.x,把项目里的旧 API 揪出来
# 升级主包(建议在虚拟环境里做)
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 出来的文件逐个登记成迁移清单,按「先跑通一个最小智能体 → 再逐文件改写」的顺序推进。不要试图一口气全改——新旧行为有差异(输入输出结构变了),一个文件一个文件改、改完立刻跑回归,比大爆炸式重写稳得多。

💡 如果项目里还有 langchain-community 依赖,升级时一并 pip install -U langchain-community。主包与社区包版本错位是升级后 import 报错的常见根因。

Step 2:写一个 create_agent 最小可用版

2 三要素起步:模型、工具、系统提示
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 旧代码

3 对照改写:换入口、换输入输出、换循环控制
# ---------- 旧写法(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

4 散落的 hook 参数,收进可组合的中间件
# ---------- 旧写法(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,把文件系统、摘要、子代理、提示缓存这类长任务常用件预装成一套中间件栈,长流程任务可以直接用它起步。

💡 迁移期间有个辨析题常被问:create_react_agent 要不要保留?答案是不用。它已被官方标记弃用、由 create_agent 取代;需要显式流程控制时,正确方向是直接写 LangGraph StateGraph(Step 7),而不是抱着旧工厂。

Step 5:给智能体接上跨轮次持久化

5 checkpointer + thread_id,会话可恢复可回放
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 平台时会自动配好,本地才需要显式传。

💡 持久化还附赠一个调试利器:因为每一步都有 checkpoint,你可以「时间旅行」——回到历史某一步改输入重跑,排查「它当时为什么这么决定」时极其好用。

Step 6:把人工审批做成中间件

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

7 create_agent 是快车道,StateGraph 是工程车道
出现以下任一需求时,跳过 create_agent,直接写 LangGraph:
□ 并行执行:多个节点同时跑,需要 Send API 手动派发
□ Supervisor-Worker 多智能体:自定义子图与跨图通信
□ 复杂分支:路由逻辑超出「模型决定调哪个工具」的范畴
□ 精细重试:要对单个节点做独立的错误处理与补偿

官方建议的路径(也是社区验证过的经验):
先用 create_agent 起步 → 遇到上面这些情况再下沉 StateGraph
这不是绕路,而是被设计好的演进路径

下沉时状态用显式的 TypedDict 定义,每个节点读状态、改状态,边和条件边决定流向;把 Step 5 的 checkpointer 机制带过去,持久化语义完全一致。此前站内已有 LangGraph 有状态工作流的专篇,这里不展开图 API 细节,只强调一条判断标准:「模型在循环里自主调工具」用 create_agent,「你要精确控制每一步怎么走」用 StateGraph。两者共用一套运行时,互相迁移的成本不高,不必一步到位。

💡 迁移完成后做一轮回归:把旧代码时期的典型输入逐条喂给新智能体,对比输出质量与工具调用轨迹。行为差异多数来自 system_prompt 表达方式的变化(模板拼装 → 直接陈述),微调一两轮通常就能对齐。

常见问题速查

你遇到的现象大概率原因 & 解决
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.x1.x 要求 Python 3.10+。先升解释器再迁代码
← 返回教程中心