Claude Agent SDK 对比实现 — 谁拥有 loop,谁拥有 context
Claude Agent SDK 对比实现 — 谁拥有 loop,谁拥有 context
日期: 2026-08-12 阶段: Phase 2 - AI-native 参考架构 标签: #claude-agent-sdk #harness #compaction #framework-bench
核心问题
数据点#2:把对账异常调查 agent 用 Claude Agent SDK(@anthropic-ai/claude-agent-sdk,TS)重写一遍,同任务、同 golden、同 eval(Day 57 三固定)。表面又是「照文档抄」,但 Claude Agent SDK 与 AI SDK 6 是两种世界观的框架,对比时有一个会让成本数字直接不可比的陷阱:
- AI SDK 6:你拥有 loop——
generateText/ToolLoopAgent把控制权交给你,你数 step、你算 token、你管 context,框架不替你压缩历史。 - Claude Agent SDK:harness 拥有 loop——
query()跑的是驱动 Claude Code 的同一套 harness,它自动做 compaction、默认开 prompt caching,并直接吐出total_cost_usd和cache_read_input_tokens。
陷阱在最后一句:Claude Agent SDK 的成本已经含了 prompt-caching 折扣,而 AI SDK 6 我用本仓 estimateCost(不建模缓存)算出来的成本不含折扣。若直接把两个数字并排,等于拿「打折价」对比「原价」——Claude Agent SDK 会因为缓存看着更便宜,但这是口径差异不是框架优势。今天必须把这个口径对齐,否则数据点#2 会污染 Day 60 的整张 trade-off 矩阵。
关键内容
A. query() 的世界观:async-iterable 消息流 + harness 自治
Claude Agent SDK(2025-09 从 Claude Code SDK 改名)的核心是 query()(官方 TS reference):
function query({ prompt, options }: {
prompt: string | AsyncIterable<SDKUserMessage>;
options?: Options;
}): Query; // Query extends AsyncGenerator<SDKMessage, void>
它返回一个异步生成器,你 for await 它,harness 内部跑「模型→工具→结果→继续」的 agentic loop,把过程作为 SDKMessage 联合类型流式吐回(SDKAssistantMessage / SDKResultMessage / SDKCompactBoundaryMessage / …)。对账 agent 实现:
import { query, createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
import { z } from 'zod'
// 五个对账工具注册为「进程内 SDK MCP server」
const reconServer = createSdkMcpServer({
name: 'recon', version: '1.0.0',
tools: [
tool('fetchLedger', '取内部流水', { period: z.string() },
async ({ period }) => ({ content: [{ type: 'text', text: JSON.stringify(loadLedger(period)) }] }),
{ annotations: { readOnlyHint: true } }),
tool('finalReport', '提交异常清单', { breaks: z.array(breakSchema) },
async ({ breaks }) => ({ content: [{ type: 'text', text: validateAndEcho(breaks) }] })),
// fetchStatement / matchByAmountAndDate / classifyBreak 同理
],
})
const q = query({
prompt: caseToPrompt(amlCase),
options: {
model: 'claude-sonnet-4-6', // 基准锁定,同 AI SDK 6
systemPrompt: RECON_SYSTEM, // 共享字符串(注意 B 节 preset 坑)
mcpServers: { recon: reconServer }, // 工具走 MCP 注册
allowedTools: ['mcp__recon__fetchLedger', /* … */ 'mcp__recon__finalReport'],
maxTurns: 8, // 对齐 stopWhen=stepCountIs(8)
permissionMode: 'dontAsk', // bench 不需人审,禁止挂起
},
})
let result: SDKResultMessage | undefined
for await (const m of q) { if (m.type === 'result') result = m }
// result.total_cost_usd / result.usage / result.num_turns / result.modelUsage
与 AI SDK 6 的结构对比:AI SDK 6 工具是裸 Record<string, Tool> 直接喂 agent;Claude Agent SDK 工具必须包成进程内 MCP server(createSdkMcpServer),工具名带 mcp__<server>__<tool> 前缀,且要进 allowedTools 白名单才会自动执行。这个差异本身是个数据点:Claude Agent SDK 把「工具=MCP」当一等公民(为 W8 的 MCP server 复用埋伏笔),代价是更重的注册仪式。
B. systemPrompt 的 preset 陷阱:三固定可能被悄悄破坏
这是个隐蔽到能让整个对比失效的坑。Claude Agent SDK 的 systemPrompt 有两种形态:
systemPrompt?: string | {
type: 'preset'; preset: 'claude_code';
append?: string; excludeDynamicSections?: boolean;
}
若用 { type: 'preset', preset: 'claude_code', append: RECON_SYSTEM },harness 会把驱动 Claude Code 的完整系统提示(数千 token 的工具使用规范、文件操作纪律等)塞在你的 RECON_SYSTEM 前面。
反直觉洞察①(Claude Agent SDK 的「默认更聪明」恰恰会破坏三固定):Claude Agent SDK 卖点是「defaults that match production」——内置工具、自动 compaction、Claude Code 级系统提示开箱即用。但在框架横评里,这些「贴心默认」全是污染源:preset 系统提示让 Claude Agent SDK 比 AI SDK 6 多吃几千 token 的 input(成本虚高)又可能因为更强的工具纪律而质量虚高——你测的不再是「框架的 tool-loop 调度」,而是「Anthropic 的系统提示工程」。基准必须用纯字符串
systemPrompt: RECON_SYSTEM(不走 preset),并显式settingSources: []切断 user/project 配置注入,才能让两框架吃到逐字符相同的系统提示。三固定在这个框架上要主动「关掉聪明」。
同理 permissionMode 必须设 dontAsk(否则工具调用可能挂起等人审,污染 latency)、maxTurns: 8(对齐 stopWhen)。框架的默认越多,控制变量要关的开关越多。
C. 成本口径对齐:prompt caching 让两框架的「便宜」不可直接比
SDKResultMessage 直接给出成本与缓存明细:
total_cost_usd: number // harness 估算,含 prompt caching 折扣
usage: { input_tokens, output_tokens,
cache_creation_input_tokens?, cache_read_input_tokens? }
modelUsage: { [model]: ModelUsage } // 按模型拆分
num_turns: number // ≈ AI SDK 6 的 steps
关键差异——缓存命中的 token 走 cache_read_input_tokens,计费远低于全价 input(Anthropic 缓存读约为原价 1/10 量级)。两框架成本口径对照:
| 维度 | AI SDK 6 | Claude Agent SDK | 可比性问题 |
|---|---|---|---|
| 成本来源 | 我用 estimateCost(totalUsage) 算 | 框架直接给 total_cost_usd | 口径不同源 |
| prompt caching | 本仓 estimateCost 不建模缓存 | 默认开,total_cost_usd 已扣折扣 | Claude SDK 看着更便宜=缓存非框架优势 |
| input token | totalUsage.inputTokens(全价) | input_tokens + cache_read_input_tokens(拆分) | 直接比 input 数会错配 |
| 步数 | steps.length | num_turns | 语义近似但非严格相等 |
| 成本含义 | 「无缓存原价」 | 「有缓存折后价」 | 并排=原价 vs 折扣价 |
反直觉洞察②(框架对比里,自动 prompt caching 是「成本优势」还是「口径噪声」取决于你问什么):若问「生产部署谁更省钱」,Claude Agent SDK 的自动缓存是真实优势(同样的对账历史重复命中,省 input);若问「框架的 tool-loop 调度效率谁高」,缓存折扣是必须剥离的噪声(它来自 Anthropic 计费策略,不是 loop 调度)。本基准两个口径都要报:(1) 裸 token 口径——用两框架的原始
input_tokens/output_tokens(Claude SDK 把cache_read也按全价折算回去)喂同一个estimateCost,比「loop 调度产生多少 token」;(2) 实付口径——AI SDK 6 用estimateCost、Claude SDK 用total_cost_usd,比「真实部署账单」。两个口径分列,不混报——混报就是 Day 60 trade-off 矩阵的第一个雷。
D. 谁拥有 context:compaction 自治 vs 手动管理
最深的架构差异在 context 管理。Claude Agent SDK 在历史逼近上下文窗口时自动 compaction,并发 SDKCompactBoundaryMessage{ boundary_index, reason, tokens_saved } 信号;AI SDK 6 不替你压——历史全量回灌(Day 58 洞察①的二次增长在这里无人兜底,超窗就报 prompt_too_long)。
对 8 步的对账 agent,历史短,大概率不触发 compaction——但这恰恰暴露一个对比纪律:短任务上 compaction 不发力,会让 Claude Agent SDK 的 context 优势在本基准上「看不见」。这不是缺陷,是基准的边界:本基准(8 步、短历史)测不出 compaction 价值,要测它得换长任务(如 P3 的多步 AML 调查)。诚实地说:数据点#2 在 context 维度上对 Claude Agent SDK 不公平地保守——它最强的能力没被这个短任务触发。这条限定语必须进 Day 60 矩阵的脚注。
设计要点/决策表
| 要点 | 决策 | 理由 |
|---|---|---|
| 系统提示 | 纯字符串 RECON_SYSTEM,不走 preset | preset 注入 Claude Code 系统提示,破坏三固定 |
| 配置隔离 | settingSources: [] + permissionMode: 'dontAsk' | 切断 user/project 注入;防工具挂起污染 latency |
| 工具注册 | createSdkMcpServer + mcp__recon__* 白名单 | Claude SDK 把工具当 MCP;为 W8 MCP server 复用埋点 |
| 成本口径 | 裸 token + 实付双列,不混报 | 自动缓存是实付优势但 loop 口径噪声 |
| 步数对齐 | maxTurns: 8 ↔ stepCountIs(8) | num_turns 与 steps 语义对齐 |
| context 限定语 | 标注「短任务测不出 compaction」 | 数据点#2 对 Claude SDK context 维度保守 |
对本项目的落地
- 落地
bench/frameworks/claudeSdk/reconAgent.ts:按 A 节,query()+createSdkMcpServer包五个共享工具(从bench/reconciliation/tools.ts的 zod schema 适配为 Claude SDK 的tool()形态——schema 同源,仅 handler 包装层不同),for await收集SDKResultMessage。唯一框架特有代码是这层 MCP 包装 + query 装配;任务/golden/eval/system 仍 import 固定层。 bench/score.ts加成本口径归一化:新增normalizeCost(frameworkResult)—— AI SDK 6 分支用estimateCost(totalUsage);Claude SDK 分支产出两个值:裸口径((input_tokens + cache_read_input_tokens) → estimateCost折回全价)+ 实付口径(total_cost_usd)。矩阵两列分列。这是 D58 钉死 token 口径之后的第二层口径纪律。- MCP 复用伏笔:Claude Agent SDK 强制「工具=MCP」的形态,与 W8 计划的「把检索/AML 工具封装为 07-28 规范 MCP server」天然契合——本实现产出的
createSdkMcpServer工具定义可在 W8 复用为真实 MCP server 的工具层(src/agent/rag/hybridSearch.ts的检索工具同理可包)。记入 ADR 附注。 - 诚实标注:
reconAgent.ts头注明确「(1) 成本双口径,禁止与 AI SDK 6 单口径直接并排;(2) 本短任务测不出 Claude SDK 的 compaction/长上下文优势,context 维度对其保守;(3) preset 已关闭以保三固定」。数据点#2 数字执行当日回填,bench 不进阻断式 CI gate。
参考资料
- Claude Docs — Agent SDK reference: TypeScript(code.claude.com/docs/en/agent-sdk/typescript):
query({prompt, options})→Query (AsyncGenerator<SDKMessage>);Options(systemPromptpreset/string、mcpServers、agents、hooks、permissionMode、maxTurns、maxBudgetUsd、settingSources);tool()/createSdkMcpServer();SDKResultMessage(total_cost_usd、usage{input_tokens,output_tokens,cache_creation/read_input_tokens}、num_turns、modelUsage);SDKCompactBoundaryMessage{tokens_saved}自动 compaction 信号(2026,执行当周确认版本) - Claude Docs — Agent SDK overview(code.claude.com/docs/en/agent-sdk/overview):与 Claude Code 同一 agent loop/context management/permission/subagent;2025-09 自 Claude Code SDK 改名;
@anthropic-ai/claude-agent-sdk内置工具+sessions+MCP;2026-06-15 起订阅计划 Agent SDK 额度独立计费(2026) - DEV — Claude Agent SDK vs Vercel AI SDK 6 — which to pick in 2026:Anthropic SDK「opinionated/Claude-shaped/autonomy」,Vercel SDK「flexible/provider-neutral/interface」;Claude SDK 默认开 prompt caching + 自动 compaction(2026)
- Anthropic — Claude Sonnet 4.5 powers coding agents(vercel.com,与 Vercel 合作):Claude Agent SDK 用于自治长任务(2026)
- 本仓物证:
src/agent/orchestrator/orchestratorAgent.ts(AI SDK 函数式 loop 对照)、src/agent/shared/cost.ts(estimateCost不建模缓存——本笔记 C 节口径差异根因)、bench/frameworks/aiSdk6/reconAgent.ts(Day 58 数据点#1)、src/agent/rag/hybridSearch.ts(W8 MCP 工具复用对象)(2026-06)
SOTA 检查 (2026-08-12)
- Claude Agent SDK 是 Claude 优先自治 agent 的标准框架(2026-08 当前):
query()async-iterable 形态、自动 compaction、createSdkMcpServer进程内工具均为稳定 API;执行当周须npm view @anthropic-ai/claude-agent-sdk version确认版本(brief 口径 Py 0.2.95 / TS 0.3.170,2026-08 须重核),核对SDKResultMessage.total_cost_usd/cache_read_input_tokens字段名未变。 - 「harness 拥有 loop vs 你拥有 loop」是两框架最本质的架构分野(2026 业界共识,DEV/Medium 对比一致):Claude SDK = 自治/Claude-shaped/默认贴近生产;AI SDK 6 = 控制权在你/provider-neutral——这是 Day 60 trade-off 矩阵的主轴,非本项目独创观点。
- 成本口径必须区分裸 token 与实付:Claude SDK 默认 prompt caching 让
total_cost_usd含折扣,与 AI SDK 6 的estimateCost(无缓存建模)口径不同源——洞察②把它显式化为基准纪律,避免「折扣价 vs 原价」误读。 - 过时认知警示:(1) 不可用
preset: 'claude_code'做框架横评——注入数千 token 系统提示破坏三固定(洞察①);(2) 不可宣称「本基准证明 Claude SDK context 管理更优」——8 步短任务根本没触发 compaction(D 节限定语),其最强能力未被测试。 - 待跟踪:Day 60 汇总时,确认
num_turns(Claude SDK)与steps.length(AI SDK 6)在「调用 finalReport 即停」下是否数值一致(若 Claude SDK 把 result 消息也计入 turn,需 -1 归一);订阅计划 2026-06-15 起 Agent SDK 独立额度计费是否影响本项目的 API key 计量口径(本项目用 API key 非订阅,应不受影响,执行当日确认)。