Chapter 03 · 对比与选型
对比与选型 · 把状态图放回框架全景里
前两章讲了状态图与 checkpoint——把 state 当 reducer 代数、把 thread_id 当时间轴上的存档点。这章把它放回框架全景里做选型:先和同源的 LCEL 比,决定什么时候从声明式管道下沉到状态图;再和五个多智能体框架比,按「主导约束」而不是「谁功能全」来选。本章基于 LangGraph 1.x,写于 2026-06;框架生态是 2026 早期快照,会变,承重判断时自行复核。
本章你将建立的心智模型
- LCEL 与 LangGraph 是同源互补,不是二选一:线性无状态 DAG 留在 LCEL,出现回边 / state 分支 / 持久化 / HITL 就下沉状态图
- 多智能体框架的差异是「押注了不同的顶层控制模型」——图 / 会话 / 角色 / handoff / tool-use 链,差异不是优劣是错配
- 选型按主导约束定:控制力与持久化 → LangGraph、团队速度 → CrewAI、会话式研究 → AutoGen(AG2)、Anthropic 原生生产 → Claude Agent SDK
- 「哪个框架最强」是错问题;对的问题是「这个项目最硬的那条约束是什么,谁直接命中它」
3.1LangGraph vs LangChain LCEL · 何时下沉
LCEL 是线性无状态 DAG,写起来最轻;流程一旦出现回边、基于 state 的分支、跨步持久化或人工中断,表达力就触顶,下沉到 LangGraph。
LCEL(LangChain Expression Language)和 LangGraph 出自同一团队,很多人因此忽略它们的边界,把本该停在 LCEL 的线性管道直接写成状态图,换来一堆不必要的样板。LCEL 用 | 把 Runnable 串成一条有向无环图(DAG)——数据从左流到右,编译期就定死。它不能回到上游节点、不能按运行时的 state 选择走哪条边、不能在中途存档恢复。这三件事正是 01 章 §1.3 的条件边 / Send 和 §1.5 的 checkpointer 存在的理由。
关键不是「LangGraph 更强所以用它」,而是这条流程的形状。LCEL 的 DAG 形状对线性管道(prompt → model → parser、非循环 RAG 的 query → retrieve → rerank → generate)是精确匹配——没有多余结构。下沉的临界点只有一个判据:流程里是否出现「回到某个节点」或「让 LLM 自己决定下一步」。出现了,DAG 就表达不了,必须升级到带循环的状态图。
| 维度 | LangChain LCEL | LangGraph |
|---|---|---|
| 控制流 | 单向 DAG,| 顺接;编译期定死,无回边 |
有向图,允许回边与循环;条件边按运行时 state 路由 |
| 状态 | 数据顺着管道流过,无跨节点共享状态 | 显式 state + per-field reducer;并发写入按 reducer 合并(§2.2) |
| 持久化 | 无内置;崩溃即从头重跑 | 内置 checkpointer,按 super-step 存档,可跨进程恢复(§2.3) |
| HITL | 无;只能在管道外自己拦截 | node 内 interrupt() 任意位置暂停,审批人改 state 再 resume(§2.4) |
| 样板成本 | 最低——一行 a | b | c 就是一条链 |
较高——要定义 state、reducer、节点、边;只在前四维有真实需求时才划算 |
LangGraph 不取代 LCEL。一条 LCEL Runnable 可以直接当作 LangGraph 的一个节点实现——graph.add_node("retrieve", retriever_chain)。所以真实形态常是:外层用状态图提供循环 / 持久化 / HITL,节点内部仍用 LCEL 写那段线性管道。下沉的是「编排层」,不是「每一段逻辑」。
把一条 query → retrieve → rerank → generate 的非循环 RAG 写成 4-node StateGraph,只为「以后说不定要加分支」。代价是立刻多出 state 定义、reducer、编译步骤的样板,而循环 / 持久化 / HITL 一个都没用上。判据很硬:当前流程出现回边或动态决策了吗?没有就留在 LCEL。等真出现了再下沉——LCEL 节点能原样塞进状态图,迁移成本低,不必预先支付。
3.2vs 多智能体框架 · 按主导约束选
五个主流多智能体框架各押注了一种顶层控制模型——图 / 会话 / 角色 / handoff / tool-use 链;选型不是比谁功能全,是看你项目最硬的那条约束落在谁的强项上。
功能清单几乎总是 LangGraph 赢——它的控制力和持久化最强。但「控制力最强」不等于「对你最合适」:控制力是要用样板和心智成本换的(02 章反复出现的代价)。如果你的项目最硬的约束是「三天内让三个角色协作的原型跑给客户看」,CrewAI 的角色化抽象直接命中,LangGraph 的精细控制反而是负担。所以选型先问一句:这个项目最硬、最不能妥协的那条约束是什么? 然后看哪个框架的顶层模型是为它而生的。
下表把五个框架按「顶层控制模型 → 强项 → 适用场景」摆开。注意第一列——顶层模型才是它们真正的分水岭,其余差异多是它的下游后果。
| 框架 | 顶层控制模型 | 强项 | 主导约束命中谁 |
|---|---|---|---|
| LangGraph | 有状态图:节点 + 条件边 + reducer | 控制力最强;内置 checkpointer / interrupt / 动态 fan-out;LangSmith 可观测 | 控制力 + 持久化:长任务、回边、精细 HITL、跨进程恢复 |
| AutoGen / AG2 | 事件驱动会话:GroupChat,每轮由 manager 选发言者 | 涌现型协作;v0.4 / AG2 重构为 async-first 事件核(streaming / 多模型 / 依赖注入) | 会话式研究:多 agent 互相启发、对话探索 |
| CrewAI | 角色化 crew:role / goal + process(顺序 / 层级) | 上手最快、团队速度最高;几小时跑通多角色协作 | 团队速度:原型、概念验证、角色分工明确的小流程 |
| OpenAI Agents SDK | 显式 handoff:agent 调 transfer_to_X 交接控制权 |
primitive 精简(Agents / Tools / Handoffs / Guardrails);OpenAI 栈贴合 | 显式交接拓扑:OpenAI-only 栈、handoff 图清晰 |
| Claude Agent SDK | tool-use 链 + 子 agent:Claude Code 同源的 agent loop | Anthropic 原生生产运行时;MCP 集成最深;subagents / hooks / Skills | Anthropic 原生生产:吃 Claude + MCP 生态、要生产级 agent loop |
AutoGen / AG2 的 GroupChat 把「下一个谁发言」交给一个 manager LLM 决定——这买来了涌现型协作,代价是路由不可审计、不易重放:同样输入两次跑,发言顺序未必相同。LangGraph 的条件边是确定的代码函数,配合 checkpointer 能逐 super-step 重放。要做「研究式探索」选会话模型;要做「可审计、可恢复的生产流程」选图模型。这条分界比任何功能清单都更决定选型。
同源的(LCEL → LangGraph)迁移成本低,LCEL 节点能原样嵌入。跨顶层模型的迁移成本高:把「会话即路由」改写成「图 + 条件边」是换骨架,不是换 API。handoff(OpenAI SDK)能映射到 LangGraph 的条件边 / Command(goto),但持久化层要自己补——这些框架普遍无内置 checkpointer,长时 HITL / 跨进程恢复要自建,而这正是 LangGraph 替你做完的事。
一个团队在 CrewAI 上做出了 3-role 协作 crew 原型,跑得不错。现在要上生产,新增两条硬需求:(a) 单次任务跑几十分钟,进程滚动更新时不能从头重来;(b) 关键步骤要人工审批、审批人能改中间结果再继续。该不该迁到 LangGraph?用主导约束判断。
展开答案(先停 10 秒再点)
该迁,而且这两条需求正好踩在 CrewAI 的两个空缺上。
- (a) 跨进程持久化:CrewAI 没有内置 checkpointer,长任务崩了从 step 1 重跑。这正是 LangGraph checkpointer(§2.3)按 super-step 存档、跨进程 resume 解决的——主导约束「持久化」直接命中 LangGraph 的强项。
- (b) 可编辑的 HITL:不是简单 yes/no,而是「看到中间结果 → 改 state → 继续」。这要 node 内任意位置暂停 + resume 时注入修改,正是
interrupt()协议(§2.4)与 §2.6 三件事合作的场景。
迁移路径:不必全推倒。常见做法是把现有 CrewAI crew 整体塞进 LangGraph 的一个节点,让状态图只负责提供持久化 + HITL 的外层——角色协作逻辑保留,只在编排层下沉。这呼应 §3.1 的「下沉的是编排层,不是每段逻辑」。
3.3选型决策 · 一棵树走到底
从约束出发顺着问四个问题:能写死流程吗 → 要状态 / 回边 / HITL 吗 → 要团队速度还是会话探索 → 落到具体框架。
把前两节收成一棵决策树。读法是从顶端「开始选型」往下,每个菱形回答一次,落到矩形终点。注意大多数路径并不通向 LangGraph——这是有意的:选型从「主导约束」出发,不从「哪个框架最火」出发。
GitHub star 是「打算看看」的信号,不是「装进了生产 CI」的信号;功能最全的框架也未必匹配你的主导约束。决策树每个分支问的都是约束,不是人气。把「这个项目最不能妥协的那条需求是什么」想清楚,树会自己把你导到终点——这一步想不清,再多对比表也救不了选型。
§本章 self-check
先合上教程,把答案写在纸上或编辑器里,再展开对照。直接点开等于把这节当再读一遍。
- 判别题:给定流程
用户问题 → 检索文档 → 重排 → 生成答案,全程单向、不回头、不需要存档。该用 LCEL 还是 LangGraph?把判据说出来。 - LCEL 和 LangGraph 同源,为什么说它们「不是二选一」?举一个二者同时出现的真实形态。
- 判别题:AutoGen / AG2 的 GroupChat 和 LangGraph 的条件边,在「可审计 / 可重放」上为什么是两类东西?这对选型意味着什么?
- 一个纯 OpenAI 栈的团队要做多 agent 交接,handoff 拓扑清晰,但需要「人工等待几小时后再继续」。用主导约束分析:选 OpenAI Agents SDK 还是 LangGraph?
答案(先做完再展开)
- LCEL。判据只有一条:流程是否出现「回到某节点」或「让 LLM 自己决定下一步」。这条 RAG 管道单向、无回边、无动态决策、无持久化需求——是 DAG 的精确形状(§3.1)。写成 4-node StateGraph 只会多出 state / reducer / 编译的样板,循环 / HITL 一个都用不上,属于过早下沉。等真要加「答案不满意就回去换 query 重检索」这种回边时,再把 LCEL 节点原样塞进状态图即可,迁移成本低。
- 因为 LangGraph 下沉的是编排层,不是每一段逻辑。一条 LCEL Runnable 能直接当作状态图的一个节点(
graph.add_node("retrieve", retriever_chain))。真实形态:外层用 LangGraph 提供循环 / 持久化 / HITL,节点内部仍用 LCEL 写线性段——二者嵌套,不是替代(§3.1 洞察)。 - GroupChat 把「下一个谁发言」交给一个 manager LLM 决定,同样输入两次跑发言顺序未必相同——路由不可审计、不易重放;条件边是确定的代码函数,配合 checkpointer 能逐 super-step 重放。对选型意味着:研究式探索、要 agent 互相启发,选会话模型(AutoGen / AG2);要可审计、可恢复的生产流程,选图模型(LangGraph)。这条分界比功能清单更决定选型(§3.2 洞察)。
- 主导约束是「几小时的人工等待」,倾向 LangGraph。handoff 拓扑清晰确实是 Agents SDK 的甜区,primitive 也更精简;但它无内置 checkpointer,「人工等待几小时后继续」要求跨进程持久化 + 可恢复的中断,这些得全部自建(自己写存储、设计 thread 寻址、实现中断协议)——而这正是 LangGraph 替你做完的事(§2.3 + §2.4)。当自建持久化的成本超过抽象成本,天平倒向 LangGraph。边缘情形:若等待只是几秒、几分钟且单进程内即可,则栈贴合的 Agents SDK 更轻——临界点在「等待时长 × 是否跨进程」。
给你的当前项目排一次选型
挑一个你正在做或最近做过的 LLM 应用,按本章方法走一遍:(a) 写出它最硬的主导约束是哪一条(控制力 / 持久化 / 团队速度 / 会话探索 / 栈锁定,只能选一条当「最不能妥协」的);(b) 沿图 3.2 的决策树走,落到哪个框架?(c) 你当前实际用的框架是什么?它在你的主导约束上是命中、过配(over-fit,用了用不上的控制力)还是欠配(under-fit,缺了你要的持久化 / HITL)?(d) 如果欠配,迁移成本是低(同源嵌套)还是高(换顶层模型)?
提示(卡住再展开)
难点在 (a):多数项目会想列出三四条约束都「重要」。强迫自己只留一条——问「如果只能满足一个需求,砍掉其余,留哪个项目就不算失败」。那一条才是主导约束,决策树是为它设计的。
(c) 的常见发现:很多项目「为什么用这个框架」的真实原因是团队历史或文档好读,不是主导约束。意识到这一点不丢人——但把它和主导约束分开写出来,你才看得清是不是该迁,以及迁移属于 §3.2 里的「同源低成本」还是「跨模型高成本」。