如果说上篇是在讲 LangChain、LangGraph 的区别与选型,那么这一篇就进入真正决定系统上限的部分了,也就是图式编排本身。

很多团队第一次做 Agent,往往不是被模型能力卡住,而是被流程失控卡住。代码里一开始只是几步串联,后来要加分支、加工具、加重试、加人工确认、加上下文状态,再往后还想拆成多个角色协作。这时候如果还是继续在一个 while 循环里硬堆逻辑,系统很快就会变得既难调试,也难维护。

LangGraph 的价值,正是在这里体现出来。它不是 LangChain 的替代品,而是更底层、更明确的图式编排能力,让你把 Agent 系统看成一张图,而不是一坨链式代码。

这一篇就单独把 LangGraph 讲透,重点放在三个关键词:

  1. 工作流
  2. 状态机
  3. 多 Agent

1. 为什么 LangGraph 会出现

官方对 LangGraph 的定位很明确,它是一个偏底层的 agent orchestration 框架,重点不是再包装一层模型调用,而是处理复杂 agent 系统真正关心的几个问题:

  1. 长流程编排
  2. 显式状态管理
  3. 可循环执行
  4. 条件分支
  5. 持久化与可恢复
  6. human-in-the-loop

换句话说,LangChain 更像是“组件层”和“链路层”,而 LangGraph 更像是“控制流层”和“运行时层”。

如果把一个 LLM 应用类比成程序:

  1. Prompt、Model、Retriever、Tool 像函数和模块
  2. LangChain 像模块组合方式
  3. LangGraph 像程序的流程控制与状态运行模型

所以当系统开始从“问一次答一次”走向“多步执行、多轮决策、长期运行”时,LangGraph 的意义就出来了。

2. LangGraph 的核心思想

LangGraph 最值得掌握的,不是某个 API 名字,而是它背后的建模方式。

官方 Graph API 文档里,核心抽象其实非常朴素:

  1. State
  2. Node
  3. Edge

这三个词看起来简单,但真正把它们想透了,整个框架就不难了。

2.1 State:系统当前的共享快照

State 是系统当前状态的一个显式描述。

它可以理解成:

  1. 当前已经收到了什么输入
  2. 已经做过哪些步骤
  3. 中间结果是什么
  4. 下一步路由依据是什么
  5. 哪些信息需要在多个节点之间共享

在很多普通 LangChain 链里,状态是“隐式”的,变量顺着代码传来传去;但在 LangGraph 里,状态被提升为第一等公民。

这非常重要,因为复杂 Agent 系统真正难的往往不是“某一步怎么做”,而是“系统此刻到底处于什么状态”。

2.2 Node:做事的地方

Node 就是图里的执行节点。它本质上只是一个函数:

  1. 接收当前 state
  2. 做一段逻辑
  3. 返回对 state 的更新

Node 可以非常轻,也可以非常重:

  1. 可以只是一次分类
  2. 可以是一次模型调用
  3. 可以是一次工具执行
  4. 也可以是一个完整子图

所以 Node 并不等于“LLM 节点”,它只是一个状态变换单元。

2.3 Edge:决定接下来去哪

Edge 负责路由控制,也就是:

  1. 下一个节点是谁
  2. 是否进入分支
  3. 是否要回环
  4. 是否应该结束

普通 add_edge 表示固定流向,add_conditional_edges 则表示运行时根据状态决定流向。

这一步就是 LangGraph 和“简单链式拼接”拉开差距的关键。

3. 从链到图:为什么图更适合 Agent

很多人会问,链式调用明明也能做很多事情,为什么一定要上图?

原因是链适合“线性流程”,图适合“动态流程”。

3.1 链适合什么

链式结构适合:

  1. 顺序稳定
  2. 步骤固定
  3. 失败路径简单
  4. 状态不复杂

比如:

  1. 先总结,再翻译
  2. 先检索,再回答
  3. 先分类,再路由

3.2 图适合什么

图结构更适合:

  1. 存在分支
  2. 存在循环
  3. 有多条可能路径
  4. 有中间状态沉淀
  5. 可能中断、恢复、审批

这其实就是大多数真正 Agent 系统的样子。

一旦你需要让系统具备“根据执行结果决定下一步”的能力,图的表达力就会远强于简单链。

