W
AI-Wiki
CONCEPT

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() 之后,图才具备 invokestreamainvoke 等执行能力。换言之,StateGraph 负责声明结构,CompiledStateGraph 才负责执行。

运行机制与状态合并

LangGraph 的执行不是一条简单的死链,而更像消息传递:

  1. 某个节点被激活。
  2. 节点读取当前 State。
  3. 节点执行自己的逻辑。
  4. 节点写回状态更新。
  5. 控制权通过边转交给下一个节点。

文中还强调了一个很关键的约束:每个节点不要返回整份 State,而只返回自己改动的部分。

之后由 LangGraph 根据 reducer 合并状态。

这样设计的原因是,复杂 Agent 很容易出现并行节点、多个结果、列表追加、消息合并等场景;如果没有 reducer,多个节点很容易互相覆盖状态。

因此,LangGraph 不只是把流程画成图,也把状态更新变成一种受约束的合并机制。

复杂 Agent 为什么会走向 LangGraph

原文把原因总结得非常直接,主要有五类。

1. 流程需要显式化

企业系统不能接受“模型觉得应该这么做”。

对于生产流程,系统需要知道:当前在哪一步、下一步是谁、失败后怎么办。LangGraph 的图结构把这些都显式表示出来。

2. 状态需要结构化

复杂任务不能只依赖消息历史。业务字段必须有清晰位置、有明确更新方式。

这也是为什么 State 在 LangGraph 中不是附属概念,而是编排核心。

3. 失败需要恢复

真实系统会超时、报错、中断。

LangGraph 可以通过 checkpointer 保存线程状态;任务跑到一半失败,后续可以从 checkpoint 继续,而不必整段重来。

4. 人工需要介入

退款、转账、删除数据、修改合同、下单交易等高风险操作,不能让模型直接放行。

LangGraph 可以通过 interrupt 暂停图执行,等待人工审批,再继续后续步骤。这个能力很难靠单个 Prompt 优雅实现。

5. 排查需要可观测

复杂 Agent 出错时,必须知道究竟是哪里错了:

  • 路由错
  • 检索错
  • 工具参数错
  • 模型生成错