Skip to main content

Claude Code 子智能体机制

前置02 Kimi CLI 里子 Agent 隔离上下文的那一节。

02 里那个场景 —— 让子 Agent 去查资料、只把结论带回来 —— 隔离是纯赚的:主 Agent 的上下文没被十几页搜索结果撑爆,结论照样拿到了。

换一个任务,同样的做法就会翻车:「把用户模块、订单模块、通知模块这三块的错误处理统一成新的 AppError 体系。」三个子 Agent 各改一块,互相看不见对方,最后你会拿到三套长得不一样的 AppError。

差别在哪?这一篇讲的就是这条线。材料基本全是官方的。

一、材料清单

本篇材料基本全为官方:

材料可信度说明
Anthropic《How we built our multi-agent research system》✅ 官方一手唯一公开了 token 成本量化数据的
Claude Code 子智能体官方文档✅ 官方一手配置项极其完整
anthropics/claude-agent-sdk-python 7,928★✅ 官方开源2026-08-18 仍在更新
anthropics/claude-agent-sdk-typescript 1,705★✅ 官方开源同上
VILA-Lab/Dive-into-Claude-Code 2,062★⚠️ 社区分析2026-08-16 更新,还活着
Yuyz0112/claude-code-reverse 2,428★⚠️ 社区逆向最后 push 2025-08-26,停更一年,结论对应很老的版本

关于逆向仓库:对 cli.js 做反混淆的那批仓库大多停更或被转手(memaxo/claude_code_re 现在跳到一个 4 star 的账号)。好在官方文档和 SDK 的信息量已经远超逆向能挖到的,本文以官方材料为主,逆向仓库只当历史版本参考。

二、隔离的反面:共享决策冲突

回想 02 里那个场景:让子 Agent 去查资料,只把结论带回来。那个场景里隔离是纯收益。

现在换一个:

「把用户模块、订单模块、通知模块这三块的错误处理统一成新的 AppError 体系。」

很自然地拆成三个子 Agent,一人一个模块,并行干。结果:

问题出在哪?

不是子 Agent 笨。是 「AppError 长什么样」这个决策,没人显式写进任务描述里。三个子 Agent 各自补全了这个空白,补得不一样。

Cognition(Devin 背后的公司)在《Don't Build Multi-Agents》里把这个总结成一条原则:

Actions carry implicit decisions, and conflicting decisions carry bad results.

动作里携带着隐式决策,互相冲突的决策产出垃圾结果。

他们举的例子更直观:让两个子 Agent 一起做 Flappy Bird 克隆,一个做背景一个做小鸟。结果背景做成了超级马里奥风格,小鸟长得也不像 Flappy Bird——两个都「完成了任务」,但拼不到一起

2.1 关键在于:这跟 02 那个场景差在哪

02 的查资料任务本节的重构任务
子任务性质只读
子任务之间各查各的,互不影响都在改同一套接口约定
隐式决策几乎没有(事实就是事实)极多(字段设计、命名、粒度)
结果能否机械合并能,拼起来就行不能,要缝合
隔离是纯收益主要成本

这张表就是「什么时候该拆、什么时候不该拆」的判据。 08 那篇 会把它展开成完整的决策树。

三、先把 Claude Code 的子智能体机制认全

3.1 它长什么样

子智能体是一个 Markdown 文件 + YAML frontmatter

.claude/agents/code-reviewer.md
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: sonnet
---

You are a code reviewer. When invoked, analyze the code and provide
specific, actionable feedback on quality, security, and best practices.

四个部分:名字、什么时候该派给它、能用哪些工具、用哪个模型,正文是它的系统提示词。

对照 Kimi CLI 的 YAML 工种定义,结构几乎一样。 后面 07 那篇 会看到 OpenHands 和 DeerFlow 也是这个形状——四家独立实现收敛到了同一套 API,说明这个抽象已经定型了。想自己做一套,照着抄就行。

3.2 放在哪:五个位置,有优先级

