跳到正文

定位与整体架构 ​

一句话:LangChain 是 Agent 的装配层,LangGraph 是它的状态机运行时;前者解决“怎么把模型和工具拼起来”,后者解决“拼起来之后怎么暂停、恢复、观测”。

适用版本:LangChain v1.x、LangGraph 1.x。v1 与 0.x 的包结构和推荐写法差异很大,旧代码迁移前先看官方迁移指南。

为什么需要 ​

直接调模型 SDK 时,每个项目都要重复写这些东西:

  • 不同厂商的请求格式、消息结构、工具调用协议不一样,换模型要改一片代码。
  • “模型返回工具调用 → 执行工具 → 把结果塞回消息 → 再调模型”这个循环要自己写,还要处理并发、超时、重试、最大轮数。
  • 多轮对话要自己存历史;进程重启后状态全丢。
  • 需要人工审批时,要把执行到一半的流程停住,等几个小时再恢复。
  • 线上出问题,要能看见每一次模型调用、工具入参、耗时和 token。

LangChain 负责前两条,LangGraph 负责后三条。它们不是二选一:create_agent 编译出来的就是一个 LangGraph 图。

核心机制 ​

包的分层 ​

换 provider、升级版本时该动哪一层,先看这张图的依赖方向。

  • langchain-core:真正稳定的抽象层。消息类型、工具定义、模型接口都在这里。
  • langchain:v1 的主角,提供 create_agent 和 middleware。旧式的 Chain、Retriever 组合被移到 langchain-classic。
  • 厂商适配包:按需安装,例如 langchain-openai、langchain-anthropic。不装就没有对应 provider。
  • langgraph:独立可用的编排引擎;create_agent 只是它上面的一层预置图。

看这张图抓接缝:实线是装配与编译依赖,虚线是可替换点——换 provider 只动适配包,要自定义拓扑才动 langgraph。

v1 的关键变化 ​

  1. 重心从 Chain 转向 Agent:主入口是 create_agent,不再以 LCEL 拼链为默认写法。LCEL(prompt | model | parser)仍然可用,但主要出现在旧代码和简单管道里。
  2. Middleware 成为扩展点:摘要、重试、降级、限流、PII、人工审批都做成 middleware,而不是让你继承 Agent 类。
  3. 统一内容块(content blocks):不同厂商的 reasoning、引用、工具调用,统一成 message.content_blocks 访问。
  4. 包拆分:LangChain 只保留装配层,重的东西下沉到 core 和厂商包;旧 API 进 langchain-classic。

一次 invoke 到底发生了什么 ​

一次 invoke 什么时候结束、状态在哪一步落盘,是这张图要回答的。

循环只在模型返回 tool_calls 时继续,所以真正的退出条件在模型输出,而不在调用次数;这也是必须额外设轮数上限的原因。checkpoint 挂在每一步之后而不是整次调用结束,因此进程在任意节点崩掉都能从最近快照续跑,代价是每一步都要序列化并写一次状态。工具执行和模型调用是两类不同的故障点,重试与超时也要分别设置;带 thread_id 就能从任意一步恢复。

什么时候不该用 ​

场景更合适的选择
单轮问答、固定 prompt直接调厂商 SDK
纯确定性业务流程,没有模型决策普通代码或工作流引擎
只需要 RAG 检索,不需要多轮工具向量库 SDK + 一次模型调用
强依赖某厂商独有能力(如特定缓存、批处理)厂商 SDK,避免抽象层丢参数
团队无法接受快速迭代的依赖固定版本,或自己封装薄薄一层

判断标准:如果去掉“多轮工具调用、状态恢复、人工介入”中的任意一项后,剩下的需求用 50 行代码能写完,就不要引入框架。

最小上手 ​

bash
pip install -U langchain langgraph "langchain[openai]"
python
from langchain.agents import create_agent

def get_weather(city: str) -> str:
    """查询指定城市的当前天气。"""
    return f"{city}:晴,25℃"

agent = create_agent(
    model="openai:gpt-5.5",          # 换成自己的模型
    tools=[get_weather],
    system_prompt="你是一个简洁的助手,需要实时信息时调用工具。",
)

result = agent.invoke({"messages": [{"role": "user", "content": "北京天气怎么样?"}]})
print(result["messages"][-1].content_blocks)

create_agent 返回的对象支持 invoke、stream、stream_events,也可以作为一个节点塞进更大的 StateGraph。

实战场景 ​

场景一:企业微信里的客服助手(标准循环,不碰 StateGraph) ​

