把问题改写成可验证系统:LangGraph 不是『又一个 Agent 封装』,而是把控制流从代码里的 if/while 提升为一等公民的数据结构。控制流变成图,就能被打印、被检查、被单步执行、被存档回放——这正是『黑盒 Agent』最缺的东西。

它解决什么问题:从单次调用到有状态多步

一个 LLM 应用的复杂度阶梯通常是:单次 prompt → 固定多步链(LCEL)→ 带工具的 Agent 循环 → 多智能体协作。前两级 LangChain 的 LCEL(prompt | llm | parser)就够了,它表达的是一条单向无环管道(DAG):数据从左流到右,不回头。

但 Agent 的本质是循环:调 LLM → 决定调哪个工具 → 执行工具 → 把结果喂回 LLM → 再决定…… 直到 LLM 说『不用工具了,这是答案』。这是一个带条件退出的 while 循环。LCEL 没法画环,于是早期 LangChain 用 AgentExecutor 把这个循环硬编码进框架内部——能跑,但它是个黑盒:你看不到中间状态、没法在某一步暂停、出错时也难以从断点续跑。LangGraph 就是来拆这个黑盒的。

维度LangChain LCELAgentExecutorLangGraph
控制流形态单向无环 DAG内置黑盒 while 循环显式有向图,可带环、可分支
能否循环不能能(但不可见)能,且控制流可打印可调试
状态管理无(流过即弃)隐式 scratchpad显式 State + reducer 累积
人工干预/断点不支持几乎不支持原生 interrupt + Checkpointer 恢复
持久化/会话需自己实现需自己实现thread_id + Checkpointer 开箱即用
多智能体拼链很别扭不擅长supervisor / swarm / subgraph 一等支持
口诀无环用 LCEL,有环上 LangGraph;要持久化、要人工干预,几乎只能 LangGraph

架构全景:四大支柱组成可循环计算图

  1. State(状态):整张图共享的一份数据(通常是 TypedDict)。每个节点读它、返回对它的更新。更新如何合并由 reducer 决定——比如 add_messages 让消息列表追加而非覆盖。这是图的『记忆』。
  2. Node(节点):一个普通 Python 函数(或 Runnable),签名 (state) -> dict。它拿到当前 State,做一件事(调 LLM、跑工具、写库),返回一个『要更新哪些字段』的字典。只做一件事,是图里的计算步。
  3. Edge(边):控制流。普通边 a -> b 表示『a 跑完跑 b』;条件边(conditional edge)则根据 State 动态决定下一步去哪个节点——这就是 Agent『还要不要再调工具』的判断落点,也是图能成环的关键。
  4. Checkpointer(检查点):在每个超步(superstep)后把 State 快照存下来,按 thread_id 归档。它带来三件事:会话持久化(重启不丢)、断点恢复(interrupt 后接着跑)、时间旅行(回到任一历史状态重放)。

最小心智模型:五步构图(可运行)

下面这段是 LangGraph 最小但完整可运行的骨架,不依赖任何 LLM——它演示固定的五步心智模型:定义 State → 加 Node → 连 Edge → compile → invoke。先把这套流程刻进肌肉记忆,后面所有复杂图都是它的展开。

# LangGraph 主包;langgraph-checkpoint-sqlite 提供 SQLite 持久化
pip install -U langgraph langgraph-checkpoint-sqlite
from typing import TypedDict, Annotated
import operator
from langgraph.graph import StateGraph, START, END


# 1) 定义 State:整张图共享的数据结构
#    Annotated[type, reducer] 指定该字段的合并方式。
#    这里用 operator.add 让 steps 列表「追加」而非「覆盖」。
class State(TypedDict):
    value: int                              # 普通字段:默认后写覆盖前值
    steps: Annotated[list[str], operator.add]  # 带 reducer:每个节点的更新会被拼接


# 2) 定义 Node:函数签名 (state) -> dict,返回「要更新哪些字段」
def add_one(state: State) -> dict:
    return {"value": state["value"] + 1, "steps": ["add_one"]}


def double(state: State) -> dict:
    return {"value": state["value"] * 2, "steps": ["double"]}


# 3) 建图并加节点、连边
builder = StateGraph(State)
builder.add_node("add_one", add_one)
builder.add_node("double", double)

