[控场AI]
· 16 分钟阅读· 8,252 字

LangChain 还是 LangGraph?用 create_agent 返回值判断

LangChain 还是 LangGraph?用 create_agent …

LangChain 1.4.3 的 create_agent 底层是 LangGraph 图,选型取决于谁决定下一步。

文章通过五个零成本脚本,验证 LangChain 1.4.3 的 `create_agent` 实际返回 `CompiledStateGraph`,节点仅 `model` 与 `tools`,说明每个 LangChain agent 都运行在 LangGraph 之上。由此得出选型法则:模型决定下一步就用 `create_agent`,代码决定下一步就用 LangGraph `StateGraph`,两者兼有就把 agent 作为节点嵌入图。文章演示了工具循环、用 `HumanInTheLoopMiddleware` 与 checkpointer 实现人工审批和中断恢复、用条件边表达重试上限,以及把子 agent 塞进父图共享 `messages`。最后给出速查表、常见报错(AgentExecutor 无法导入、缺 checkpointer 恢复失败、resume 需字典格式)与常见问答,并提醒结论基于脚本化模型,仅作启发式判据。

LangChain 还是 LangGraph?用 create_agent 返回值判断

在 LangChain 1.4.3 里,create_agent 返回的不是链条,而是一个 LangGraph 图。打印它的类型会得到 CompiledStateGraph,节点列表只有 model 和 tools。这个事实直接给出了两个框架的分工答案:谁决定下一步,谁就决定你该用哪个框架。

如果模型决定下一步,用 create_agent。如果你的代码决定下一步,写一个 LangGraph StateGraph。如果两者都要,把 agent 塞进图里当一个节点。

本文用五个零成本的脚本演示每种情况,全部使用一个复读固定回复的假模型,无需 API key,只验证路由和审批这些连线逻辑。判断法则可以浓缩成一句话:如果模型运行之前我就能把步骤顺序和分支写下来,我就写图;如果步数和顺序取决于模型发现了什么,我就用 create_agent。

环境准备与三个版本细节

需要 Python 3.10 以上,LangChain 和 LangGraph 在 PyPI 上都这么声明。本文所有测试在 Python 3.13 上完成,锁定的版本是 langchain 1.4.3、langgraph 1.2.13 和 langchain-core 1.6.6。

安装命令是 pip install langchain==1.4.3 langgraph==1.2.13。版本锁定很重要,因为输出和报错信息都来自这几个版本,更新的版本可能不同。单独安装 langchain 时会自动把 langgraph 作为依赖拉进来,pip show langchain 的 Requires 一行可以确认这一点。

一个关键点是共享的 helpers.py 文件,它定义了一个按顺序循环复读回复的脚本化模型,以及 lookup_order 和 refund 两个工具。后续每个步骤存成单独文件(如 step1.py)放在同一目录运行。

Step 1:先看清楚 create_agent 到底返回什么

写老版本的教程说 LangChain 是链条加 AgentExecutor。在 1.4.3 里 AgentExecutor 已经无法导入,agent API 变成了 create_agent。LangChain 官方文档称它是「最小、高度可配置的 harness」,而 LangGraph 文档把自己描述为面向长时间运行、有状态 agent 的低层编排框架和运行时。

我实际验证了这个说法。构建一个最小的 agent 并打印它的类型和节点:

agent = create_agent(model=scripted(), tools=[lookup_order])
print(type(agent))
print(list(agent.get_graph().nodes))

输出是 <class 'langgraph.graph.state.CompiledStateGraph'>,节点为 ['__start__', 'model', 'tools', '__end__']。model 节点调用大模型,tools 节点执行模型请求的工具,循环重复直到模型不再请求工具。

create_agent 在 LangGraph 运行时内运行的循环图

