SOURCE
LangChain 系列:为什么复杂 Agent 最后都要走向 LangGraph? - 今日头条 摘要
文档概览
- 文章的主论点非常明确:LangGraph 的价值不在于“更炫”,而在于“更可控”。
- 作者把简单 Agent 与复杂 Agent 明确区分:前者可以依赖模型决定下一步动作,后者一旦进入真实业务,就会碰到流程、状态、分支、审批、失败恢复等工程问题。
- 全文围绕一个判断展开:复杂 Agent 的核心矛盾,不是模型不会调用工具,而是业务系统不能把关键流程交给黑盒循环自由发挥。
- 因此,LangGraph 的本质被概括为:把 Agent 从“黑盒循环”拆成“可控状态机”。
- 文中还给出一个工程分工类比:LangChain 更偏模型组件,LangGraph 更偏复杂 Agent 编排;在企业架构里,业务主服务、AI 服务、流程编排、观测评测应分层处理。
关键事实
核心判断:LangGraph 不是更花哨,而是把复杂 Agent 变成可控状态机
- 文章反复强调,LangGraph 并不是为了把 Agent 写得更复杂,而是为了把已经复杂的 Agent 变得可治理。
- 作者对比了两种控制方式:
- 普通 Agent:模型自己决定怎么走。
- LangGraph:开发者先把路画出来,模型只在“该决策的地方”做局部决策。
- 这意味着控制权发生了转移:从“模型主导全局流程”转向“开发者主导流程结构,模型负责局部判断”。
- 文章把这种差异定义为工程化差异,而不只是编码风格差异。
普通 Agent 在复杂业务中的四类主要瓶颈
- 第一类瓶颈是流程不可控。
- 在普通工具调用循环里,模型可能多查、漏查、乱跳,导致流程既不稳定也不容易审计。
- 第二类瓶颈是状态散落。
- 上一步的结果常常混在 messages 里,业务字段没有单独治理空间;当系统需要明确订单号、用户 ID、审批结果、风险等级等字段时,纯消息堆叠会越来越难维护。
- 第三类瓶颈是失败后难以从中间恢复。
- 任务跑到一半崩溃后,普通 Agent 往往难以从中间状态继续,而不是从头再来。
- 第四类瓶颈是人工介入不优雅。
- 审批、驳回、修改、继续执行这类动作,不是靠再补一句 Prompt 就能稳定处理的;一旦涉及真实业务责任,必须有明确暂停点和恢复点。
- 文章的结论是:普通 Agent Loop 不是不能跑,而是“跑复杂了难控制”。
LangGraph 的四个核心组成:State、Node、Edge、Runtime
- 文章给出一个一句话定义:LangGraph = State + Node + Edge + Runtime。
- State:当前任务状态,即整个执行过程中需要被保存和更新的业务信息。
- Node:每一步要做的事,可以是 LLM、RAG、Tool,也可以是人工审批。
- Edge:控制下一步去哪里,既可以是固定跳转,也可以是条件判断。
- Runtime:负责把整个图运行起来,并支持流式、持久化、中断、恢复等能力。
- 这四个概念共同说明,LangGraph 并不是一个“大 Prompt 包装器”,而是一个把状态、步骤、路由和运行机制显式拆开的图式系统。
StateGraph 的定位:builder,不是运行器
- 文中对 StateGraph 的定位区分得很清楚:它不是运行器,而是 builder。
- StateGraph 的职责是收集并组织图结构相关的定义,包括:
- nodes:节点集合。
- edges:固定边。
- branches:条件分支。
- channels:状态通道。
- state schema:状态结构定义。
- reducer:状态合并规则。
- 真正能运行的是 compile() 之后的 CompiledStateGraph。
- 文章明确指出,只有在 compile() 之后,系统才具备 invoke、stream、ainvoke 等执行能力。
- 因此,StateGraph 与 CompiledStateGraph 不是同义词:前者负责构建,后者负责执行。
StateGraph 构建流程中的关键环节
- 初始化阶段会创建 builder,并准备多个核心容器。
- 文中点名了四类内部容器:nodes、edges、branches、channels。
- 同时,在初始化阶段还会解析 State schema。
- 作者特别强调,哪些字段能更新、更新后怎么合并,都会在这一阶段先准备好。
- add_node 的作用是注册节点。
- 节点本质可以是函数或 Runnable。
- LangGraph 并不强行要求节点内部一定是某种特定组件;它可以封装 LLM、数据库查询、搜索、人工审批,或者普通 Python 逻辑。
- 对节点的真正要求只有一个:读入 State,返回 Partial State。
- add_edge 用于注册固定路线。
- 文章给出的典型含义是:A 执行完就去 B。
- add_conditional_edges 用于注册条件路线。
- 也就是:A 执行完后,根据当前状态决定去 B、C,还是 END。
- 作者把这一步的意义概括为:把原本藏在 Prompt 里的业务流程,拿出来变成真正的程序结构。
- compile 阶段负责把 builder 变成可执行图。
- 在 compile 时会做结构校验,文中给出的检查项包括:
- 是否存在孤立节点。
- 入口和出口是否合理。
- 分支目标是否存在。
- 通过校验后,builder 被转换为 CompiledStateGraph。
运行时的关键机制:节点返回 Partial State,由 reducer 合并
- 文章强调,LangGraph 的运行时不是“一条死链”,而更像消息传递机制。
- 被激活的节点会:
- 读取当前状态。
- 执行自身逻辑。
- 写回状态更新。
- 再通过边把控制权交给下一个节点。
- 一个非常关键的约束是:每个节点不要返回整份 State。
- 节点只返回自己改动的部分,也就是 Partial State。
- 然后由 reducer 负责把这些局部更新合并回完整状态。
- 文章解释说,这个机制之所以关键,是因为复杂 Agent 很容易出现以下场景:
- 并行节点同时更新状态。
- 多个结果需要汇聚。
- 列表字段需要追加而不是覆盖。
- 消息字段需要合并而不是丢失。
- 如果没有 reducer,多个节点的结果就可能相互覆盖,导致状态管理混乱。
复杂 Agent 采用 LangGraph 的五个理由
1. 业务流程需要显式化
- 企业系统不能接受“模型觉得应该这么做”。
- 真正的业务系统需要明确知道:当前在哪一步、下一步是谁、失败后怎么办。
- LangGraph 的作用之一,就是把这些流程画出来,变成显式可检查的结构。
2. 状态需要结构化
- 文中明确区分了消息上下文与业务状态。
- messages 只是上下文,不应承担全部业务治理职责。
- 订单号、用户 ID、风险级别、审批结果、召回文档、工具返回值等,都应进入 State。
- 文章给出的判断是:消息是上下文,State 才是业务状态。
3. 失败需要恢复
- 真实系统一定会遇到超时、报错、中断。
- 文章指出,LangGraph 可以通过 checkpointer 保存线程状态。
- 这样任务在跑到一半失败后,下次可以从 checkpoint 继续,而不是强制从头执行。
4. 人工需要介入
- 在退款、转账、删除数据、修改合同、下单交易等高风险场景里,模型不能直接落地执行。
- 文章给出的机制是 interrupt。
- 图可以在特定节点暂停,等待人工审批,再继续执行。
- 这让人工介入成为流程中的正式环节,而不是临时打断对话的补丁。
5. 排查需要可观测
- 复杂 Agent 出错时,排查目标不是“模型为什么不聪明”,而是精确定位哪一步错了。
- 文中列出了几类典型故障位点:路由错、检索错、工具参数错、模型生成错。
- 图结构的价值在于,每一步都可追踪,从而支持排障与评测。
重要细节
智能客服案例中的典型节点拆分
- 文章用智能客服举例,说明复杂 Agent 不是“用户问,模型答”这么简单。
- 一个可控的客服流程至少包括以下节点:
- 意图识别。
- 知识库检索。
- 业务查询。
- 风险判断。
- 人工审批。
- 答案质检。
- 作者特别强调“一个节点只做一件事”。
- 对应到案例中:
- 意图识别节点只负责分类。
- RAG 节点只负责查资料。
- 工具节点只负责调用业务接口。
- 人工节点只负责审批。
- 质检节点只负责拦截风险答案。
- 这种拆分方式的目的不是增加节点数量,而是让每一步边界清楚、责任清楚、失败点也清楚。
什么情况下应该考虑 LangGraph
- 文章明确反对“为了用 LangGraph 而用 LangGraph”。
- 对简单任务来说,上图反而会增加复杂度。
- 但只要 Agent 开始出现以下任一类特征,就应该考虑 LangGraph:
- 分支。
- 循环。
- 状态恢复。
- 人工审批。
- 多 Agent 协作。
- 这个判断标准很实用:不是看模型是否强,而是看流程是否已经具备典型的工程复杂性。
企业级架构分层建议
- 文章给出了一个偏企业落地的分层方案。
- 推荐做法不是把所有 AI 逻辑都塞进 Java。
- 更稳的方式是:Spring Boot 做业务主服务,Python FastAPI 做 AI 服务,LangGraph 放在 AI 服务内部。