位置作用域优先级典型用途
托管设置(managed settings)全组织1(最高)公司统一下发
--agents 命令行参数当前会话2一次性实验
.claude/agents/当前项目3提交进版本库,团队共享
~/.claude/agents/个人全局4自己的常用工具
插件的 agents/启用该插件处5(最低)通过插件分发

第 3 条值得注意:子智能体定义可以跟着代码一起提交。这意味着「这个项目该怎么审代码」变成了仓库的一部分,新人 clone 下来就有。Kimi CLI 的工种是内建在包里的,改不了。

3.3 启动时上下文里到底有什么

这一点官方文档写得非常明确,值得整理成一张图:

前四项跟 Manus 官方说的 "fresh context for every item"Kimi CLI 的独立 context 文件 是一致的——「子 Agent 必须拿全新上下文」这件事三家没有分歧。

分歧在第五项:兄弟 Agent 名册。 这是本专题里独一份,第五节展开。

四、隔离强度的可调档位

隔离强度是连续可调的,不是开关隔离更严隔离更松4.1 工具白名单tools /disallowedTools4.2 权限模式permissionModeplan / acceptEdits …4.3 模型选择model: inherit成本杠杆4.4 受控嵌套默认 3 层到顶撤走 Agent 工具4.5 兄弟通信SendMessage本专题独一份4.6 fork继承完整历史隔离的反面前三档收紧「能做什么」,后三档松开「能看到什么 / 能不能再派」——两组正交,可任意组合4.7 isolation: worktree给子智能体独立 git 工作树。介于「同进程上下文隔离」与「一子 Agent 一虚拟机」之间的中间档,成本远低于起机器解决多子 Agent 并发改码互相冲突4.8 memory: user / project / local跨会话持久记忆。比 Kimi CLI 的 resume 更进一步:resume 复活的是某个实例,memory 让整个「工种」积累经验正交于隔离强度
Claude Code 不替你选架构,而是把星型、树形、带通信的图都做成可配置项——代价是需要自行判断该用哪档。三家禁止递归、仅此一家默认放开到 3 层,且带深度计数器与 Agent(type1, type2) 可派工种白名单。

4.1 工具白名单与黑名单

先看最基础的控制。四种写法,从松到紧:

① 只给白名单

tools: Read, Grep, Glob, Bash

只有这四个能用,其他全部拒绝。

② 从全集里剔除

disallowedTools: Write, Edit

继承所有工具,只去掉写文件的。

③ 按 MCP server 粒度控制

tools: Read, mcp__github, mcp__slack
disallowedTools: mcp__*

这一条对照 Kimi CLI 写死的 mcp_configs=[] 很有意思:Kimi 是一刀切禁止子 Agent 用任何 MCP(怕连接开销和工具描述撑爆上下文),Claude Code 是按子智能体粒度配

更灵活,但代价是配错了就会重现 Kimi 想避免的那些问题。这是个明确的权衡:Kimi 用「不给选择」换稳定,Claude Code 用「给你选择」换适用面。

④ 用钩子做条件判断

hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/validate-command.sh"

工具调用前跑一个脚本,脚本说不行就拦下来。这是唯一能做「动态判断」的一档——前三种都是静态的「能不能用这个工具」,这一种能判断「能不能用这个工具做这件具体的事」。

4.2 permissionMode 权限模式

permissionMode: plan

六个可选值:

含义
default危险操作逐个问用户
acceptEdits自动接受文件编辑,其他仍然问
auto自动化程度更高
dontAsk不问
bypassPermissions全部放行
plan只读探索模式

plan 这一档相当于 Kimi CLI 的 plan 工种——但实现层级不同:Kimi 是在工具列表里把写操作剥掉,Claude Code 是在权限层拦。

两者可以叠加使用,这正好呼应 02 里讲的那条经验「绝对不能做」的事,提示词和代码要各堵一遍。 这里是「工具白名单和权限模式各堵一遍」。

4.3 模型选择与解析优先级

model: sonnet          # 家族别名
model: claude-opus-5 # 完整型号
model: inherit # 跟主对话一样(默认)