这意味着一个 LangChain agent 自动获得了 LangGraph 的 checkpointing 和 interrupt 能力,Step 3 会实测这一点。Middleware(在模型和工具调用前后固定点运行的函数)会往图里加节点:加上 Step 3 的审批中间件后,图里会多出第五个节点 HumanInTheLoopMiddleware.after_model。

两个库的对比可以总结成表格:LangChain 包名 langchain,你写的是模型、工具、提示词和中间件,它依赖 langgraph;LangGraph 包名 langgraph,你写的是状态、节点和边,它只需要 langchain-core。

一个需要警惕的坑: 老教程会从 langgraph.prebuilt 导入 create_react_agent,或从 langchain.agents 导入 AgentExecutor。在测试版本里,前者已被标记为弃用并推荐改用 create_agent,后者完全无法导入。用到这两个中任何一个的教程都早于当前设计。管道式链条(prompt | model 的 LCEL 语法)仍然可用,它适合没有循环的固定调用序列。

CompiledStateGraph 与 checkpointing、interrupt 的关系:CompiledStateGraph 是 LangGraph 对图定义编译后得到的可执行对象。编译阶段会校验节点与边的拓扑、绑定运行时配置,并挂载可选的持久化与中断能力。checkpointing 指每执行完一个「super-step」(一批可并行节点)就把当前状态快照写入 checkpointer,从而支持断点恢复、时间旅行调试和跨调用续跑;interrupt 则是在指定节点前后暂停执行、把控制权交还给调用方,等外部输入后再继续。这两项能力的实现依赖 LangGraph 的状态机和 checkpointer 抽象,而不是 LangChain agent 自身实现的,所以使用 create_agent 时只要传入 checkpointer 就能直接获得,无需手写图。

Step 2:用 create_agent 写一个工具循环

如果你能把任务描述成「这是目标,这是工具集,一直做到完成」,就用 create_agent。查订单的客服、搜索向量库的文档机器人、建工单的助手,本质上都是同一个循环换了不同工具。

agent = create_agent(
    model=scripted(tool_call("lookup_order", order_id="A1"), say("Order A1 has shipped.")),
    tools=[lookup_order],
    system_prompt="You answer order questions. Use the tool, never guess.",
)

运行后线程里有四条消息:问题、工具调用、工具结果和最终答案。换成真实模型只需把 model=scripted(...) 替换成模型字符串(如 "anthropic:claude-haiku-4-5"),装上对应集成包并设置环境变量。

Deep Agents 是第三种选择,但本文没有实测,只说 LangChain 的官方建议:构建或重构 agent 时可以先用 create_deep_agent,需要更少内置上下文管理和更细的循环控制时选 create_agent。

Step 3:给 agent 加审批和记忆

LangGraph 文档把 human in the loop 和记忆列为核心优势,而一个人工审批不需要写任何图代码。create_agent 接受 checkpointer、store、interrupt_before、interrupt_after 和 middleware 列表。

关键代码是这段:

agent = create_agent(
    model=scripted(tool_call("refund", order_id="A1"), say("Refund issued.")),
    tools=[refund],
    middleware=[HumanInTheLoopMiddleware(interrupt_on={"refund": True})],
    checkpointer=InMemorySaver(),
)

用 thread_id 绑定一次会话,第一次 invoke 会让 agent 暂停。__interrupt__ 是暂停时出现在结果里的键,它的 payload 有 action_requests(要展示的工具名和参数)和 review_configs(每个工具允许的决策)。用 Command(resume={"decisions": [{"type": "approve"}]}) 把人做的决定发回去。

这里模型仍然决定每一步,中间件只决定它选的工具调用能否运行。发 reject 时工具不会运行,模型会收到一条带拒绝原因的工具消息。

上线前要把 InMemorySaver 换成数据库后端,否则重启就丢。checkpointer 只覆盖单个线程,跨会话应该存活的事实要放进 store。

