普通subagent每次启动固定开销约436k token(包含完整上下文),fork模式则继承对话和缓存;作者测量了真实fan-out场景的数据。
如果曾经把工作委托给 Claude Code 的 subagent,然后查了一下用量,你大概和我有一样的反应:这么小的活儿,怎么费用这么高?
答案是:一个普通的 subagent 是从零开始的。它不知道你之前在做什么,所以整个提示前缀——system prompt、工具 schema、你的 CLAUDE.md,以及其他加载进来的内容——都会在这个 agent 身上重新发送。我在一个真实 fan-out 场景下测量过,固定开销大约是每个 agent 436,000 个 token,与实际交给 agent 的任务无关。
从 2.1.232 开始,有一种 subagent 不会这样做。更新日志里是这么写的:
Subagent forking is now on by default: a subagent_type: "fork" subagent inherits the full conversation and prompt cache, and non-teammate agent spawns in interactive sessions now run in the background by default
一行里变了两条默认行为。这篇文章讲的是第一个,以及一个容易造成误读的命令问题。
这个把我坑过,所以在往下写之前值得先把它们区分开。三个都存在于当前版本,做不同的事,出现在不同的时间点。
1. context: fork in skill frontmatter — 在 2.1.0 加入。
---
name: my-skill
description: "..."
context: fork
---
这让一个 skill 或 slash 命令运行在 fork 出来的 subagent 上下文中,而不是内联在你当前会话里。这是 skill 的属性,由写这个 skill 的人声明。
2. /fork — slash 命令。它的行为在 2.1.212 发生了变化:
/fork now copies your conversation into a new background session (its own row in claude agents) while you keep working; the in-session subagent it used to launch is now /subtask
所以 /fork 不再是一个 subagent 了。它是会话副本——一个独立的第二会话,从你当前所在的地方开始。如果你要的是旧的 in-session 行为,那已经移到了 /subtask。如果你是在 2.1.212 之前学的 /fork 并且之后没碰过,这个变化会让你困惑。
3. subagent_type: "fork" — 2.1.232 里变成默认的那个。
这是一种 subagent,按常规方式 spawn 的,但它继承你的会话,以及——对成本来说关键的部分——你的 prompt cache。
同一个词,三层含义:skill frontmatter、会话命令、subagent 类型。
这是我在另一篇关于 CLAUDE.md 和 subagent 的文章里写错的地方,也是那篇文章的一位评论者让我回去重新核实的原因。
继承 cache 不会减少 token 数量。那些 token 依然会发送给模型。变化的是它们按什么费率计费:cache 读取而不是新鲜输入。所以如果你在考虑 context window 压力,什么都没改善。如果你在考虑成本,那改善的就多了。
这和 2.1.229 的另一个变化是同一个思路,我最初把它归类为常规更新:
Improved workflow fan-outs to stagger same-prefix sibling agents so subsequent agents read the cached prompt prefix instead of re-paying it (CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS=0 disables)
把这两行放在一起看,轮廓就清晰了。当十个 agent 共享一个前缀且同时启动,没有任何一个能读到还没人写过的 cache,所以十个都要付全价。错开启动意味着第一个写 cache,其他九个读。Forking 则是把同样的技巧应用到父会话而不是兄弟 agent。
这意味着我 ~436k-per-agent 的数字最好理解为上限:这是一个冷的、未错开的、非 forked agent 的成本。在错开的 fan-out 下,或者用 forked subagent,token 数量不变,美元数字变了。如果你自己在测量这个,要把 cache 读取的 token 和新鲜输入的 token 分开看再下结论——一个单一的"总 token 数"会把你要观察的整个效果隐藏掉。
Forking 并不是严格更好。在几种常见场景下,继承会话恰恰是你不想要的:
独立审查。如果你想要对一个决定听听第二种意见,一个已经读过你推理过程的 agent 并不独立——它已经被你的结论说服了。只看到产物的冷 agent 才是对的。
上下文卫生。一个长的会话会积累死胡同、放弃的方案和过时的文件内容。Forking 把所有这些都带过去。一次狭窄的任务用干净的提示往往表现更好,不是更多上下文。
任何你不希望被重复的。fork 继承完整会话,包括碰巧在里面的所有东西。
我总结的规则是:agent 需要继续某件事时 fork,需要检查某件事时 spawn 冷的。
同一段更新日志还说 non-teammate agent spawns in interactive sessions now run in the background by default。后台执行本身不是新东西——subagent 从 2.1.198 起就默认后台了——但边界又移动了,而且会产生一个特定的困惑时刻:你委托了一个任务,立刻问"它找到了什么?",结果被告知还在运行。
那是 agent 在工作,不是失败。结果会在后续轮次以完成通知的形式到达。如果你想同步阻塞,CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 可以让一切变成同步的。
有两件事值得在自己的环境里确认,而不是相信博客文章,包括这一篇:
查看你安装版本的更新日志。运行 claude --version,然后查那个版本的条目。默认行为在 2.1.x 系列里移动过好几次,针对 2.1.180 写的建议不是针对 2.1.232 的建议。
在你的用量明细里看 cache-read 和 fresh input 的对比,而不是看总数。如果你的 fan-out 全都是按 fresh input 计费,那要么前缀实际上没有共享,要么 agent 全都在同时启动。
一个通用的教训,比这个特定版本更持久:在 Claude Code 里,"这多少钱"和"这消耗多少上下文"悄悄变成了不同的问题。一个改动可能改善了一个而让另一个原封不动。