4. 一个最小 LangGraph 例子

LangGraph 官方 Graph API 的经典写法,大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from typing_extensions import TypedDict
from langgraph.graph import START, END, StateGraph


class State(TypedDict):
topic: str
draft: str


def write_outline(state: State):
return {"draft": f"这是关于 {state['topic']} 的提纲"}


def finalize(state: State):
return {"draft": state["draft"] + "\n\n这是最终版本。"}


builder = StateGraph(State)
builder.add_node("write_outline", write_outline)
builder.add_node("finalize", finalize)

builder.add_edge(START, "write_outline")
builder.add_edge("write_outline", "finalize")
builder.add_edge("finalize", END)

graph = builder.compile()

result = graph.invoke({"topic": "LangGraph"})
print(result)

这个例子虽然简单,但已经能看出 LangGraph 的最核心骨架:

  1. 定义状态
  2. 定义节点
  3. 定义边
  4. 编译图
  5. 执行图

如果只把它看成“又一种链式写法”,会低估它。真正的重点在于,从这里开始,流程控制就被显式建模了。

5. LangGraph 里的状态机思维

很多人提到 LangGraph,只记住了“图”,但其实更值得掌握的是“状态机”思维。

所谓状态机思维,并不是非得写得像教科书里的 FSM,而是要明确:

  1. 系统当前处于哪种状态
  2. 哪个节点会改变状态
  3. 哪种状态会触发哪条边
  4. 哪些状态意味着结束

举个很典型的例子,一个研究类 Agent 可以有这些状态:

  1. input_received
  2. planning
  3. searching
  4. analyzing
  5. reviewing
  6. completed
  7. failed

如果没有状态机视角,代码就容易变成:

  1. 到处 if else
  2. 中间变量散落
  3. 出错后不知道怎么恢复
  4. 人工接入点很难插

而有了状态机视角,你就会把系统想成:

  1. 状态更新发生在哪里
  2. 状态跳转由什么触发
  3. 哪一步允许重试
  4. 哪一步必须人工确认

这就是 LangGraph 真正的工程味道。

6. 条件边:图真正活起来的地方

固定边只适合线性流程,条件边才是图的灵魂。

官方文档里的写法大致是通过 add_conditional_edges,让某个函数根据当前状态返回下一步目标节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from typing import Literal
from typing_extensions import TypedDict
from langgraph.graph import START, END, StateGraph


class State(TypedDict):
question: str
route: str


def classify(state: State):
text = state["question"]
if "代码" in text:
return {"route": "coder"}
return {"route": "researcher"}


def coder(state: State):
return {"question": state["question"]}


def researcher(state: State):
return {"question": state["question"]}


def router(state: State) -> Literal["coder", "researcher"]:
return state["route"]


builder = StateGraph(State)
builder.add_node("classify", classify)
builder.add_node("coder", coder)
builder.add_node("researcher", researcher)

builder.add_edge(START, "classify")
builder.add_conditional_edges("classify", router)
builder.add_edge("coder", END)
builder.add_edge("researcher", END)

graph = builder.compile()

这里最重要的不是“会分支”本身,而是:

  1. 分支逻辑变成了图上的显式结构
  2. 路由依据来自状态,而不是零散变量
  3. 后续调试时能看到为什么走到这条路径

对 Agent 来说,这一点非常重要,因为“为什么它做了这个决定”通常就是最关键的调试问题。

7. 回环:Agent 为什么天然适合图

普通工作流很多是单向往前走,但 Agent 经常需要循环:

  1. 先规划
  2. 再调用工具
  3. 再观察结果
  4. 再决定是否继续

这本质上就是一个 loop。

在传统链式结构里,循环往往会被写成手工 while 循环;在 LangGraph 里,它可以自然建模为:

  1. agent 节点思考
  2. 条件边判断是否继续
  3. tools 节点执行
  4. 再回到 agent

这个模式正是很多 tool-calling agent 的基础骨架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from typing import Literal
from typing_extensions import TypedDict
from langgraph.graph import START, END, StateGraph


class AgentState(TypedDict):
messages: list[str]
need_tool: bool


def call_model(state: AgentState):
return {
"messages": state["messages"] + ["模型决定需要继续调用工具"],
"need_tool": True,
}


