主流框架
框架到底解决了什么问题?答案不在框架的 README 里,而在你徒手写的那几十行 Loop 里。这篇把四个主流框架拆到 API 级别,看完你自己会做选型。
先破个题:你大概率不需要立刻学框架
打开任何一个 Agent 框架的文档,都会被几百个概念砸晕:Node、Edge、State、Handoff、Guardrail、Checkpoint……于是很多人得出一个结论:做 Agent 好难。
真相恰恰相反。Agent 的核心循环,几十行代码就能写完。 框架存在的意义不是"让 Agent 成为可能",而是帮你解决裸写之后会反复撞上的那批共性问题——状态持久化、人工介入、可观测性、权限控制、多 Agent 协作、流式 UI。所以这一章的学习路径是反直觉的:先徒手把 Loop 写出来,看清框架到底在替你做什么,再决定要不要用、用哪个。 顺序搞反了,你会把每个框架都学成一本背不完的说明书;顺序对了,每个框架都只是"我那几十行代码的某种扩展包"。
裸 Loop:几十行代码的 Agent
回忆上一章的 Agentic Loop:调用模型 → 解析 tool_call → 执行工具 → 结果回填 → 重复,直到模型说"做完了"。用 Anthropic 的 API 写,核心就这么点:
const messages = [{ role: "user", content: task }];
while (true) {
const res = await client.messages.create({ model, tools, messages });
messages.push({ role: "assistant", content: res.content });
if (res.stop_reason !== "tool_use") break; // 模型不再调工具,结束
const results = [];
for (const block of res.content) {
if (block.type === "tool_use") {
const output = await runTool(block.name, block.input); // 真的去执行
results.push({ type: "tool_result", tool_use_id: block.id, content: output });
}
}
messages.push({ role: "user", content: results }); // 结果塞回上下文
}
注意这段代码里的三个事实,它们是你理解一切框架的钥匙:
- 上下文就是一个数组。 所谓"记忆",此刻只是
messages.push。上下文压缩、会话恢复、记忆系统,全是对这个数组的管理策略。 - 模型从不执行工具。 它只输出"我想调这个"的意图,真正动手的是你的代码。权限、审批、沙箱,插在哪一层一目了然。
- 停止条件是你自己写的。 这里用
stop_reason,你完全可以加最大步数、token 预算、超时熔断。
加上工具定义、系统提示词和错误处理,一个能跑的真实 Agent 也就百行以内。建议你真的亲手写一遍——写完你会发现,框架文档里 80% 的术语突然都有了具体的所指。
亲手写的时候你大概率会撞三个小坑,先打个预防针:工具结果必须带上对应的 tool_use_id 回填,顺序乱了模型会懵;任何一步都可能抛异常(网络、超时、工具报错),不给 while 套上兜底,Loop 就变成了"要么成功要么消失";最大步数和 token 预算要从第一版就加上,别等账单教你。这三个坑,后面每个框架都用各自的方式替你处理了——到时候你可以对照着看。
框架在解决什么:Harness 层的共性问题
上一章说过,跑 Loop 的那层程序叫 Harness。裸写几轮之后,你会撞上这些问题,而且几乎每个项目都会撞上:
- 上下文管理:对话越来越长,什么时候压缩、怎么压缩、压缩丢了关键信息怎么办?
- 持久化与恢复:进程崩了、跑到一半要审批,状态存哪、怎么从断点续跑?
- 可观测性:几十步的工具调用,出了问题怎么回放、怎么归因到具体某一步?
- 权限与安全:哪些工具调用需要人确认?哪些目录不许碰?审批体验怎么做?
- 多 Agent 协作:子任务怎么分发,上下文怎么隔离,结果怎么汇总?
- 流式 UI:怎么把 Loop 的每一步(正在思考、正在调工具、工具返回了)实时推到前端?
框架 = 这些共性问题的一套现成答案。 不同框架的差异,本质是答案的风格不同:有的给你一整套装配好的 Harness(Claude Agent SDK),有的只给四块积木(OpenAI Agents SDK),有的给你一台编排引擎(LangGraph),有的干脆说"这些问题里只有 UI 那个值得我管"(Vercel AI SDK)。下面逐个拆到 API 级别。
Claude Agent SDK:把 Claude Code 的 Harness 直接给你
Anthropic 的思路很直白:Claude Code 是我们花大力气调出来的工业级 Harness,与其让你重造,不如直接开放。Claude Agent SDK(前身 Claude Code SDK)和 Claude Code 跑的是同一套 Loop:文件读写、Bash、搜索、网页抓取等内置工具,加上自动上下文压缩、会话恢复,全部开箱即用。
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash", "Grep"],
permission_mode="acceptEdits", # 改文件自动放行,跑命令前仍确认
agents={"tester": tester_agent}, # 注册一个子 Agent
)
async with ClaudeSDKClient(options=options) as client:
await client.query("修复 tests/ 里挂掉的用例,修完跑一遍测试")
async for msg in client.receive_response():
print(msg)
这套 SDK 真正值钱的是三件别人很难重造的东西:
- 权限模式(Permission Modes):四档旋钮。
default敏感操作逐个问;acceptEdits文件修改自动放行、命令仍确认;plan先只读探索并输出计划、批准后才动手;bypassPermissions全自动(只在 CI 或沙箱里用)。一套成熟的"人机权责划分"方案,直接拿走。 - Hooks:在工具执行前后插入你的逻辑——
PreToolUse可以拦下所有含rm -rf的 Bash 调用,PostToolUse可以给每次 Edit 自动跑一遍 lint。相当于在 Loop 内部开了质检工位。 - 子 Agent(Subagents):主 Agent 通过 Task 工具把子任务派给专项 Agent,子 Agent 拥有独立的上下文窗口,探索几十个文件后只把结论带回主上下文。这是对抗上下文膨胀最实用的机制之一。另外它原生支持 MCP,外部工具源即插即用。
还有两件"隐形"的工程值得点名:一是自动上下文压缩——对话逼近模型上下文上限时,Harness 会自动做摘要压缩,你几乎无感;二是会话恢复——每次会话有 ID,进程退出后可以 resume 接着聊。这两件事自己写都不难想到、很难写对。
- 设计哲学:模型和 Harness 协同优化——给模型"一台电脑"(文件系统 + Shell),比塞一堆精雕细琢的专用工具效果更好
- 适用场景:编码、运维、文件系统密集型 Agent;想快速拿到生产级 Loop 而不想自己调 Harness 细节
- 代价:深度绑定 Anthropic 生态,Loop 内部行为对你是半黑盒,想改 Loop 本身基本没门
OpenAI Agents SDK:极简抽象,只给四块积木
OpenAI 的 Agents SDK(Swarm 的正式化产物)走了另一个极端:抽象越少越好,Loop 你自己看得见。核心概念只有四个,但每个都有完整的 API 面:
- Agent:指令 + 工具 + 模型的打包。工具就是把普通 Python 函数装饰一下,签名和 docstring 自动变成工具协议。
- Handoff:多 Agent 的唯一模式。本质是注册一个
transfer_to_xxx工具,模型调用后,Runner 把后续对话连同完整历史移交给目标 Agent——像客服转接,新坐席能看到全部聊天记录。支持on_handoff回调和输入过滤。 - Guardrails:输入/输出上的校验闸口,和主流程并行执行,触发即中断:
from agents import Agent, Runner, input_guardrail, GuardrailFunctionOutput
@input_guardrail
async def no_pii(ctx, agent, message):
return GuardrailFunctionOutput(
output_info=None,
tripwire_triggered=contains_pii(message), # 触发就抛异常拦下
)
billing = Agent(name="账单专家", instructions="只处理账单问题", tools=[query_order])
triage = Agent(name="分诊", instructions="判断该转给谁",
handoffs=[billing], input_guardrails=[no_pii])
result = Runner.run_sync(triage, "帮我查下上个月的账单")
- Tracing:默认开启,每次运行记录完整 span 链(哪次模型调用、哪个工具、哪次交接、多少 token),可导出到 OpenAI 的 Traces 面板,也能
add_span_processor接到自己的观测系统。再加一个SQLiteSession,对话历史的存取也不用写了。
Runner 本身也有两种用法值得知道:Runner.run_sync 一把跑完拿结果,适合脚本;Runner.run_streamed 则把 Loop 的每个事件(token、工具调用、Handoff 发生)逐个吐出来,适合接自己的 UI。换句话说,它把"循环"暴露给你看,只是不强迫你管。
- 设计哲学:不发明新范式,框架只补上多 Agent 交接、护栏和追踪这三件裸写最烦的事
- 适用场景:对话式业务 Agent(客服分诊、助手路由这类 Handoff 天然契合的场景);想要轻依赖、低学习成本。模型不锁死 OpenAI,配 OpenAI 兼容端点或 LiteLLM 就能接别家
- 代价:复杂流程编排能力弱,Handoff 之外的多 Agent 模式(层级、辩论、并发)要自己做;Tracing 默认数据流向 OpenAI,在意合规要显式改配置
LangGraph:把 Agent 当状态机来编排
LangChain 团队发现:大家嘴上说"让模型自主",生产环境里真正想要的是对每一步的精细控制。LangGraph 的答案是把 Agent 画成一张图——节点是函数,边是转移条件,State 在节点间流动:
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command
def review(state: MessagesState):
decision = interrupt({"question": "允许执行这一步吗?"}) # 在这里暂停等人
return {"messages": [("assistant", "已批准,继续执行")]} if decision == "yes" else {}
graph = StateGraph(MessagesState)
graph.add_node("llm", call_model) # 节点:调模型
graph.add_node("review", review) # 节点:人工审批
graph.add_edge(START, "llm")
graph.add_edge("llm", "review")
graph.add_edge("review", END)
app = graph.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "demo-1"}}
app.invoke({"messages": [("user", "清理过期缓存")]}, config) # 跑到 interrupt 停住
app.invoke(Command(resume="yes"), config) # 人批准后从断点继续
几个值得记住的机制细节:
-
State 与 Reducer:State 是一个带合并规则的 TypedDict,比如消息字段挂
add_messagesreducer——节点返回新消息时是 append 而不是覆盖。节点只需返回"增量",图的运行时负责合并。 -
Checkpointer:编译时挂上 SqliteSaver / PostgresSaver,每执行完一步就把完整状态落盘,
thread_id标识一条会话。进程崩溃、服务重启,都能从最后一个快照续跑(durable execution)。 -
interrupt / Command(resume=...):人工介入不是"外挂一个审批系统",而是图的原生原语——暂停时状态完整保留,恢复时从精确的断点继续。
-
条件边(Conditional Edges):Loop 的"是否继续"不是写死的——路由函数读当前 State,决定下一步去工具节点、审批节点还是 END。模型自主性的大小,就调在这里。
-
时间旅行:
get_state_history能列出全部历史快照,从任意一个 checkpoint 分叉重放——调试 Agent 的"后悔药"。 -
多 Agent 在图里的表达很直白:supervisor 模式就是一个"调度节点"加若干"专家节点";图还能嵌套——一个节点本身就是另一张编译好的子图,复杂系统可以分层搭。
-
配套生态:LangSmith 做观测,LangGraph Platform 做部署。注意 LangGraph 不依赖 LangChain,直接用
@anthropic-ai/sdk写节点完全没问题。 -
设计哲学:自主性是要被精确配给的——哪里让模型自由发挥,哪里钉死流程,全由你画在图上
-
适用场景:长时运行、需要人工介入节点、对可控性和可恢复性要求高的复杂业务流(审批链、多阶段研究 Agent、客服工单流转)
-
代价:学习曲线最陡,概念税最重;简单场景用它纯属杀鸡用牛刀。你锁定的是框架范式本身——代码从此是"图"的形状
Vercel AI SDK:Agent 是个前端问题
Vercel 的视角又不一样:大多数 Agent 最终是个 Web 产品,难点在体验和交互。AI SDK 首先是一层统一 provider 抽象——换模型就是改一行字符串,OpenAI、Anthropic、Google 随切;然后是为 React 准备好的流式 UI 能力。至于 Agent,它不是神秘生物,就是一个带停止条件的工具循环:
import { streamText, tool, stepCountIs } from "ai";
import { z } from "zod";
const result = streamText({
model: "anthropic/claude-sonnet-4.5", // 换 provider 只改这一行
prompt: "查北京明天的天气并给穿衣建议",
tools: {
weather: tool({
description: "查询城市天气",
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => fetchWeather(city),
}),
},
stopWhen: stepCountIs(8), // 工具循环最多自主跑 8 步
});
for await (const part of result.fullStream) {
// text-delta / tool-call / tool-result……逐 part 实时推到 UI
}
机制上值得说清的三点:
- 工具循环是 SDK 自动跑的:模型返回 tool-call → SDK 调用你的
execute→ 结果回填 → 再调模型,直到满足stopWhen(可以是stepCountIs(n),也可以是自定义条件比如"出现了某个工具调用")。prepareStep还能让你在每一步临时改模型、改工具集。 - UI 是一等公民:前端的
useChat直接消费这条流,工具调用的中间状态("正在查天气…")和结果都能实时渲染,工具结果甚至可以渲染成 React 组件(Generative UI)。 - 边界划得很清:持久化、审批流、长任务恢复不在射程内——进程死了就死了,那些交给你的数据库和任务队列。这不是缺点,是明确的职责声明。
四件套里另外两个也顺手记一下:generateObject / streamObject 用 schema 约束模型输出结构化 JSON,做表单生成、数据抽取时比解析自由文本省心得多。统一 provider 这层还有个隐藏福利:同一份评测脚本换着模型跑,对比成本和质量的门槛几乎为零。
- 设计哲学:模型调用标准化,剩下的精力全砸在"把 AI 能力顺畅地流进 UI"
- 适用场景:TypeScript 技术栈、做对话式 / 生成式 UI 的 AI 应用;多模型快速切换对比
- 代价:不是为后台长任务设计的,复杂编排和 durable execution 要自己补或叠别的框架
四个框架怎么选:一张对比表
| 维度 | Claude Agent SDK | OpenAI Agents SDK | LangGraph | Vercel AI SDK |
|---|---|---|---|---|
| 语言 | Python / TypeScript | Python / TypeScript | Python / TypeScript | TypeScript 为主 |
| 核心抽象 | 现成的工业级 Harness | Agent + Handoff | 状态图(StateGraph) | 统一模型 API + 流式 UI |
| 持久化 | 会话可恢复(resume) | Session 记忆(SQLite 等) | Checkpointer,一等公民 | 不管,交给你的数据库 |
| 人工介入 | 权限模式 + Hooks | Guardrails 拦截 | interrupt / resume 原生 | 前端工具审批,自己组装 |
| 多 Agent | 子 Agent(独立上下文) | Handoff 交接 | 图上画多个 Agent 节点 | 需自行编排 |
| UI 集成 | 无(偏后端 / CLI) | 无 | 无(观测靠 LangSmith) | 一等公民(useChat 等) |
| 模型绑定 | 仅 Claude | 任意,OpenAI 体验最佳 | 任意 | 任意 |
一句话版:要现成的找 Claude,要轻的找 OpenAI,要控的找 LangGraph,要界面的找 Vercel。
也别把它们当成互斥选项——真实项目里组合很常见:Vercel AI SDK 管前端流式体验,LangGraph 在后端跑复杂编排,中间用你自己的 API 隔开。框架的职责边界越清晰,组合起来越不拧巴。
迁移成本与供应商锁定
选型时最容易被忽略的问题是:三年后想换掉它,要付出什么?
- Claude Agent SDK:锁定最深。 你买的本来就是"Harness 和 Claude 协同调优"这件事,工具集、权限模型、上下文压缩策略都是围绕 Claude 训出来的行为设计的。迁走约等于重造 Harness——所以只在"我就是要 Claude 系能力"的场景用。
- OpenAI Agents SDK:中等。 Handoff、Guardrails 都是可移植的概念,换框架时业务逻辑(工具和 instructions)能带走,Runner 和 Tracing 层要重写。注意 Tracing 数据默认进 OpenAI,这是个软性绑定。
- LangGraph:锁的不是厂商,是范式。 模型随便换,但你的代码已经长成"图"的形状,迁走等于把流程重新想一遍。不过反过来说,图的显式性也让迁移时有完整的文档可依。
- Vercel AI SDK:锁的是生态位。 它存在的意义就是消除模型锁定,但前提是你活在 TypeScript / React 世界里。
通用的对冲策略只有一条:把工具实现和 prompt 当成自己的资产来维护——它们与框架无关、可以随时带走;而 Loop 那一层,接受它"可替换"的事实,不要在框架的私有 API 上长太多业务逻辑。
争议:框架依赖 vs 裸写,谁对?
这个话题在社区里吵了好几年,两边的逻辑都值得听懂。
裸写派:Agent 产品的差异化就在 Harness——工具设计、上下文策略、停止条件,这些是核心竞争力,外包给框架等于把命脉交出去。而且框架的抽象必然泄漏:出了问题你要先看穿框架的魔法,才能看到自己的 bug。Anthropic 在《Building Effective Agents》里也明说:能用简单可组合的模式就别上框架。持这种观点的团队通常的演化路径是:从框架起步 → 被抽象反复绊倒 → 抽出自研的轻量 Loop → 迭代速度反而变快,因为每一行 Harness 代码都是自己人写的。
框架派:上面那个路径有个隐含前提——团队里有人写得出生产级 Harness。持久化、断点续跑、HITL、Tracing,每一件重造都是按月计的工作量,而且自己写的版本bug更多。如果 Agent 只是产品的一个功能(客服、内部工具),用框架等于两个人干六个人的活,把省下的时间花在真正差异化的业务逻辑上。持这种观点的团队的典型体验是:先上框架快速验证场景成立,等某天真撞到框架天花板了,再带着"已经想清楚的需求"迁移,此时迁移成本反而低。
我的判断是:这不是信仰问题,是定位问题——Harness 是你的产品,就裸写;Agent 是你的功能,就用框架。怕的是中间态:明明在做功能,却为面子重造 Harness。
框架 vs 裸写:判断标准
一张速查表,按从上到下的顺序问自己:
- 你是在学习吗? → 裸写。框架的抽象会挡住你对 Loop 的理解
- 单模型 + 三五个工具 + 单次会话? → 裸写。百行代码,框架只会增加间接层
- Harness 本身就是你的核心竞争力?(比如在做 Coding Agent 产品)→ 裸写或深度改造
- 需要持久化 / 人工审批 / 断点续跑? → 上框架,这些自己造又贵又容易错
- 需要多 Agent 交接或复杂编排? → 对话交接选 OpenAI Agents SDK,图状流程选 LangGraph
- 在做 Web AI 产品、看重流式体验? → Vercel AI SDK
- 就想快速拿到一个"像 Claude Code 那样能干"的 Agent? → Claude Agent SDK
还有一个通用的避雷问题:这个框架的核心抽象,你能用一句话向同事解释清楚吗? 如果不能,说明你还没搞懂它在替你做什么——这时候引入它,debug 时你会连问题出在你的代码还是框架的魔法里都分不清。
常见误区
- 没写过裸 Loop 就学框架:框架文档里的每个概念都对应裸写时的一个坑,没见过坑就看不懂答案
- 以为框架能弥补模型能力:框架只解决 Harness 层的问题,模型不行,换什么框架都白搭
- 为用框架而用框架:一个定时跑的摘要脚本套上 LangGraph,复杂度翻倍,收益为零
- 把对比表当排名表:四个框架解决的是不同问题,"哪个最强"是个错误的问题
- 被抽象绑架后失去透明度:用着用着不知道发给模型的 prompt 长什么样了——永远保留"能看到完整上下文"的逃生通道
术语表
| 名词 | 定义 | 一句话直觉 | 常见混淆 |
|---|---|---|---|
| Harness | 跑 Agentic Loop 的外层程序:组装上下文、调模型、执行工具、判断停止 | 模型是马,它是缰绳和车架 | 与"框架"混用:框架只是 Harness 的现成实现之一 |
| Agentic Loop | 观察-思考-行动-观察的自主循环,模型自己决定下一步 | 不是一问一答,是自己找活干 | 不等于多轮对话:多轮对话由人驱动,Loop 由模型驱动 |
| Handoff | 一个 Agent 把对话控制权连同历史移交给另一个 Agent | 客服转接:"转给账单组" | 不是子程序调用:交接后当前 Agent 就退场了 |
| Subagent | 主 Agent 派生的专项 Agent,拥有独立上下文窗口,干完回传结论 | 主厨把配菜交给小工,不占用主厨的台面 | 与 Handoff 混淆:Subagent 会回来交结果,Handoff 是彻底换人 |
| Guardrails | 输入/输出上的内容校验闸口,触发 tripwire 即中断执行 | 安检门,过了才放行 | 与权限模式混淆:Guardrails 查内容合不合规,权限模式管操作允不允许 |
| 权限模式 | Claude Agent SDK 控制工具执行需不需要人确认的档位 | 汽车驾驶模式:经济 / 运动 / 越野 | 与 Guardrails 混淆(见上),二者常搭配使用 |
| Hook | 在工具执行前后插入自定义逻辑的回调(PreToolUse / PostToolUse) | 流水线上的质检工位 | 类似 middleware,但作用点在 Agent Loop 内部 |
| Tracing | 记录一次运行完整执行轨迹:每次模型调用、工具执行、交接、token 消耗 | 飞机的黑匣子 | 不是 logging:Tracing 是结构化的因果链,可回放归因 |
| StateGraph | LangGraph 核心抽象:节点是函数、边是转移、状态按 reducer 合并流动 | 把 Agent 画成流程图,每个格子都能换 | 与 LangChain 混淆:LangChain 是组件库,LangGraph 是独立编排引擎,不依赖前者 |
| Checkpointer | LangGraph 的状态落盘组件,每步存快照,支持续跑与时间旅行 | 游戏存档,随时读档重来 | 不是缓存:它存的是可恢复的执行状态,不是结果 |
| interrupt | LangGraph 里主动暂停执行、等待人工输入的原语,配 Command(resume=...) 恢复 | 流程里的"审批节点" | 不是抛异常:暂停时状态完整保留,可精确续跑 |
| stopWhen | Vercel AI SDK 定义工具循环停止条件的参数 | Loop 的刹车片 | 与 maxTokens 混淆:前者管"跑几圈",后者管"一次说多少话" |
| MCP | Model Context Protocol,把工具和数据源标准化接入 Agent 的开放协议 | AI 工具界的 USB-C 接口 | 不是某个 SDK 的私有功能,跨厂商通用 |
参考材料
- Building Effective Agents — Anthropic:什么时候根本不需要 Agent 框架
- Building agents with the Claude Agent SDK — 这套 SDK 背后的 Harness 设计思路
- Claude Agent SDK 文档 — 权限模式、Hooks、子 Agent 的官方参考
- openai-agents-python — OpenAI Agents SDK 源码与文档,抽象少到可以直接读源码
- LangGraph 文档 — StateGraph、Checkpointer、interrupt 的官方指南
- Vercel AI SDK 文档 — streamText、stopWhen 与流式 UI 的设计
小结
先徒手写出几十行的裸 Loop,看清 Harness 层的共性问题,再去框架货架上按图索骥:要现成工业级 Harness 找 Claude Agent SDK,要轻量多 Agent 交接找 OpenAI Agents SDK,要精细编排和可恢复找 LangGraph,要做 Web 端 AI 体验找 Vercel AI SDK。选型时多问两句"迁移成本"和"这是不是我的核心竞争力"。框架是杠杆,不是拐杖——它放大你对 Loop 的理解,但替代不了它。