生效优先级(先匹配的赢):

  1. CLAUDE_CODE_SUBAGENT_MODEL 环境变量
  2. 单次调用时传的 model 参数
  3. 子智能体定义里的 model
  4. 主对话的模型

为什么这是主要杠杆:探索类子 Agent 的调用次数往往是写代码的好几倍,但它干的活(搜索、阅读、汇总)对推理强度要求低得多。给它配小模型,成本能降一个量级。

Kimi CLI 的 default_model 字段 是同一个思路。

4.4 逃生舱一:受控嵌套(默认 3 层)

现在进入这篇的重点。Claude Code 允许子智能体再派子智能体

深度上限可配,默认为主对话之下 3 层。到达上限时 Agent 工具会被撤走。用 CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH 控制。

对比一下三家:

注意失效方式的差别

  • Kimi 是「调了之后返回错误」——模型会浪费一次调用去撞墙,然后从错误消息里学到不能这么干
  • Claude Code 是「到了深度就把工具从列表里撤掉」——模型压根看不到这个工具,不会尝试

后者对模型更友好,但它跟 Manus 的「遮蔽而非删除」原则是冲突的:动态改工具列表会让 KV-cache 前缀失效。

这个冲突是真实存在的取舍,没有免费的解法。可能的调和方式是:深度变化发生在子 Agent 创建时(新上下文本来就要重新算),而不是在一个正在运行的上下文中途改。

还有一个 Kimi 没有的控制粒度

tools: Agent(worker, researcher), Read, Bash

Agent(类型1, 类型2) 可以限定这个子智能体只能派哪几个工种。 不是「能不能派」的开关,是「能派谁」的白名单。

有了这个,就能画出受控的流水线——比如 lead 只能派 researcherresearcher 只能派 fetcher,天然形成层级,不会横向乱长。

4.5 逃生舱二:SendMessage 兄弟通信

这是本专题里独一份的设计。回顾一下前面:

子 Agent 之间能通信吗
Manus❌ 官方原话 "Sub-agents never talk to each other."
Anthropic 研究系统❌ 官方说子 Agent 互相不知道对方存在
Kimi CLI❌ 代码里没有任何通信机制
DeerFlow❌ 星型
Claude CodeSendMessage + 兄弟 Agent 名册
同样三个子 Agent,差别只在有没有那两条虚线① 星型 —— 前四家都是这个主 Agent子 Agent 1子 Agent 2子 Agent 3子 Agent 之间零通信,所有信息经主 Agent 中转信息流是一棵树,出问题能沿树回溯② 带横向通道 —— Claude Code主 Agent子 Agent 1子 Agent 2子 Agent 3子 Agent 拿到兄弟名册,可以直接 SendMessage信息流从树变成图,调试难度上一个台阶代价很具体:星型下出了问题你能沿着树往上回溯,开了横向通道就只能在图里找路径。所以这个能力应该按需打开,不是默认开着。
原来这两种拓扑画成上下堆叠的两个 Mermaid 子图,262×1205 —— 而它们本来就是并排比较的关系,竖着堆恰恰把「差别只在那两条虚线」这一点藏起来了。摆成左右对照之后 980×262,虚线一眼就看得见。

回到第一节那个重构任务:三个子 Agent 各自定义 AppError 会打架。有了 SendMessage,A 定完接口可以直接告诉 B 和 C,不用绕回主 Agent。

但要清楚代价:一旦开了横向通道,你就失去了「星型」最大的好处——可预测性。星型结构下,信息流是一棵树,出问题时你能沿着树回溯。开了横向通道之后,信息流变成图,调试难度上一个台阶。

所以这个能力应该是「按需打开」,不是默认开着。

4.6 逃生舱三:fork 继承完整历史

前面所有讨论的前提都是「子 Agent 拿全新上下文」。fork 是这个前提的反面

fork 子智能体继承整个对话历史和系统提示词

什么时候需要:有些任务恰恰需要知道前面发生的一切,重新交代一遍的成本比继承还高。

提供 fork 这个逃生舱本身就说明了一件事:纯隔离模型在实践中不够用。 三个逃生舱(嵌套、SendMessage、fork)都是对「彻底隔离」这个理想模型打的补丁。