builder.add_edge(START, "add_one")   # 入口 -> add_one
builder.add_edge("add_one", "double")  # add_one -> double
builder.add_edge("double", END)        # double -> 终点

# 4) compile:把蓝图编译成可执行图(此处可挂 checkpointer,见后续章节)
graph = builder.compile()

# 5) invoke:传入初始 State,跑完整张图,拿到最终 State
result = graph.invoke({"value": 1, "steps": []})
print(result)
# {'value': 4, 'steps': ['add_one', 'double']}
# value: (1+1)*2 = 4;steps 因 reducer 被追加成完整轨迹

把上面的 value 换成 messages: Annotated[list, add_messages]、把节点换成『调 LLM』和『跑工具』、再把 add_one -> double 的普通边换成一条根据 LLM 输出决定『去工具节点还是去 END』的条件边,你就得到了一个真正的 ReAct Agent。整本 wiki 都在沿这条主线展开。

# 真实场景的 30 秒预览:官方 prebuilt 一行起一个带工具的 ReAct Agent
# pip install -U langchain-openai
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI


def get_weather(city: str) -> str:
    """查询某城市天气。"""          # docstring 会作为工具描述喂给 LLM
    return f"{city} 今天晴,26C"


agent = create_react_agent(
    model=ChatOpenAI(model="gpt-4o-mini"),  # 任意 LangChain ChatModel
    tools=[get_weather],                     # 普通函数即可作为工具
)

# 输入/输出都走 messages:这正是上面 State 心智模型的真实形态
result = agent.invoke(
    {"messages": [{"role": "user", "content": "北京天气怎么样?"}]}
)
print(result["messages"][-1].content)
# create_react_agent 内部就是「LLM 节点 + 工具节点 + 条件边」编译成的 StateGraph
推荐做法
  • 需求里出现『循环』『重试』『分支判断』『多个 Agent 接力』『跑到一半要人工确认』时,直接上 LangGraph
  • 先用 TypedDict 把 State 想清楚(有哪些字段、各自怎么合并),再动手加节点
  • 对话/Agent 一律带 add_messages reducer 管理 messages,别手动拼 list
  • 前期用 create_react_agent 这类 prebuilt 快速验证,复杂控制流再下沉到手写 StateGraph
不推荐
  • 不要为一条确定性的『prompt -> llm -> parser』管道硬上 LangGraph,那是 LCEL 的活
  • 不要把状态藏在节点的全局变量/闭包里——状态必须进 State,否则 Checkpointer 存不到、恢复不了
  • 不要在节点函数里直接修改传入的 state 对象,应当 return 一个『更新字典』让 reducer 合并
  • 不要一上来就写多智能体大图,先把单 Agent 的环跑通
常见误区
  • 把 LangGraph 当成 AgentExecutor 的语法糖——它是更底层的图运行时,心智模型完全不同
  • 忘了 reducer:默认字段是覆盖语义,消息列表会被后一个节点冲掉,表现为『上下文丢失』
  • compile 后才想起要持久化——Checkpointer 是在 compile(checkpointer=...) 时挂载的

能用『State / Node / Edge / Checkpointer』四个词解释清楚你要建的图,并说出哪条边是条件边、为什么这张图会成环——就算掌握了本章。

全书学习路径

  1. 安装与环境配置:装对包(langgraph + checkpoint backend),跑通 hello graph
  2. 核心概念:图、State、Node、Edge 的精确定义与 START/END
  3. 快速上手 StateGraph:从零搭第一个真正有用的图
  4. State 与 Reducer:Annotated、add_messages,搞懂状态合并
  5. 条件边与路由:动态控制流,让图学会『分支与成环』
  6. Checkpointer 持久化:thread_id 会话、断点恢复、时间旅行
  7. 流式输出与 HITL:values/updates/messages 三种流模式 + interrupt 中断恢复
  8. 多智能体、子图与 prebuilt:supervisor、swarm、subgraph、create_react_agent
  9. 踩坑与生产部署:把图安全地送上线

瓶颈是验证,不是生成。把 Agent 的控制流画成可检查、可存档、可单步的图,你才真正拥有了它——而不是被一个黑盒 while 循环拥有。

— 本 Wiki 编写原则