TL;DR: LangGraph 是面向长时运行、有状态 Agent 的编排引擎,不是 AI 应用的默认起点。选不选它,四个问题就够:任务要不要断点续跑、高风险动作要不要人审、要不要多角色编排、出问题要不要回放追责。四个都答否,几十行手写循环更干净;任何一个答是,它才开始划算,而且要连它的运维成本一起接受。
先看一个不需要任何框架的 Agent
很多人在项目第一天就把 langgraph 写进了 requirements.txt,理由通常是「以后要做 agent」。这个理由值得推敲,因为 agent 的核心机制本来就不复杂,值得先亲手摸一遍。
我们先不加任何框架,直接用模型官方 SDK 写一个能自主调用工具的 agent:
# pip install openai==1.102.0
# export OPENAI_API_KEY=sk-...
import json
from openai import OpenAI
client = OpenAI()
MODEL = "gpt-4o-mini"
MAX_STEPS = 8
def get_weather(city: str) -> str:
return f"{city}:晴,26°C" # 演示用假数据,替换成真实 API 即可
TOOLS = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询一个城市的天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
def run(question: str) -> str:
messages = [{"role": "user", "content": question}]
for _ in range(MAX_STEPS):
resp = client.chat.completions.create(
model=MODEL, messages=messages, tools=TOOLS
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content or ""
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
return "达到最大步数,停止"
print(run("北京和上海今天哪个更热?"))
大约 40 行,这是一个完整的 agent,没有夸张。它的核心是一个循环:模型收到问题和工具列表,自己决定是调工具还是直接回答;调了工具,结果就拼回上下文再问一轮;直到模型不再要工具,循环结束。所谓「自主」,就是把「调什么工具、调几次」这个决策交给模型,而不是写死在 if/else 里。
顺着这段代码,可以把「agent」这个词定义得非常朴素:一个大模型,一组它能调的工具,一个让它反复决策的循环,加一个终止条件。四个部件都在上面这 40 行里。市面上所有 agent 框架,不管宣传语多复杂,做的都是这四个部件的工程化:工具注册做得更顺手,循环里加更多控制,终止条件做得更可靠。理解了这个,选型问题就从「哪家强」变成了「我的任务在哪个部件上超出了手写的舒适区」。
这段代码的弹性也比很多人预期的高。换模型,只改一个字符串;加新工具,往 TOOLS 里加一项描述;怕模型绕圈,把 MAX_STEPS 调小。调试也直接:messages 数组里每一步都看得见,出了错从头打印一遍,就能知道模型在哪一步开始跑偏。
当然,它的天花板也是真实存在的,只是不在功能层面。messages 数组随着每一步持续膨胀,第 8 步的调用要把前面 7 步全部带上,token 账单随步数非线性上涨,这段代码没有任何管理手段;两次运行之间互相不知道对方存在,没有跨会话记忆;多实例同时部署时,谁也不知道谁在跑。这些缺口分别是本系列第 04 篇和第 13 篇的主题,而它们还不是框架的入场券,真正的入场券是下面三个时刻。
相当一部分被称为「智能体」的需求,比如查数据再总结、按步骤填表单、给文章配摘要配标签,到这一步就已经完成了。先写这 40 行还有一个额外的好处:以后无论用不用框架,你都真正理解 agent 在干什么,而不是隔着一层框架术语去猜。
手写循环会在三个时刻撞墙
舒适区被打破,不是因为你想要更多功能,而是因为需求长出了框架才有的形状。具体是三个时刻。
时刻一:任务跑到一半,进程没了。 一个挂着审批的流程跑了三天,周五晚上服务器重启,周一用户回来问:跑到哪了?能不能从第三步继续,别从头来。要满足这句话,你得做三件事:每一步之后把状态存到进程外,存数据库而不是内存;存的东西要能还原成一个可以继续跑的现场;还原之后,之前发过的请求、写过的记录不能重发重写,也就是副作用要幂等。每一件都有坑:快照存多细,粒度错了恢复不完整或者慢得没法用;状态结构改版之后,旧快照怎么读;「继续」的语义是重跑最后一个节点,还是从暂停的某一行接着走。
时刻二:执行到高风险动作,需要有人点头。 转账、删数据、群发邮件之前停下来等人确认。听起来简单,实现起来要回答:暂停的时候,执行到一半的状态放在哪?审批人三天没看,流程超时算批准还是驳回?人批完,从哪一行继续?用 sleep 轮询数据库实现,进程就一直被占着;把状态序列化塞进任务队列,等于在自研一个持久化引擎。
时刻三:出了问题,要能回到历史某一步看现场。 客户说上周三那次跑错了参数,你需要的不是道歉,而是重放那一次的执行路径,看到每一步的输入输出。重放的前提是每一步的状态都被完整记下来,带时间线,能定位到具体某一次运行。这又是一套存储和检索,而且平时没人用它,出了事才发现缺。
三个时刻对应的正是持久化、human-in-the-loop、时间旅行。自己实现不是不行,从零手写的团队在这三件事上把重试、断点、状态管理的补丁写到几千行的故事不少,也有人写到最后又回到了框架。这三个时刻真的出现了,框架才开始划算;「以后可能有」不算,提前上框架,抽象税从第一天就在付。
LangGraph 到底是什么
截至 2026 年 9 月,LangGraph 最新版本是 1.2.11,1.0 发布于 2025 年 10 月,官方承诺 1.x 内不做破坏性变更。项目 README 的自我定位很直白:low-level orchestration framework for building stateful agents,面向长时运行、有状态 agent 的低层编排框架。「low-level」不是自谦,是在提醒你它管的是底下那一层。
它的执行模型说穿了是一个状态机:你定义一个 state 结构,把要做的事拆成节点(就是普通函数,接收 state、返回对 state 的更新),再用边把它们连起来,边可以是固定的,也可以由条件决定走向。运行时从入口开始,每一步把当前 state 交给下一个节点,节点返回的更新合并进 state,直到走到终点。前面那 40 行手写循环,在这个模型里就是「模型节点」和「工具节点」互相连接转圈,循环的每一步都恰好是一个可以存档的边界。这就是「有状态编排」的字面意思:状态不再埋在函数调用的栈里,而是一个显式的、可以被存取和恢复的数据结构。不想画图也有函数式写法(第 05 篇的 @entrypoint 和 @task),但底下的存档和恢复机制是同一套。
1.0 还带来一个容易被忽视的结构变化:旧的 langgraph.prebuilt.create_react_agent 被废弃,高层封装 create_agent 移到了 langchain.agents,而它运行在 LangGraph 的运行时之上,再往上是 deepagents 这类 agent harness。分层倒过来了:LangGraph 不再是「带图 API 的全家桶」,而是底下那台引擎,上面可以套不同的壳。所以「我该用 LangChain 还是 LangGraph」这个问题在 1.x 之后问法变了:你要选的是上面的壳,LangGraph 是共用的底座。本系列第 11 篇专门拆这层封装。
1.0 还带来一个容易被忽视的结构变化:旧的 langgraph.prebuilt.create_react_agent 被废弃,高层封装 create_agent 移到了 langchain.agents,而它运行在 LangGraph 的运行时之上,再往上是 deepagents 这类 agent harness。分层倒过来了:LangGraph 不再是「带图 API 的全家桶」,而是底下那台引擎,上面可以套不同的壳。所以「我该用 LangChain 还是 LangGraph」这个问题在 1.x 之后问法变了:你要选的是上面的壳,LangGraph 是共用的底座。本系列第 11 篇专门拆这层封装。
它给你的核心能力就四件,每一件都对着前面某个时刻:
- 快照:图执行每跨过一个边界就存一次状态,挂在某个 thread_id 下。一次对话、一次任务就是一个 thread,它的全部历史随时可取。这是时刻一的答案,第 03 篇拆解它到底存了什么、恢复语义是什么。
- 叫停与恢复:
interrupt()在任意位置暂停存档,人处理完用Command(resume=...)从断点继续。这是时刻二的答案,demo 五分钟能跑通,生产化的坑在第 06 篇。 - 回放:拿着历史 checkpoint 重跑或分叉。调试和追责都靠它,这是时刻三的答案,也是第 15 篇回归测试的地基。
- 编排:一个图里挂多个有独立状态的子角色,supervisor 派活或对等移交都行。第 09 篇专门讲什么时候该放弃多角色。
Uber、LinkedIn、Klarna、Replit 都在生产使用它。这是 LangChain 官方口径,参考时记得打折。
一条判断线:四个问题
把三个时刻加一条编排需求,就是完整的判断线。对着你的项目问:
- 任务会不会跑到一半中断,之后需要从断点继续?注意答「是」的标准不是「可能断网」,而是中断之后用户真的在乎从哪继续。一次几十秒的生成任务,失败重跑一遍就行,这不叫断点续跑需求。
- 有没有高风险动作需要在执行前经过人工确认?「高风险」指动了钱、动了数据、动了外部世界:转账、删记录、对外发消息。只在屏幕上展示内容给用户看的,不算。
- 是否真的需要多个角色分工,而不是一个配了好工具的单角色能解决?把一个能干活的单角色拆成 supervisor 加三个 sub-agent,通常只会更慢、更贵、更难调试。
- 出了问题,是否需要回放历史执行路径来定位或追责?内部工具可能日志就够了;面向客户、涉及资金的流程,「上次到底怎么走的」是硬需求。
任何一个答「是」,LangGraph 值得认真评估。四个全答「否」,手写循环、裸 SDK 或者 Pydantic AI 这类轻量封装是更便宜的选择。
拿两个项目套一下这套题。第一个,周报生成器:读 issue 和 commit 记录,生成草稿,人改完发出。跑一次几十秒,失败重跑就行,不花钱也不动外部世界,四个全否,40 行循环加一个定时任务就是全部,上框架纯粹是给自己找事。第二个,报销审批 agent:读发票、校验金额、按金额分级,超过五千要财务总监批,审批经常跨天,批完还要触发付款。第一问是(跨天中断),第二问是(动钱),第三、四问看公司要求。两个「是」已经足够认真评估它了,剩下的题不用做完。
再补一个关于第三问的例子,因为「要不要多角色」是被幻想污染最重的一题。有人做一个客服 agent,把意图识别、查订单、查退款政策、生成回复拆成四个角色加一个 supervisor,跑通之后发现比单角色配四个工具更慢也更贵,还多出一堆角色之间传话丢信息的 bug。拆分的理由是「职责清晰」,但职责清晰是给人看的代码架构理由,模型不在乎你的类图。拆的正当理由只有一个:单个角色的上下文装不下,或者不同角色的工具和权限确实需要隔离。多数号称需要多 agent 的需求,答案见第 09 篇。
回答这四个问题靠证据,不靠想象。判断材料就在两个地方:需求文档和已有日志。审批跨不跨天,产品经理知道;动作动不动钱,需求文档写着;跑一次要几步、失败率多高,真跑几天日志里都有。反过来说,在还没有任何运行数据的需求评审会上拍板「我们要上 LangGraph」,和拍板「我们不要」一样,都是在猜。
灰色地带也存在。比如你要的其实只是 durable execution:任务在机器重启后自动恢复、失败自动重试,并不需要 agent 语义和图编排,那 Temporal 这类工作流引擎比 LangGraph 更对口。下面的案例部分有一个现成的迁移故事,本系列第 19 篇有完整对比。
用它的代价:即使四个问题都答「是」
这是官方文档不会放在首页的部分。
调试体验会变差。 你的代码不再是从上到下执行,而是拆成节点在图里跳,循环图和主流 APM 的 span 树模型对不上,报错堆栈经常在节点边界断掉:你看到某个节点抛了异常,却不容易看到它进入之前状态长什么样。社区里「没有 LangSmith 就活不下去」的说法反复出现,而 LangSmith 收费,开源替代都得自己搭。第 14 篇讲循环图的观测和测试怎么落地。
多一个有状态组件要运维。 checkpointer 在生产要接真数据库(内存版禁用),checkpoint 表持续膨胀需要清理策略,state schema 演进没有官方版本化迁移工具。2025 年还出过 patch 版本夹带破坏性变更的事故:langgraph-checkpoint-postgres 从 2.0.21 升到 2.0.22,metadata 序列化被打挂,跟着升级的服务直接报错。连 patch 版本都不能闭眼升,这是把一个持久化中间件放进依赖时要想清楚的事。第 13 篇是一次真实的表膨胀事故复盘。
学习成本在抽象层。 reducer、superstep、Command 这些概念要先建立心智模型,才能写出不出错的代码。state 里放什么、节点返回增量还是全量、并行分支怎么合并,都是新坑,而且这些坑不在 demo 阶段出现,会在上线后的诡异 bug 里出现。第 02 篇用「状态是一组每个 key 带合并规则的通道」这一个模型,把大半概念串了起来。
教程时效风险。 0.x 时代的中文教程和翻译站大量存在且已过期,照着旧教程写会直接用到废弃 API,而报错信息不会告诉你是教程老了。第 18 篇整理了 0.x 到 1.x 的迁移清单。
这四笔账列在一起容易让人觉得框架一无是处,所以要说明白抽象税买到了什么。付了这些成本,你换来的是一套被大量生产系统验证过的恢复语义:快照什么时候存、恢复从哪继续、并行怎么合并,这些最难的语义决定官方替你做了,而且文档写得清楚。自己手写的版本里,这些语义散落在几千行补丁的每个 if 里,写的人离职之后没人敢动。也就是说,代价是真的,换来的东西也是真的,判断线回答的是「你需不需要这个东西」,不是「这个东西好不好」。
三个真实案例:两正一反
Uber(正面)。 面向 5000 多名内部工程师的 AI 开发工具,用 LangGraph 编排代码修复、单测生成等专用 agent,官方口径称节省 21000 多工程师小时。对着判断线看:流程长(一次修复跨多步)、需要审计(改的是生产代码库)、多角色分工明确。四个问题至少三个答是,这是框架兑现价值的场景。数字出自官方口径,折扣照打,但「任务形状和框架能力对得上」这一点是能看出来的。
Klarna(正反两面)。 客服 assistant 上线首月处理 230 万次对话,消化约三分之二的客服会话,解决时长下降约 80%。这些数字被广泛引用,常被省略的是后半句:Klarna 后来公开承认过度自动化损害了服务质量,重新招回了人工客服。这个案例和框架选型关系不大,和判断线第二问背后的事有关:自动化替掉的那部分里,有些本来就该有人在场。框架没有问题,问题在于把「能自动化」当成了「该自动化」。
Grid Dynamics(反面)。 给一家财富 500 制造商做深度研究 agent,技术栈是 LangGraph 加 Redis、Kafka。他们踩到状态过期 bug 难以复现、人审等待需要自建重试、Kafka 扩容竞态,最后整体迁到 Temporal,删掉了数千行自建的重试和错误处理代码。关键结论不是「LangGraph 不行」,而是他们要的核心其实是 durable execution:声明式重试、无状态 worker、自动恢复。checkpoint 提供的是快照存取,不等于这一整套执行保障。用判断线复盘:他们真正答「是」的只有第一问的一半,而重试保障、人审长时间等待这些痛点,Temporal 的原语更对口。
还有一个常被引用的弃用故事:Octomind 写过《Why we no longer use LangChain》,核心论点是框架在需求变具体之后就崩了,Hacker News 上有几百条讨论,LangChain 的 CEO 也亲自回应。公平起见,反方向的故事同样真实:不少从零手写的团队,在重试、断点恢复、并发控制上补丁写到几千行之后,又回到了框架。两边都是真实经验,区别不在团队水平,在任务落在判断线哪一侧。
替代品速查
| 你的情况 | 更顺手的起点 |
|---|---|
| 单趟任务、简单线性链 | 裸 SDK,手写循环 |
| 只需要长任务断点恢复,不需要图 | Temporal、Restate 这类 durable execution 引擎 |
| 想要开箱即用的编码 agent | Claude Code、Claude Agent SDK |
| 原型期多角色协作,先跑通再说 | CrewAI |
| 要 agent 但想避开重抽象 | Pydantic AI、smolagents |
这份表不是排名,每一行的成立条件就是左边那句话,条件变了结论就变。两个常见的误用值得点名:拿着「只需要断点恢复」的需求去用 LangGraph,会为用不到的图编排付抽象税;拿着「流程固定、每步都是确定性代码」的需求去用任何 agent 框架,你要的可能只是一个普通工作流引擎,模型参与决策的地方才算 agent。
结论
回到标题的问题。建议按顺序:
- 先手写。100 行以内的循环加两三个工具,能覆盖大多数需求,还能让你真正理解 agent 在干什么。这几十行不会白写,它们以后就是 LangGraph 图里每个节点的内容。
- 撞到判断线里的任何一个「是」(断点续跑、人审、多角色、回放),再认真评估 LangGraph,并且接受它的运维成本:真数据库、表清理、版本升级纪律。
- 如果发现要的其实只是任务恢复而不是编排,去看 Temporal 一类的工作流引擎,别拿 agent 框架硬凑。
提前给项目装上 LangGraph 不算错误,但抽象税从第一天就开始付,收益要等你真的撞上那三个时刻才兑现。反过来,四个问题答了「是」还硬扛手写,付的是另一种税:几千行状态管理补丁,和出事那天没人看得懂的现场。
两个执行层面的提醒。第一,别用名气做决定:「Uber 在用所以我也用」和「Octomind 弃用了所以我不碰」是同一种论证错误,他们的任务形状和你的不一样,结论不可移植,能移植的只有判断方法。第二,如果评估结果含糊,就花一个下午做一次有截止时间的验证:挑一个真实流程用它立起来,接上真数据库,让两三个同事各跑一遍。团队卡在哪、哪里别扭、state 该放什么,一下午暴露的问题比两周会议多。验证完不用它,损失也只是一个下午。
本系列的展开
这篇是整个系列的判断线。如果四个问题里有答「是」的,后面的展开顺序是:第 02 到 05 篇打地基(reducer、checkpointer、记忆、函数式 API),第 06 到 11 篇讲控制(人审、子图、并行、多 agent、流式、高层封装),第 12 到 17 篇进生产(错误处理、checkpoint 运维、调试、评测、安全、部署),第 18 到 20 篇收尾(0.x 迁移、替代品对比、综合项目)。只想对比选型,可以直接跳第 19 篇。
延伸阅读
- LangGraph 官方文档:概念与 API 的权威来源,旧域名 langchain-ai.github.io 已停止更新
- LangChain 1.0 发布博客:分层变化的官方说明
- Octomind: Why we no longer use LangChain 与 Hacker News 讨论:弃用叙事与官方回应
- Grid Dynamics 迁移 Temporal 案例实录:checkpoint 与 durable execution 边界的一手素材
- Hacker News: Agent design is still hard:手写路线的复杂度反噬