博客.
博客.
(联系方式)

保持联系

如果你想联系我,无论是讨论合作机会、分享想法,还是只是打个招呼,都可以通过以下方式找到我。

(最后更新)

版权所有 / 2026

(快捷键)C
返回学习路线
(02 · Agent 开发)2026年8月

主流框架

框架到底解决了什么问题?答案不在框架的 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 }); // 结果塞回上下文
}

裸 Loop 全景:调用模型后判断是否还要调工具,是则执行工具并把结果塞回 messages 数组重复循环,否则结束

注意这段代码里的三个事实,它们是你理解一切框架的钥匙:

  1. 上下文就是一个数组。 所谓"记忆",此刻只是 messages.push。上下文压缩、会话恢复、记忆系统,全是对这个数组的管理策略。
  2. 模型从不执行工具。 它只输出"我想调这个"的意图,真正动手的是你的代码。权限、审批、沙箱,插在哪一层一目了然。
  3. 停止条件是你自己写的。 这里用 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, "帮我查下上个月的账单")

Handoff 与 Guardrail:用户消息先过 no_pii 闸口(含 PII 触发即中断),分诊 Agent 再通过 Handoff 连同完整历史移交给账单专家

  • 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)                     # 人批准后从断点继续

LangGraph 状态图:START 经调用模型节点到 interrupt 人工审批节点再到 END,Checkpointer 每步把状态落盘,批准后 resume 从断点续跑

几个值得记住的机制细节:

  • State 与 Reducer:State 是一个带合并规则的 TypedDict,比如消息字段挂 add_messages reducer——节点返回新消息时是 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 SDKOpenAI Agents SDKLangGraphVercel AI SDK
语言Python / TypeScriptPython / TypeScriptPython / TypeScriptTypeScript 为主
核心抽象现成的工业级 HarnessAgent + Handoff状态图(StateGraph)统一模型 API + 流式 UI
持久化会话可恢复(resume)Session 记忆(SQLite 等)Checkpointer,一等公民不管,交给你的数据库
人工介入权限模式 + HooksGuardrails 拦截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 裸写:判断标准

一张速查表,按从上到下的顺序问自己:

  1. 你是在学习吗? → 裸写。框架的抽象会挡住你对 Loop 的理解
  2. 单模型 + 三五个工具 + 单次会话? → 裸写。百行代码,框架只会增加间接层
  3. Harness 本身就是你的核心竞争力?(比如在做 Coding Agent 产品)→ 裸写或深度改造
  4. 需要持久化 / 人工审批 / 断点续跑? → 上框架,这些自己造又贵又容易错
  5. 需要多 Agent 交接或复杂编排? → 对话交接选 OpenAI Agents SDK,图状流程选 LangGraph
  6. 在做 Web AI 产品、看重流式体验? → Vercel AI SDK
  7. 就想快速拿到一个"像 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 是结构化的因果链,可回放归因
StateGraphLangGraph 核心抽象:节点是函数、边是转移、状态按 reducer 合并流动把 Agent 画成流程图,每个格子都能换与 LangChain 混淆:LangChain 是组件库,LangGraph 是独立编排引擎,不依赖前者
CheckpointerLangGraph 的状态落盘组件,每步存快照,支持续跑与时间旅行游戏存档,随时读档重来不是缓存:它存的是可恢复的执行状态,不是结果
interruptLangGraph 里主动暂停执行、等待人工输入的原语,配 Command(resume=...) 恢复流程里的"审批节点"不是抛异常:暂停时状态完整保留,可精确续跑
stopWhenVercel AI SDK 定义工具循环停止条件的参数Loop 的刹车片与 maxTokens 混淆:前者管"跑几圈",后者管"一次说多少话"
MCPModel Context Protocol,把工具和数据源标准化接入 Agent 的开放协议AI 工具界的 USB-C 接口不是某个 SDK 的私有功能,跨厂商通用

参考材料


小结

先徒手写出几十行的裸 Loop,看清 Harness 层的共性问题,再去框架货架上按图索骥:要现成工业级 Harness 找 Claude Agent SDK,要轻量多 Agent 交接找 OpenAI Agents SDK,要精细编排和可恢复找 LangGraph,要做 Web 端 AI 体验找 Vercel AI SDK。选型时多问两句"迁移成本"和"这是不是我的核心竞争力"。框架是杠杆,不是拐杖——它放大你对 Loop 的理解,但替代不了它。