Agent 专题写到今天,工具箱已经换过三代:裸 SDK 系列手写工具循环,messages 列表、tool call 分发、重试兜底全部亲手造过一遍;LangChain 基础系列换了趁手的家伙,用 create_agent 把同一套循环藏进库函数;TypeScript 侧还用 Mastra 对照着写过一轮。工具越用越高级,但有个问题一直没正面回答:当循环本身复杂到一定程度,while 就不够用了。
《LangGraph 从入门到实战》是 Agent 专题的收官系列,共 14 篇,前置只有裸 SDK 与 LangChain 基础两个系列。主角 LangGraph 做的事,是把 Agent 循环从代码里的控制流提升为一种显式数据结构——图。本篇是第 1 篇,只立"图"这个心智模型,不写可运行的完整代码(第 2 篇动手)。全文按"痛点 → 心智模型 → 与 LangChain 的关系 → 与 while 的等价性 → 超能力预告 → 路线图"展开。
1、while 循环的失控
裸 SDK 系列里那个工具循环,压缩后一共十行:
def run(messages, max_steps=10):
for _ in range(max_steps):
resp = model.invoke(messages, tools=TOOLS)
if not resp.tool_calls: # 终止条件一:不再要工具
return resp.content
messages.append(resp) # 对话历史手工维护
for call in resp.tool_calls: # 分发、重试全是自己的事
messages.append(run_tool(call))
return "已达到步数上限" # 兜底散落在循环外
十行代码干干净净,写 demo 完全够用,问题出在它长大之后。往循环里持续加需求:工具失败要重试、某类操作要人工确认、并发调用要聚合、超时要打断——每一项都往循环体里塞 if,终止条件从一个变成五个,散落在函数各个角落。三个月后回看,"这个循环什么时候停"没有一行代码能回答,答案分布在整个函数体里。
痛点归成三类。状态传递乱:messages 是个裸列表,谁都能 append、谁都能改,几个分支过后没人说得清当前上下文里到底有什么。循环控制散:终止、限流、降级全是手写 if,彼此没有统一形态,改一处牵一串。恢复难:进程一重启,循环里攒下的状态全部归零;想"跑到第三步暂停、明天接着跑",得自己设计存储与恢复协议,这部分代码常常比业务本身还长。
往根上说:这个循环其实是一张图——模型节点、工具节点、条件转移、回边——只不过藏在 while 和 if 的控制流里,看不见摸不着。看不见的结构没法审查、没法存档,更没法在它上面做基础设施。LangGraph 做的事,就是把它从代码里拉出来,变成显式声明的一等公民。
2、图式编排心智模型
LangGraph 的核心抽象一句话讲完:节点是函数,边是控制流,State 是共享黑板。
节点(node)是一个普通 Python 函数:读入完整 State,返回要更新的字段子集,框架负责把增量合并进黑板。边(edge)声明"下一步去哪":普通边是固定转移;条件边(conditional edge)挂一个路由函数,按当前 State 动态决定去向——分支、循环、提前收束,全部由边表达。State 是全图唯一的共享数据结构,典型形态是消息列表加若干业务字段,每个节点都读它、写它。
拿一个客服 Agent 举例,把流程画成三个节点的图:理解提问、查知识库、组织回答,查完知识库带着结果回到理解节点重新判断。图示如下:
解读这张图:里面没有任何循环语句,"查完再理解、理解完可能再查"的循环,被表达成一条从"查知识库"指回"理解提问"的边。循环还在,但它从控制流语句降级为图上的一条线,与普通边平起平坐。三要素与常规代码的对应关系整理成表:
| 图元素 | 代码世界里的对应物 | 职责 |
|---|---|---|
| 节点 | 一个函数 | 干活,返回状态增量 |
| 普通边 | 函数的调用顺序 | 固定转移 |
| 条件边 | if 与循环判断 | 动态路由与回环 |
| State | 贯穿全程的上下文对象 | 全图共享的黑板 |
用这个模型回看第 1 节的失控循环:messages 就是 State,模型调用与工具执行就是两个节点,"还有没有 tool call"就是条件边。业务没变,变的是表达方式——从"读代码脑内模拟执行"变成"看图"。
3、与 LangChain 的关系
先交代版本事实。langgraph 是独立发布的包,不装 langchain 也能单独使用;它出自 LangChain 团队之手,官方定位是低层编排框架(low-level orchestration framework)与 Agent 运行时。版本线方面,2025 年 10 月 LangGraph 发布 1.0 进入稳定期,截至 2026 年 10 月已迭代到 1.2.x,PyPI 最新为 1.2.18。文档并入 LangChain 统一文档站,入口在官方文档的 LangGraph 分区,源码在 GitHub 仓库。1.0 之后 StateGraph 有了正式名字 Graph API,与 Functional API 相对,但它依旧是搭图主入口,from langgraph.graph import StateGraph, START, END 这行导入从 0.x 时代用到今天没变过。
两者的分工一句话:LangChain 给组件,LangGraph 给编排。LangChain 负责与模型、工具、提示词打交道,create_agent 封装了开箱即用的标准 Agent;LangGraph 负责把任何东西——包括 create_agent 造出的 Agent——当作图上的一个节点,与自定义节点、条件边、检查点组装成任意流程。对照如下:
| 维度 | LangChain | LangGraph |
|---|---|---|
| 定位 | 组件与集成 | 编排与运行时 |
| 典型入口 | create_agent | StateGraph |
| 解决什么 | 怎么调模型、怎么定义工具 | 流程怎么走、状态怎么存 |
| 单独使用 | 可以 | 可以 |
| 组合形态 | 产出的 Agent 作为图中节点 | 为组件提供流程骨架 |
两个常见误解当场拆掉。其一,"用 LangGraph 必须用 LangChain"——不必,节点就是普通函数,接什么模型客户端都行。其二,"LangGraph 是 LangChain 的高级封装"——方向反了,官方定位恰恰是低层框架:预封装入口越不合身,越要下沉到 LangGraph 自己搭图。顺带一提,0.x 时代住在 langgraph.prebuilt 里的 create_react_agent,1.0 起推荐入口收拢为 LangChain 侧的 create_agent。本系列两边都会用:中段以 StateGraph 讲透机制,实战篇回到 create_agent 享受封装红利。
4、同一个循环的两种写法
心智模型立住了,现在把它与 while 循环正面并排。同一个"模型-工具"循环,裸写版本如下(LangChain 基础系列口径,9 行):
def run_agent(messages: list) -> str:
for _ in range(MAX_STEPS):
resp = model.invoke(messages)
if not resp.tool_calls: # 不再要工具即收尾
return resp.content
messages.append(resp)
for call in resp.tool_calls:
messages.append(run_tool(call))
raise StepLimitError("已达到步数上限")
解读:控制流长在代码里——for 管步数上限,if 管出口,函数体就是流程的全部真相。换成 LangGraph 的图写法(15 行,ToolNode 来自 langgraph.prebuilt,第 6 篇展开):
from langgraph.graph import MessagesState, StateGraph, START, END
def agent(state):
return {"messages": [model.invoke(state["messages"])]}
def route(state): # 有工具调用去 tools,否则直达终点
return "tools" if state["messages"][-1].tool_calls else END
builder = StateGraph(MessagesState)
builder.add_node("agent", agent) # 节点一:模型
builder.add_node("tools", ToolNode(TOOLS)) # 节点二:工具
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", route) # 条件边:去或停
builder.add_edge("tools", "agent") # 回边:循环在此
graph = builder.compile()
对照着读三件事。其一,循环消失了:没有任何循环语句,"回到 agent"是一条普通边,回环与直线在图里地位相同。其二,State 不再手工维护:agent 节点只返回增量消息,MessagesState 内置的 reducer 负责拼回黑板(reducer 是第 3 篇的主角)。其三,原先散落各处的步数上限,变成运行时统一参数 recursion_limit(1.0.6 起默认 1000)——从"每个循环自己数"变成"框架替你数"。
两种写法表达力等价:图能做的 while 都做得到,反之亦然。真正的差别在于,结构显式化之后,框架获得了在结构上做事的位置——这正是下一节的内容。
5、图带来的超能力
流程一旦成为显式数据结构,框架就在任意两个节点之间拿到了插入点。四类生产环境最值钱的能力,都从这个插入点长出来。
循环与多代理。条件边加回边,任意复杂的拓扑都是同一种写法,不存在"嵌套 while 管不住"的复杂度天花板。多代理协作也顺理成章:一张图可以作为节点嵌入另一张图,supervisor 循环派活、worker 干活交差,组网方式与单 Agent 同构(第 10 篇展开)。
持久化。每一步都是图上的超步(superstep),框架能在每个超步结束时给 State 打快照(checkpointer)。进程崩溃后从最近快照续跑,对话历史、工具结果、中间判断一样不丢——第 1 节的"恢复难"在这里被系统性解决(第 7 篇)。
中断恢复。在任意节点声明 interrupt,图跑到此处自动挂起、存档、返回等待;人工审批完成后带着决定恢复执行。human-in-the-loop 从"自己设计暂停协议"变成一行声明(第 8 篇)。
可观测。图的执行历史就是"走到过哪些节点、每步 State 长什么样",回放、逐步重跑、按图调试天然可用(第 12 篇)。
while 循环里,这四项能力每一项都得自己造轮子;图里它们是框架的默认责任——因为框架看得见你的流程。
6、系列路线图
全系列 14 篇,四段推进:本篇立模型,第 2~6 篇把单 Agent 图写透,第 7~9 篇解决生产可靠性,第 10~14 篇组网与上线。完整地图如下:
- 第 1 篇:图式编排心智模型(本篇)
- 第 2 篇:环境搭建与第一个 StateGraph
- 第 3 篇:State 深入——共享黑板与 reducer
- 第 4 篇:节点与边——路由、分支与并行
- 第 5 篇:create_agent——官方预置的 Agent 图
- 第 6 篇:工具接入——ToolNode 与工具循环
- 第 7 篇:Checkpointer——持久化与时间旅行
- 第 8 篇:中断与恢复——human-in-the-loop
- 第 9 篇:流式输出——token 与节点事件
- 第 10 篇:子图与多 Agent 协作
- 第 11 篇:Functional API——函数式写图
- 第 12 篇:测试与调试——图的可观测性
- 第 13 篇:部署——从 pm2 到 LangGraph Platform
- 第 14 篇:实战——生产级多 Agent 项目
节奏上唯一的例外就是本篇:整个系列里它只讲不写,从第 2 篇起每篇都有可运行代码,第 14 篇把全部能力合成一个完整项目。
7、总结
本篇立了一个心智模型:Agent 循环本质是一张图,节点是函数、边是控制流、State 是共享黑板;while 循环把这张图藏在控制流里,LangGraph 把它显式声明出来。两种写法表达力等价,但结构显式化之后,循环控制、持久化、中断恢复、多代理组网从"自己造轮子"变成"框架的默认责任"。LangGraph 与 LangChain 的分工也清楚了:一个给组件,一个给编排,可分可合,版本事实上 langgraph 已独立迭代到 1.2.x。
留一个不动手的练习:把你手头一个真实业务——订单审核、周报生成、代码评审都行——在纸上画成一张图,依次回答三个问题。哪些步骤是节点?一句话能说清输入输出的才配当节点。哪里需要条件边?把"判断去哪"的逻辑单独拎出来。State 黑板上放哪几个字段?够用就好,多一个字段就多一份合并烦恼。画完自查有没有回边——没有循环的业务流程,多半还不需要 LangGraph。对于准备入坑的读者,建议把这张纸留好,等第 2 篇动手时直接把它翻译成第一个 StateGraph。