痛点:自研 SDK 胶水写客服助手,换一家模型改了 40 处调用;对话一长就超窗口;上线第一周就烧掉一个月预算——一条工单查不到答案,模型反复调同一个检索工具 60 次,没有任何机制能拦。这三件事分别对应框架的三个存在理由:统一模型接口、上下文治理、循环上限。这类需求 create_agent 一层就够,关键装配是四件:

python
agent = create_agent(
    model=init_chat_model("openai:gpt-5.5", temperature=0, timeout=30, max_retries=2),
    tools=[query_order, search_kb, escalate_to_human],
    system_prompt=SYSTEM,
    middleware=[                          # 上线必带的三件,见 03 篇
        SummarizationMiddleware(model="openai:gpt-5-mini", trigger=("tokens", 6000), keep=("messages", 20)),
        ModelCallLimitMiddleware(run_limit=8, exit_behavior="end"),
        PIIMiddleware(strategy="mask"),
    ],
    checkpointer=AsyncPostgresSaver.from_conn_string(DB_URI),  # 多副本共享
)

实战判断:什么时候发现该下到 LangGraph?出现第一种信号就停手——"要先分类再走不同处理链""这个节点之后必须人工审批""两步之间要并行"。这三条任意一条出现,create_agent 的预置拓扑已经装不下,继续堆 middleware 只会做出没人敢改的黑盒。

场景二:一次线上事故的归因路径(为什么分层重要) ​

痛点:没有分层抽象时,所有故障最后都被归因成一句话——"模型不行",团队只能 endless 调 prompt。分层的第一价值不是代码组织,是给故障发工单的正确收件人。典型案例:"客服 Agent 把 A 客户的订单信息回答给了 B 客户"。按包分层往回走:

  1. trace 里看消息序列(langchain-core 的消息结构)→ 发现上下文里混入了别人的 ToolMessage;
  2. 查 thread_id 生成逻辑(业务代码)→ 前端把 session id 复用串了;
  3. 查工具(业务代码)→ query_order 只信模型传来的 order_id,没有校验"当前登录用户是否有权看这单"。

结论落在两条实践上:框架状态与业务状态分离——thread_id 由服务端签发并在每个请求校验归属,永远不信前端;租户过滤写死在工具内——从 runtime.context 取身份,不拼进 prompt 让模型决定查哪个租户。抽象层没有替你把这两件事做错的机会,但也一点没替你做对。

生产动作 ​

  • 锁版本:langchain、langchain-core、langgraph、厂商包四者版本相互约束,用 lock 文件固定,不要用浮动 latest。
  • 升级先读迁移指南:v1 把旧 Chain 移到了 langchain-classic;create_react_agent 已由 create_agent 取代。
  • 业务逻辑放在工具和节点里:不要继承框架类、不要往 middleware 里塞业务规则;框架只负责编排。
  • 默认开追踪:LANGSMITH_TRACING=true + API Key,或接入自己的 OpenTelemetry;否则线上只能看到“慢”,看不到慢在哪一步。
  • 给 Agent 设上限:最大模型轮数、最大工具调用次数、单次超时,缺一个就可能出现无限循环烧钱。
  • 区分“框架状态”和“业务状态”:checkpoint 里存的是对话与图状态,订单、工单等业务真相仍在业务库,用 ID 关联。

边界 ​

  • 抽象会漏:厂商特有的参数、缓存策略、工具调用细节,统一接口不一定全覆盖;必要时在工具或 middleware 里直接调 SDK。
  • 版本迭代快:一年内的 API 变化可能很大,小团队要预留升级成本。
  • 不是低代码平台:复杂业务仍然要写代码,框架只减少胶水。
  • LangGraph 不是通用工作流引擎:它擅长“模型决策 + 确定性步骤混合”的长任务,不适合纯定时任务或大规模数据管道。
  • 托管能力有绑定:LangSmith 的部署、评测、追踪体验最好,但迁出时要自己补可观测性和持久化。

讲清楚 ​

LangChain 解决的是装配问题:把不同厂商的模型、工具、提示词统一成一套接口,再提供一个标准的 Agent 循环。LangGraph 解决的是运行问题:把这个循环变成有状态的图,每一步都能落 checkpoint,所以可以暂停等人审批、进程挂了接着跑、回放历史。

两者是同一套东西的两层,create_agent 返回的就是 LangGraph 图。选型时先看需求复杂度:单轮调用直接调 SDK;标准工具循环用 LangChain;有分支、并行、人工介入、长任务再上 LangGraph。

这套框架的代价是抽象泄漏和版本变化快。控制方法是锁版本、把业务逻辑放在工具和节点里、默认开追踪,并且始终给 Agent 设轮数和成本上限。

适用:LangChain v1.x / LangGraph 1.x | 初稿 2026-10

把 AI 工程讲到既懂也会用