4.7 isolation: worktree

isolation: worktree

给子智能体一个独立的 git worktree。

这一档很巧妙,它正好卡在两个极端之间:

隔离粒度代表多个子 Agent 同时改代码会怎样成本
上下文窗口Kimi CLI改到同一个文件会互相覆盖几乎为零
git worktreeClaude Code各改各的副本,互不干扰一次 checkout
沙箱容器Suna完全独立百毫秒级启动
虚拟机Manus完全独立秒级 + 独立计费

回到第一节那个重构任务:三个子 Agent 各自在自己的 worktree 里改,物理上不可能覆盖对方的文件。合并的问题还在(接口约定冲突),但至少不会出现「A 写了一半被 B 覆盖」这种更低级的事故。

这是本专题里我认为性价比最高的一个隔离设计——花一次 checkout 的成本,买到了文件级的物理隔离。

4.8 memory 跨会话记忆

memory: project    # 可选 user / project / local

子智能体可以有跨会话的持久记忆。

这比 Kimi CLI 的 resume 又往前一步

  • resume 是复活一个具体实例(这个 a3f9c1d2 之前查过什么,接着问)
  • memory 是让这个工种积累经验(所有 code-reviewer 实例共享一份「这个项目容易出什么问题」)

五、成本:唯一公开了数字的一家

前面讲了这么多机制,绕不开一个问题:多 Agent 到底贵多少?

Anthropic 那篇博客是目前唯一公开量化数据的:

指标数值
普通 Agent 相比聊天的 token 消耗4 倍
多 Agent 相比聊天的 token 消耗15 倍
并行子 Agent 带来的研究耗时下降最多 90%
token 用量对评测效果方差的解释力80%

最后一条最值得琢磨:在他们的研究评测里,光「烧了多少 token」这一个变量,就解释了 80% 的效果差异。

把这句话摊开说:

多 Agent 效果好,很大程度上不是因为「协作涌现出了智能」,而是因为并行让你在可接受的时间内烧掉了 15 倍的 token。

这个认识很重要,因为它把判据变得非常朴素:

当任务的价值高到值得付 15 倍 token 时,多 Agent 才划算。

深度调研、竞品分析、大规模信息搜集——符合。日常问答、改个小 bug——不符合。

5.1 架构本身

Anthropic 多智能体研究系统架构

图片来源:Anthropic 官方博客 How we built our multi-agent research system。原文说明:用户查询流经一个 lead agent,由它创建专职子 Agent 并行检索不同侧面。

完整工作流(含记忆持久化与引用阶段):

多智能体研究系统完整流程

图片来源:同上。注意 LeadResearcher 的第一步是把计划写入 Memory 做持久化——因为上下文超过 20 万 token 会被截断,计划必须落在上下文之外。这与 Manus 的「文件系统即上下文」 是同一思路的不同实现。

官方强调的四条经验:

  1. 教会 orchestrator 怎么派活是重中之重。任务描述要足够自包含,否则子 Agent 会做重复劳动或集体漏掉某块。
  2. 子 Agent 互相不知道对方存在,也无法中途协调——这是并行的前提
  3. 评测用 LLM-as-judge 打分卡(准确性、引用、完整性),不规定它必须走哪条路径
  4. 「最后一公里往往占了旅程的大部分」——从 demo 到生产的可靠性工程量远超预期。

第 1 条值得展开,它跟第一节那个 AppError 的例子是同一件事:

在多 Agent 系统里,提示词工程的重心从「怎么让模型干好活」转移到了「怎么让模型把活分好」。

分活分不好,后面并行得再快也是白烧钱。

六、同一家公司,两个产品,两种架构

这是全篇最值得记住的一条观察:

Anthropic 的研究系统Anthropic 的 Claude Code
任务性质查资料,只读写代码,
子 Agent 之间互相不知道对方存在可以 SendMessage
嵌套默认 3 层
隔离彻底可调,还有 fork 逃生舱

这不是自相矛盾,这是最好的证据。