def run_tool(state: AgentState):
return {
"messages": state["messages"] + ["工具执行完成"],
"need_tool": False,
}


def should_continue(state: AgentState) -> Literal["tools", "__end__"]:
return "tools" if state["need_tool"] else "__end__"


builder = StateGraph(AgentState)
builder.add_node("agent", call_model)
builder.add_node("tools", run_tool)

builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue)
builder.add_edge("tools", "agent")

graph = builder.compile()

这种“思考 -> 决策 -> 行动 -> 观察 -> 再思考”的闭环,就是为什么图比链更适合 Agent。

8. 工作流和 Agent 的边界,到底怎么分

这是做系统时非常容易混的地方。

8.1 Workflow

工作流的特点是:

  1. 大部分路径可预定义
  2. 开发者知道主要步骤
  3. 模型更多承担局部能力

例如:

  1. 分类
  2. 路由
  3. 检索
  4. 生成
  5. 审核

这种时候,LangGraph 虽然也能用,但系统本质还是 workflow。

8.2 Agent

Agent 的特点是:

  1. 下一步动作不完全固定
  2. 模型要参与行动决策
  3. 工具调用和执行路径会动态变化

8.3 为什么 LangGraph 同时适合两者

因为 LangGraph 并不强行要求你做“完全自主 Agent”,它只是提供图式编排能力。

所以它既能表达:

  1. 非常确定的 workflow
  2. 带循环的 tool agent
  3. 多角色系统

这也是它特别适合作为“中间层”的原因。你可以先用它搭 workflow,后面再逐步长成 agent 系统,而不是换一套架构。

9. 多 Agent 不是多几个 Prompt,而是多几个状态边界

很多人说自己在做多 Agent,实际只是写了几个不同 system prompt,然后让它们轮流说话。

真正工程意义上的多 Agent,更重要的是边界和协作机制。

我更倾向于把多 Agent 理解成:

  1. 不同节点拥有不同职责
  2. 不同节点消费不同上下文
  3. 不同节点产出不同类型结果
  4. 节点之间通过状态与边协作

LangGraph 在这里的优势很明显,因为它允许你把每个 Agent 当成一个节点,或者进一步当成一个子图。

一个经典拆法是:

  1. Planner
  2. Researcher
  3. Writer
  4. Reviewer

它们并不一定都需要“自治”,但都应该有自己的职责和输入输出边界。

10. 子图:把复杂系统拆成可维护的块

官方文档里也明确提到可以把 subgraph 当成 node 加进父图里。这一点在多 Agent 系统中特别有用。

为什么?

因为大系统最怕的是所有逻辑摊平成一个巨图。那样虽然理论上也能跑,但维护体验会非常差。

更合理的方式是分层:

  1. 顶层图负责任务编排
  2. 子图负责某一类复杂任务
  3. 子图内部再拆局部节点

例如一个“研究报告系统”可以这样分:

  1. 顶层图
    负责接收需求、选择子流程、汇总结果
  2. 检索子图
    负责搜索、去重、摘要
  3. 写作子图
    负责组织提纲、写初稿、润色
  4. 审核子图
    负责事实检查、格式检查、风险判断

这种设计方式的收益非常现实:

  1. 可读性更好
  2. 调试范围更小
  3. 不同团队可以并行维护
  4. 将来更容易升级成真正多 Agent 系统

11. 一个多 Agent 的 LangGraph 建模思路

下面给一个概念性例子,不追求直接可上线,但很适合建立建模直觉。

11.1 状态定义

1
2
3
4
5
6
7
8
9
10
from typing_extensions import TypedDict


class ReportState(TypedDict):
topic: str
plan: str
research_notes: str
draft: str
review: str
status: str

11.2 各 Agent 节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def planner(state: ReportState):
return {
"plan": f"围绕 {state['topic']} 先调研,再写作,再审核",
"status": "planned"
}


def researcher(state: ReportState):
return {
"research_notes": "这里是检索后的调研结果",
"status": "researched"
}


def writer(state: ReportState):
return {
"draft": "这里是基于调研信息生成的初稿",
"status": "drafted"
}


def reviewer(state: ReportState):
return {
"review": "结构清晰,但还需要补充案例",
"status": "reviewed"
}