一个细节提醒: 当前文档在 invoke 调用里加了 version="v2",返回的是带 .value 和 .interrupts 的 GraphOutput 对象。两个版本都测过,本文示例用默认行为,返回带 __interrupt__ 键的字典。

checkpointer 与 store 的职责区分:checkpointer 负责保存「单个线程」的执行状态,键是 thread_id,用于同一会话的中断恢复和多轮连续对话;它的生命周期通常与一次会话绑定,重启服务后需要持久化后端(如 SQLite、Postgres)才能保留。store 则是跨线程的长期键值存储,用来保存应该在多次会话之间共享的事实,例如用户偏好、历史工单摘要、长期记忆条目。二者常配合使用:checkpointer 让当前对话可中断可续跑,store 为任意线程提供共享上下文。错误地把跨会话数据放进 checkpointer,会导致换一个 thread_id 后数据消失;反过来,把需要中断恢复的临时状态放进 store,会丢失暂停点信息。

Step 4:当你的代码决定下一步,转到 StateGraph

有些任务的分支和重试可以提前写下来。在 LangGraph 里,状态是共享字典,节点是更新它的函数,边说明下一个跑哪个节点。条件边通过调用你的函数来选下一个节点,还能指回之前的节点,形成循环。

这里用一个退款流水线演示:模型抽取金额,普通规则决定结果,抽取失败最多重试三次再转人工。这个重试上限是业务规则,所以它写在代码里而不是提示词里。

图结构是:START 连到 extract,extract 通过 add_conditional_edges 分三条路——retry 指回自己、approve 和 review 各自连到 END。

运行结果里,第一个请求(30 美元)绕了一次循环,第二次回复读出 30 后被规则批准,共两次模型调用;第二个请求(120 美元)第一次就超出阈值,直接转人工,只有一次模型调用。由于脚本化模型按调用顺序回复、不看输入文本,这个运行只展示控制流,不说明真实抽取质量。

状态、节点与 reducer 的协作方式:LangGraph 的状态是一个共享的 TypedDict 或 Pydantic 模型,节点函数接收当前状态并返回「状态更新字典」,运行时会把这些更新合并回状态。默认合并方式是覆盖,但可以为某个键声明 reducer 来改变合并行为,例如对消息列表使用 add_messages 按 id 去重追加,对计数器使用求和。条件边(add_conditional_edges)接收一个纯函数,根据当前状态返回下一个节点名或 END,因此路由逻辑用普通 Python 表达、可测试、可画图。与提示词驱动不同,这类路由不消耗模型调用,也不受模型输出波动影响,适合表达重试上限、阈值判断、人工兜底等业务规则。

Step 5:两者都要时,把 agent 放进图里

一个系统可以同时用两者。因为 create_agent 返回已编译的图,你可以把它作为节点加进 StateGraph。它能工作是因为 agent 和图共享 messages 键,MessagesState 按 id 合并消息,agent 返回的消息不会在父图里重复。

graph.add_node("triage", triage)
graph.add_node("agent", sub_agent)   # 一个 LangChain agent 作为一个节点
graph.add_node("template", template)

紧急消息走 agent 分支去查订单,线程里有四条消息;普通消息走模板分支,这是纯 Python,不消耗模型调用,只留两条消息。

Step 5 支持流程图的 LangGraph 绘制

要自己画出已编译的图,调用 support.get_graph().draw_mermaid_png(),它会把图文本发给 mermaid.ink 服务,需要联网。

MessagesState 与 add_messages reducer:MessagesState 是 LangGraph 为对话场景预定义的状态结构,核心是 messages 键,其 reducer 为 add_messages。该 reducer 按消息 id 合并:若新消息 id 已存在则替换,否则追加,从而避免嵌套图与父图共享 messages 时消息被重复。子 agent(由 create_agent 编译出的图)与父 StateGraph 都读写同一个 messages 键,子图内部的中间消息也会回流到父状态,所以把 agent 作为节点嵌入时无需额外适配代码。若使用自定义状态,只要同样为消息字段声明 add_messages,也能获得这种按 id 合并的语义。

