状态图编排:持久执行与检查点 本节摘要:Agent 与工作流共享一个问题:当一个 40 步的运行在第 38 步失败,你想从第 38 步续上,而不是从头重来。二流的状态模型让运维只能在一个「假设每次都是全新运行」的库周围 hack 重试。LangGraph 的设计回答是:状态是一等公民的类型化对象,变更显式,每个节点之后都持久化检查点——恢复就是一次 调用。本节吃透 LangGraph 的核心模型:Agent 是状态机,节点是纯函数 ,边是条件或直连转移,状态在每个节点后被检查点化,可在任意失败处从上一个成功检查点恢复。它提供四大能力——持久执行、流式、人在环中、综合记忆——以及三种编排拓扑:监督者、对等群体(Swarm)、层次化嵌套子图。Klarna、Uber、J.P.
本节摘要:Agent 与工作流共享一个问题:当一个 40 步的运行在第 38 步失败,你想从第 38 步续上,而不是从头重来。二流的状态模型让运维只能在一个「假设每次都是全新运行」的库周围 hack 重试。LangGraph 的设计回答是:状态是一等公民的类型化对象,变更显式,每个节点之后都持久化检查点——恢复就是一次
load_state(session_id)调用。本节吃透 LangGraph 的核心模型:Agent 是状态机,节点是纯函数(state) -> state_update,边是条件或直连转移,状态在每个节点后被检查点化,可在任意失败处从上一个成功检查点恢复。它提供四大能力——持久执行、流式、人在环中、综合记忆——以及三种编排拓扑:监督者、对等群体(Swarm)、层次化嵌套子图。Klarna、Uber、J.P. Morgan 等生产用户证明了「图形状 + 检查点」让恢复变廉价。本节用标准库从零实现一个带类型化状态、条件边、检查点/恢复循环的状态图。
对应原课程:Phase 14 · Lesson 13 ·
langgraph-stateful-graphs(原英文phases/14-agent-engineering/13-langgraph-stateful-graphs/docs/en.md)。
阅读完本节,你应当能够:
Agent 与工作流共享一个问题:当一个 40 步的运行在第 38 步失败,你想从第 38 步续上,而不是从头重来。二流的状态模型让运维只能在一个「假设每次都是全新运行」的库周围 hack 重试。
LangGraph 的设计回答:状态是一等公民的类型化对象,变更显式,检查点在每个节点后持久化。恢复是一次 load_state(session_id) 调用。
一个图由四样东西定义:
(state) -> state_update,返回后把 update 合并进状态。START 与 END 哨兵节点标出边界。例子:一个带 classify、refund、bug、sales、done 节点的 Agent——把第 12 节的路由工作流表达成图。
每个节点返回后,运行时把状态序列化写进一个检查点器(SQLite、Postgres、Redis、自定义)。第 N 步失败时,运行时可 resume(session_id),带着精确状态从第 N+1 步续上。
LangGraph 文档明确点名了这件事关乎生产用户:Klarna、Uber、J.P. Morgan。论点不在图形状本身,而在图形状 + 检查点让恢复变廉价。
💡 设计要点:状态一等公民的真正价值不在「能存」,而在「能精确恢复」。当失败发生,你不是重跑整个昂贵流程,而是从最后一个成功节点带着完全一样的状态续上。这对长流程(审批、合规、多步研究)是质变——一次 LLM 调用的钱省下来,远超检查点器的运维成本。
langgraph-supervisor 里的 create_supervisor()(不过 LangChain 团队 2026 年建议直接通过工具调用做这件事,以获得更多上下文控制)。原课程 code/main.py 用标准库实现一个状态图:
State —— 类型化字典,带 messages、step、route、output、human_approval。Node —— 可调用对象,取状态返回 update 字典。StateGraph —— 节点 + 边 + 条件边 + run + resume。SQLiteCheckpointer(内存版替身)—— 每个节点后序列化状态;load(session_id) 恢复。核心骨架如下,用伪代码展示。
from typing import TypedDict class State(TypedDict): messages: list step: int route: str # refund / bug / sales output: str human_approval: bool def classify(state: State) -> dict: route = llm_classify(state["messages"][-1]) return {"route": route, "step": state["step"] + 1} def refund(state: State) -> dict: return {"output": "退款已处理", "step": state["step"] + 1}
class StateGraph: def __init__(self, state_type): self.nodes = {} self.edges = {} # node -> 下一步(直连名或条件函数) def add_node(self, name, fn): self.nodes[name] = fn def add_conditional_edges(self, name, router_fn, mapping): # router_fn(state) -> key; mapping[key] -> 下一个节点名 self.edges[name] = ("cond", router_fn, mapping) def add_edge(self, src, dst): self.edges[src] = ("direct", dst)
class SQLiteCheckpointer: def __init__(self): self.store = {} # session_id -> [state 快照...] def save(self, session_id, state): self.store.setdefault(session_id, []).append(dict(state)) def load(self, session_id): snaps = self.store.get(session_id, []) return snaps[-1] if snaps else None def run(graph, state, session_id, ckpt): while state.get("step_node") != "END": node_fn = graph.nodes[state["step_node"]] update = node_fn(state) state.update(update) ckpt.save(session_id, state) # 每个节点后检查点 state["step_node"] = next_node(graph, state) return state def resume(graph, session_id, ckpt): state = ckpt.load(session_id) # 精确恢复 return run(graph, state, session_id, ckpt)
运行 python3 code/main.py 会展示第一次运行在人工闸门失败、持久化、然后恢复产出最终输出。
💡 设计要点:
resume之所以能精确恢复,全靠「节点是纯函数 + 状态完全序列化」两个前提。如果某个节点读了墙钟、随机数、或外部 API 而没把这些捕获进状态,恢复后重放就会得到不同结果——这是「非确定节点」反模式的根。
create_react_agent、create_supervisor,或自建图。| 框架 | 模型 | 检查点 | 适用 |
|---|---|---|---|
| LangGraph | 状态机 | 内置多后端 | 持久状态图 |
| AutoGen v0.4 | Actor | 需配 | 高并发 |
| Claude Agent SDK | 托管 harness | 内置会话存储 | Claude 生态 |
| 自建 | 全控 | 全控 | 精确控制 |
本节产出一份可复用技能(原课程 outputs/skill-state-graph.md):
skill-state-graph.md:给定任意目标运行时,生成一个 LangGraph 形状的状态图,内置检查点与恢复接线。包含一份状态设计清单(状态字段是否覆盖工具结果与记忆写入?哪些字段该进检查点?reducer 怎么合并并发 update?),以及一份恢复可靠性清单(节点是否纯函数?随机种子/墙钟/外部 API 是否捕获?条件边是否克制?)。Python 代码(code/main.py)是独立可运行的状态图骨架,类型化状态、条件边、检查点/恢复都是后端无关的;把内存检查点器换成真实 SQLite/Postgres 即可投入生产。
classify 到 end 的条件边:分类置信度低于阈值时走它。人工手动设置 route 后恢复运行。langgraph-supervisor 参考。把玩具移植到 create_supervisor。对比轨迹形状。load_state(session_id)。create_supervisor 给更多上下文控制。下一节,我们看 Actor 模型——AutoGen v0.4 用消息传递的并发原语替代状态机,当你的场景是高并发多 Agent 协作时,它比状态图更合身。