研究任务是一堆独立的只读检索,隔离带来的是纯收益——各查各的,最后拼起来。写代码任务有大量共享状态和隐式约定,隔离反而会制造第一节那种冲突。

架构由任务形态决定,不由技术信仰决定。

这条线是 08 那篇 的主线。

七、会在哪儿翻车:症状 → 原因 → 对策

症状原因对策
几个子 Agent 的产出合不到一起隐式决策冲突(接口、命名、粒度)先串行定接口再并行;或用 SendMessage 让它们对齐(Step 5)
子 Agent 改代码互相覆盖共享同一份工作区isolation: worktree,各改各的副本(Step 7)
账单失控多 Agent 约 15 倍 token,任务不值这个价先算任务价值,不值就用单 Agent(第五节)
子 Agent 做了重复劳动 / 集体漏掉某块主 Agent 派活的任务描述不自包含提示词重心放在「怎么分活」上(第五节)
子 Agent 加载慢 / 上下文一上来就很满MCP server 连接开销 + 工具描述tools: mcp__xxx 精确控制,别全给(Step 1)
子 Agent 无限套娃没设深度上限CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH,默认 3(Step 4)
层级乱长,不知道谁派了谁只控制了「能不能派」,没控制「能派谁」Agent(类型1, 类型2) 限定可派工种(Step 4)
出问题后无法回溯信息流开了 SendMessage,拓扑从树变成图默认关闭横向通道,确实需要才开(Step 5)
子 Agent 需要主对话的背景,重新交代成本很高用了普通子智能体改用 fork 模式(Step 6)

八、全局定位

01 的五个维度 打分:

维度Claude Code 的答案
D1 隔离单位独立上下文窗口;可选 isolation: worktree 升级到独立 git 工作树
D2 通信拓扑星型 + 可选横向 SendMessage,本专题唯一支持兄弟通信的
D3 结果回收只有最终结果回主对话,中间输出不上浮
D4 递归深度默认 3 层可配;到顶撤走 Agent 工具;Agent(...) 限定可派工种
D5 生命周期background 后台、memory 跨会话记忆、fork 继承历史

一句话总结:配置项最丰富、约束最松的一家。它不替你选架构,而是把星型、树形、带通信的图都做成可配置项——代价是你得自己想清楚要哪个。

8.1 三家放一起看

ManusKimi CLIClaude Code
隔离单位一台虚拟机一个 context.jsonl上下文窗口 / git worktree
递归未公开(推测单层)硬禁止默认 3 层
兄弟通信明确禁止无机制SendMessage
子 Agent 有角色无,都是完整实例三个内建工种用户自定义 + 三个内建
子 Agent 用 MCP——一刀切禁止按 Agent 精确配
跨会话记忆未公开实例可 resume工种可有 memory
定义放哪系统内建包内 YAML项目仓库里的 Markdown

能看出一条清晰的谱系:从 Manus(最刚性、最贵、隔离最彻底)→ Kimi CLI(中等刚性、单层、彻底隔离)→ Claude Code(最柔性、可递归、可通信)。

刚性换的是可预测性和成本可控,柔性换的是任务适应面。没有哪一端「更先进」——它们服务的任务分布不一样。

九、小结与自查清单

判断要不要拆

  • 子任务是只读的还是要写同一份东西?(写 → 慎拆)
  • 有多少隐式决策没法写进任务描述?(多 → 慎拆)
  • 结果能机械合并还是要人工缝合?(要缝合 → 慎拆)
  • 这个任务值不值 15 倍 token?

如果决定拆

  • 派活的任务描述自包含吗?把「怎么分活」的提示词写好了吗?
  • 子 Agent 之间要不要能通信?默认应该是不要
  • 多个子 Agent 会不会改同一份文件?会的话上 worktree 隔离
  • 递归深度限了吗?限的是「能不能派」还是「能派谁」?

成本

  • 探索类子 Agent 有没有绑更便宜的模型?
  • MCP 是全给还是按需给?

逃生舱

  • 有没有场景其实需要 fork(继承全部历史)而不是全新上下文?
  • 需不需要工种级的跨会话记忆?

十、参考