11.3 图结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langgraph.graph import START, END, StateGraph


builder = StateGraph(ReportState)
builder.add_node("planner", planner)
builder.add_node("researcher", researcher)
builder.add_node("writer", writer)
builder.add_node("reviewer", reviewer)

builder.add_edge(START, "planner")
builder.add_edge("planner", "researcher")
builder.add_edge("researcher", "writer")
builder.add_edge("writer", "reviewer")
builder.add_edge("reviewer", END)

graph = builder.compile()

这个例子看起来是线性的,但它已经具有多 Agent 风格的基础:

  1. 职责拆分
  2. 状态共享
  3. 顺序显式

如果后面你要加:

  1. 审核不过退回写作
  2. 某些主题先检索再规划
  3. 高风险内容进入人工审批

LangGraph 都可以继续承接,而不需要推翻原有结构。

12. Human-in-the-loop 为什么和 LangGraph 很搭

一旦系统开始执行真实任务,人工介入通常是必需的,而不是可选项。

典型场景包括:

  1. 发邮件前确认
  2. 调用高风险接口前审批
  3. 审核生成内容
  4. 在关键分支上人工修正状态

LangGraph 适合做这件事,是因为它本身就是显式状态和显式边的框架。

也就是说,你完全可以把“人工审批”当成图上的一个节点或状态关口,而不是临时塞进某个回调函数。

从工程角度看,这种设计非常值钱,因为:

  1. 它可观察
  2. 它可恢复
  3. 它可审计

对于真正上线的 agent 系统,这比“模型多聪明一点”更重要。

13. 我对 LangGraph 的实践建议

如果你准备把 LangGraph 用进真实项目,我会建议按下面的顺序来:

13.1 先把 State 设计清楚

别急着写节点。先想清楚:

  1. 哪些字段属于共享状态
  2. 哪些字段只是临时变量
  3. 哪些字段决定路由
  4. 哪些字段决定结束条件

13.2 再写节点职责

每个节点最好回答一个问题:

这个节点的唯一责任是什么?

如果一个节点同时负责:

  1. 检索
  2. 总结
  3. 判断分支
  4. 写数据库

那它往往已经过重了。

13.3 边的语义要简单

固定边就做固定跳转,条件边只负责路由,不要把一大堆业务逻辑全塞进路由函数里。

13.4 先做单 Agent 图,再做多 Agent 图

很多多 Agent 项目失败,不是因为“多 Agent 理念不对”,而是因为连单图状态流都没梳理清楚。

13.5 把可观测性当必需品

至少要能回答:

  1. 执行到了哪个节点
  2. 当前 state 长什么样
  3. 为什么走了这条边
  4. 哪一步失败了

14. LangGraph 和第三篇 Agent 实战是什么关系

到这里其实就能看出来,LangGraph 很像 Agent 系统的“骨架层”。

如果没有 LangGraph 这种图式思维,很多 Agent 项目会出现这些问题:

  1. 看起来能跑,但流程不可控
  2. 看起来智能,但状态不可见
  3. 看起来灵活,但一出错就没法恢复

所以第三篇再讲 Agent 实战时,我们就不会只盯着:

  1. 模型怎么调
  2. 工具怎么接
  3. Prompt 怎么写

而会更自然地回到这些更关键的问题:

  1. 任务如何拆分
  2. 状态如何流转
  3. 工具调用如何被约束
  4. 单 Agent、L2/L3/L4 和 OpenClaw 类系统本质上差在哪

15. 小结

这一篇最核心的内容,其实可以压缩成三句话:

  1. LangGraph 不是“另一个 Agent 包”,而是 agent orchestration 的图式框架
  2. 它最值得学习的是状态机思维,而不是单个 API
  3. 多 Agent 的关键不只是多角色,更是状态边界、子图拆分和流程治理

如果用一句更通俗的话概括:

LangChain 让你会搭积木,LangGraph 让你会搭一套真正能长期运行的系统。

下一篇我们再回到 Agent 实战本身,把 L2 工作流、L3 工具型 Agent、L4 多 Agent 系统,以及 OpenClaw 这类更激进的 computer-use agent 放到同一张图谱里来看,你会更容易理解它们之间到底是升级关系、互补关系,还是根本不是同一类东西。