LangGraph
定义
LangGraph 在本文语境中的本质,不是“更花哨的 Agent 框架”,也不是单纯把 Prompt 编排做得更复杂,而是把复杂 Agent 从“模型驱动的黑盒循环”改造成“开发者可定义、可检查、可恢复的状态机”。
简化地说:普通 Agent 往往是模型不断决定“下一步做什么”;而 LangGraph 是开发者先把路画出来,模型只在局部需要判断的地方参与决策。
原文给出的核心判断是:简单 Agent 靠一个模型循环调用工具就够,但真实业务不是聊天,真实业务有流程、有状态、有分支、有审批,也有失败恢复。因此复杂 Agent 最终会走向图式编排。
在这个意义上,LangGraph 负责的不是业务系统本身,也不是底层模型组件本身,而是复杂 Agent 的流程编排层。
与普通 Agent 的差异
普通 Agent 的典型模式是:模型判断下一步,模型决定调用哪个工具,工具结果再塞回模型,然后继续循环。
这种模式适合 Demo,也适合比较标准的工具调用;但一旦业务变复杂,就会暴露明显上限:
- 流程不可控:模型可能多查、漏查、乱跳,执行路径不稳定。
- 状态不清楚:上一步结果散落在 messages 中,订单号、用户 ID、风险级别、审批结果、召回文档、工具返回值这类业务字段难以治理。
- 失败难恢复:任务中途崩溃后,普通 Agent 很难从中间状态继续。
- 人工介入困难:审批、驳回、修改、继续执行,并不是一个 Prompt 就能优雅处理的。
所以普通 Agent 的问题不是“完全不能跑”,而是“复杂以后难控制”。这正是 LangGraph 要解决的工程问题。
四个核心抓手:State、Node、Edge、Runtime
原文把 LangGraph 概括为:State + Node + Edge + Runtime。
State:当前任务状态
State 表示任务在当前时刻的业务状态。
它不是随意堆在对话消息里的上下文,而是结构化保存的任务字段。文中明确指出,复杂任务不能只靠聊天记录;像订单号、用户 ID、风险级别、审批结果、召回文档、工具返回值,都应该进入 State。
一句话概括就是:消息是上下文,State 才是业务状态。
Node:每一步执行单元
Node 表示流程中的一个执行步骤。
节点可以是:
- LLM 调用
- RAG 检索
- Tool 或业务接口调用
- 人工审批
- 普通 Python 逻辑
LangGraph 并不关心节点内部到底是模型、数据库、搜索还是人工操作;它只关心一件事:节点读取当前 State,返回 Partial State,也就是它改动的那部分状态。
这也是它和很多“全量上下文重算”式 Agent 的重要区别。
Edge:固定或条件跳转
Edge 定义下一步往哪里走。
它可以是:
- 固定边:A 执行完直接去 B。
- 条件边:A 执行完后,根据当前状态判断去 B、C,或者直接结束。
条件边的意义在于,原本藏在 Prompt 里的业务流程判断,被提升成了真正的程序结构。于是“分支、循环、路由”不再依赖模型临场发挥,而是进入开发者可见、可审计的图结构。
Runtime:运行、流式、中断、持久化与恢复
Runtime 负责把整张图真正运行起来。
原文强调,运行时不仅仅是“执行节点”,还承担了复杂 Agent 工程化所需的能力,包括:
- 流式执行
- 持久化
- 中断
- 恢复
也就是说,LangGraph 的价值不只在静态建图,还在于让这张图可以以工程化方式持续运行。
StateGraph 在干什么
在文中,StateGraph 被明确区分为 builder,而不是运行器。
它的职责是收集和组织图结构,而不直接承担运行。真正可执行的是 compile() 之后得到的 CompiledStateGraph。
StateGraph 初始化
创建 StateGraph 时,会准备几类核心容器:
nodes:存放节点edges:存放固定边branches:存放条件分支channels:存放状态通道
同时还会解析 State schema,提前确定哪些字段可以更新、状态如何合并。
这里的关键点是:LangGraph 在建图阶段就开始处理状态结构,而不是等运行时才临时拼接。
add_node:注册节点
add_node 用来注册节点。
节点本质上是函数或 Runnable。LangGraph 不限定节点实现方式,但要求节点符合同一个基本接口语义:读入 State,输出 Partial State。
这使得一个图里可以混合放入模型调用、检索逻辑、数据库查询、审批逻辑和普通程序代码。
add_edge 与 add_conditional_edges:注册路线
add_edge 用于固定跳转,add_conditional_edges 用于条件跳转。
固定边适合线性流程,条件边适合分支、循环和路由控制。
原文特别强调,这一步的意义是把“业务流程”从 Prompt 里拿出来,变成真正的程序结构。
compile:变成可执行图
compile() 会把 builder 变成可执行图,并进行结构校验。
文中列出的校验点包括:
- 有没有孤立节点
- 入口和出口是否合理
- 分支目标是否存在
只有完成 compile() 之后,图才具备 invoke、stream、ainvoke 等执行能力。换言之,StateGraph 负责声明结构,CompiledStateGraph 才负责执行。
运行机制与状态合并
LangGraph 的执行不是一条简单的死链,而更像消息传递:
- 某个节点被激活。
- 节点读取当前 State。
- 节点执行自己的逻辑。
- 节点写回状态更新。
- 控制权通过边转交给下一个节点。
文中还强调了一个很关键的约束:每个节点不要返回整份 State,而只返回自己改动的部分。
之后由 LangGraph 根据 reducer 合并状态。
这样设计的原因是,复杂 Agent 很容易出现并行节点、多个结果、列表追加、消息合并等场景;如果没有 reducer,多个节点很容易互相覆盖状态。
因此,LangGraph 不只是把流程画成图,也把状态更新变成一种受约束的合并机制。
复杂 Agent 为什么会走向 LangGraph
原文把原因总结得非常直接,主要有五类。
1. 流程需要显式化
企业系统不能接受“模型觉得应该这么做”。
对于生产流程,系统需要知道:当前在哪一步、下一步是谁、失败后怎么办。LangGraph 的图结构把这些都显式表示出来。
2. 状态需要结构化
复杂任务不能只依赖消息历史。业务字段必须有清晰位置、有明确更新方式。
这也是为什么 State 在 LangGraph 中不是附属概念,而是编排核心。
3. 失败需要恢复
真实系统会超时、报错、中断。
LangGraph 可以通过 checkpointer 保存线程状态;任务跑到一半失败,后续可以从 checkpoint 继续,而不必整段重来。
4. 人工需要介入
退款、转账、删除数据、修改合同、下单交易等高风险操作,不能让模型直接放行。
LangGraph 可以通过 interrupt 暂停图执行,等待人工审批,再继续后续步骤。这个能力很难靠单个 Prompt 优雅实现。
5. 排查需要可观测
复杂 Agent 出错时,必须知道究竟是哪里错了:
- 路由错
- 检索错
- 工具参数错
- 模型生成错