LangChain 与 LangGraph 选择速查

根据模型还是代码决定步骤来选择框架的决策树

你的需求选择
模型调用工具直到任务完成create_agent
同上,但需要人工审批风险工具create_agent 加 HumanInTheLoopMiddleware 和 checkpointer
需要摘要和子 agent 的长期开放任务create_deep_agent
固定步骤,某些步骤有 LLM 调用LangGraph StateGraph
agent 前后有你自己的路由StateGraph,把 create_agent 当节点
以上所有方案的 trace 和评估LangSmith

中间件让你的代码在模型和工具的固定钩子上介入,但模型仍驱动循环;StateGraph 让你的代码拥有路由权。LangChain 官方把这条线画得很清楚:当内置钩子不够用时,LangGraph 是构建完全自定义图的逃生舱。

在实践中什么时候该离开 create_agent 加中间件?当你需要一个无论模型说什么都必然执行的步骤、一个自带上限的重试循环、或几个 agent 之间的固定路由时。如果整个任务就是两三次固定顺序、没有循环的模型调用,我两个都不用,直接写普通函数或管道链条。

需要说明的是,这些测试都用脚本化模型验证连线,规则只应作为启发式判断,而不是硬性结论。

常见报错排查

ImportError: cannot import name 'AgentExecutor':1.4.3 不再从 langchain.agents 导出它。改用 create_agent,或者 pip install langchain-classic 后从 langchain_classic.agents 导入。create_react_agent 也被标记为弃用。

RuntimeError: Cannot use Command(resume=...) without checkpointer:agent 暂停了但没有保存点可恢复。传入 checkpointer=InMemorySaver() 并用相同 thread_id 再次 invoke。陷阱在于第一次调用即使没有 checkpointer 也会正常暂停,错误只在恢复时才暴露。

TypeError: 'bool' object is not subscriptable:你传了 Command(resume=True)。中间件期望字典格式 {"decisions": [{"type": "approve"}]},每个待处理动作一个决策,按顺序对应。

agent 暂停后没有后续:第一次 invoke 会提前返回,只有用 Command 再次调用才会继续。每次调用后检查 "__interrupt__" in result。

常见问题

应该先学 LangChain 还是 LangGraph? 先学 create_agent。LangGraph 文档自己推荐刚上手 agent 或想要更高层抽象的人用 LangChain agent,而且由于 create_agent 跑在 LangGraph 上,你会顺带掌握状态、检查和中断。当你需要代码选择下一步时再学 StateGraph。

LangGraph 还有意义吗? 有,它是每个 LangChain agent 下面的运行时。LangChain 1.4.3 依赖它,所以每个 create_agent agent 都是 LangGraph 图。它的发布节奏也很密,根据 PyPI 历史,7 月到 10 月间有六个版本。

LangGraph 属于 LangChain 吗? 实践中是的。两者都在 langchain-ai 的 GitHub 组织下,共用一套由 LangChain 运营的文档站点,但在 PyPI 上是独立包。langchain 依赖 langgraph,反过来则不需要。

用 LangGraph 必须用 LangChain 吗? 不必。LangGraph 文档明确说使用 LangGraph 不需要 LangChain,尽管它的示例用 LangChain 组件做模型和工具。节点可以是普通 Python 函数,就像 Step 4 的流水线那样,虽然 LangGraph 底层依赖 langchain-core。

RAG 放在哪里? RAG 是用任一库都能搭的模式:一个搜索文档并把结果交给模型的工具或节点。文档问答机器人是 create_agent 加搜索工具的好场景,而带固定检索和打分步骤的流水线适合用图。

#LangChain vs LangGraph#create_agent#LangGraph StateGraph#Python agent 框架#HumanInTheLoopMiddleware#AI agent 开发#LangGraph 教程
分享:

相关推荐