Skip to content

1. 子 Agent 的一生 ​

上一篇讲清了「为什么拆」与「拆开之后谁负责什么」。这一篇跟着一个子 Agent 走完它的一生,看每一步具体要做什么决定。

父级决定拆。 它先把一个任务切成几个子任务,判断哪一个适合交出去。判据在上一篇讲过——需要隔离上下文、需要收窄权限、需要独立归因。

组装任务描述。 父级写一段话交给子级。这段话是子级能看到的全部信息,写得好不好直接决定子级能不能做事。

创建子级。 选择一个运行环境:全新建一个会话,或者从父级历史分叉,或者交给另一个运行时。

子级读到什么。 它拿到任务描述,加上自己的系统提示与工具集。它看不到父级的思考过程(除非分叉),也看不到另外几个子级的进展。

执行与回报。 子级干活,完成后把结果交回。结果的形式取决于回报结构:一段自由文本,还是一个带状态、证据、未决项的结构化对象。

父级据以决策。 继续、重试、换一个子级、或者终止。

销毁。 子级会话结束。如果它有产物,产物要能被父级访问;如果它有结论,结论要已经在回报里。

这一生的每一站都对应一个设计问题。

站要回答的问题可选答案
创建子级子级如何创建全新建、从父级历史分叉、跨运行时远程
子级读到什么看多少父级历史零继承、继承摘要、继承完整前缀
子级能用什么工具集怎么给父级全量、按角色裁剪、按任务声明
执行与回报结果怎么回来自由文本、结构化对象、工具回报
父级决策同时能跑几个一个、固定上限、动态配额

五个问题是设计顺序,不是分类维度:前一个的答案会收窄后一个的可选范围。


2. 五问在四家身上的分布 ​

同一个问题,四家给了不同答案。差异不在谁做得更好,在于答案之间的约束让它们落在三条已经收敛的路线上。

接下来五节逐问展开:有哪些可选答案、四家各选了什么、这个选择的代价是什么。


3. 子级如何创建 ​

三种方式,差别在「新会话从哪里获得初始状态」。

全新建。 子级从零开始,只有调用方显式传入的任务描述。优点是干净,缺点是需要交代。

从父级历史分叉。 子级复制父级的上下文前缀。优点是省去交代,缺点是子级会继承父级的错误假设。

Claude Code 的 fork 语义值得细看。它的提示词里写了两条与常规理解相反的约束。

第一条,分叉时提示词应当写成指令,不写成情境复述。原话的意思是:子级已经继承了你的上下文,所以任务描述要说「做什么」,不必再说「现在是什么情况」。这条约束直接解决分叉的典型误用——把已经在上文里的背景再抄一遍,既浪费 Token,也容易与上文冲突。

第二条,不要抢答。发出分叉后,父级对结果一无所知,提示词明确禁止「捏造或预测分叉的结果」;如果用户在通知到达前追问,应当告诉用户还在跑。这条约束针对一个具体故障:父级按自己的预期编造子级的结论。

跨运行时。 子级是另一个 Agent 运行时。DeepSeek Harness 的委派后端覆盖这种形态:进程内新会话、进程内分叉、ACP 协议、Codex、Claude Code、SDK 六种。

跨运行时的代价是能力取交集。父级只能使用子级运行时支持的机制:如果对面不支持「中途发消息」,这条能力在跨运行时下就消失;如果对面把工具结果格式化成不同结构,回报解析就要写两套。

三种方式的选择取决于一件事:任务描述能否自包含。能,用全新建;不能但可以摘要,用分叉;父级本身就是另一个生态,用跨运行时。


4. 看多少父级历史 ​

这一问与第一问强耦合,但值得单独看,因为它决定了子级能不能判断「我读过什么」。

策略子级能看到直接后果
零继承只有任务描述任务必须自包含,否则返工
继承摘要一段压缩过的父级结论摘要遗漏处即为盲区
继承完整前缀父级全部上下文无法区分「我读过的」与「父级读过的」

第三行是分叉最难处理的一处。子级继承了父级的完整历史,因此它看到的所有工具结果都像是自己读的。当它需要判断「这个文件我改过没有」,只能从历史里推断,而历史里既有父级的动作也有它自己的。

对这个问题,Claude Code 的处理是把分叉定位成「继续同一件事」,不要求子级做归属判断:分叉的用途是多文件重构这类需要同一份历史的延续性工作,判断「谁做过」在这种场景里不重要。

反过来,探索型任务用零继承,子级看到的所有内容都确实是它自己读的,归属判断不存在歧义。

这一问的实用结论是:继承越多,子级的归属判断越难。因此需要归属判断的任务(例如「检查我有没有漏改」)应当用零继承加显式传参。


5. 能用什么工具 ​

权限收窄有三种粒度,各自的能力与盲区不同。

粒度表达能力盲区
按角色禁用工具「这个角色不能写文件」不能表达「只能写某些路径」
按任务声明「本任务允许写 src/」依赖调用方写对
按权限动作「能用 shell,shell 内写操作单独授权」依赖每个工具正确声明

Claude Code 用第一种。它的 Explore 在定义里禁用了编辑、写文件、Agent 工具与计划模式退出,只留只读检索类。这个粒度挡不住「读了不该读的文件」,但能挡住「改了不该改的代码」。

Codex 用协作模式限定,接近第一种但支持命名空间维度:tool_namespace 让工具按命名空间分组,disable_native_tools 可以整体关掉原生工具。

OpenCode 用第三种,粒度最细。每个叶子工具自己声明需要什么权限动作,检查时按声明匹配。代价是声明错了就等于没限制。

DeepSeek Harness 让后端配置工具集,进程内后端可继承父级并收窄,跨运行时后端的权限由对方决定。

三种粒度都有一个共同的上限:都做不到参数级白名单。没有一家能表达「只能对 src/ 下的路径调用写入」。这类限制靠沙箱或文件系统权限实现,不在工具层的职责内。

理解这一点很重要,因为它决定了权限分离能买到什么。买到的是「减少能力面」,买不到的是「精确控制数据范围」。


6. 把任务写成子级能用的形式 ​

五个问题里,最难做对的是「写任务描述」。它是零继承策略下唯一的输入,写不好,前面四个问题的答案都白费。

Claude Code 的提示词里有一整套写法要求,值得逐条看,因为每一条都对应一种具体的失败。

6.1 起点:假设对方什么都不知道 ​

「像一个刚走进房间的聪明同事那样交代任务——它没看过这段对话,不知道你试过什么,也不理解这件事为什么重要。」

这句话给出三条必写内容:要达成什么以及为什么、已经知道了什么或排除了什么、足够它自己做判断的背景。

第三条最重要。前两条是事实,第三条是判断依据。缺了第三条,子级只能按字面执行,遇到需要变通的地方就卡住或乱猜。

6.2 按任务类型给不同的东西 ​

这条规则很精确:查询类任务交出确切的命令,调查类任务交出问题本身。

理由是:查询类任务的步骤是确定的,交出命令能保证执行一致;调查类任务的前提可能本身就是错的,如果预先规定步骤,那套步骤会变成负担——子级会照着走,即使第一步就已经发现前提不成立。

这个区分解释了为什么「统一模板」在委托里行不通。同一个模板要么对调查类太具体,要么对查询类太含糊。

6.3 不要转交理解 ​

「不要写『根据你的发现去修这个缺陷』或『根据研究结果去实现它』。写能证明你自己理解了的提示词:包含文件路径、行号、具体要改什么。」

这条针对的是一种看起来省事、实际代价最高的写法。把「理解」转交出去,等于让子级从头建立判断,而它缺少父级已经积累的全部上下文。

一个对照:

text
弱:根据你查到的情况,修复登录失败的问题。
强:登录失败的原因是 src/auth/session.ts 第 42 行把过期时间写成了固定值,
    应当改为从配置读取(配置项在 config/session.ts 的 ttl 字段)。
    改这两处,不要动 refreshToken 的逻辑。

强版本传递的是判断,任务本身只是一句话。它把「改哪里」「为什么改」「不要动什么」都写清了,子级不需要重新推导。

6.4 需要短回答就明说 ​

「如果你需要简短回答,说出来(例如『200 词以内汇报』)。」

这条对应回报结构的体量问题。不说,子级会按自己的判断决定详细程度;说了,体量可控。

6.5 分叉的三条额外约束 ​

分叉继承父级历史,所以写法不同,而且多了三条与常规直觉相反的约束。

写成指令,不写情境复述。 子级已经有上下文,任务描述要说做什么,不必再说现在是什么情况。把上文背景再抄一遍的代价是浪费 Token,而且容易与上文冲突。

不要偷看。 工具结果里有一个输出文件路径,提示词明确禁止去读或 tail 它,除非用户明确要求查看进度。「你会收到完成通知,相信它。」

这条针对的是一种具体行为:父级因为不确定进度,反复去读输出文件。代价是额外的读取调用,而且读到的通常是半成品。

不要抢答。 「发出之后你对分叉查到的东西一无所知。绝不要捏造或预测分叉的结果。如果用户在通知到达前追问,告诉用户还在跑。」

这条针对的故障是父级按自己的预期编造结论。它的危害比等待更大——用户会以为已经有结果了。


7. 结果怎么回来 ​

回报结构的差异看起来是格式问题,实际决定了主上下文体积的增长曲线。

自由文本。 子级自己组织最终消息。灵活,但体积不可控:同一个子级两次运行,可能一次给结论加来源,一次只给结论。

结构化对象。 约定字段(状态、结论、证据、未决项)。可校验,但要求子级按 schema 输出。

工具回报。 子级通过工具把结果写回,父级按需读取。信息量最大,但要求有回报通道。

体量差异可以估。设子级自由返回约 2,000 字,父级要读全部;结构化汇报的「结论、证据、未决问题」三段各 200 字,父级只读 600 字。三次子任务就差 4 KB 以上上下文。

这个差距在单次任务里不明显,在长任务里会累积成窗口压力与缓存失效。

Claude Code 的回报偏自由文本,靠提示词约束(例如要求探索子代理返回绝对路径),不强制 schema。Codex 是消息加等待,父级用 wait 取回一条消息。OpenCode 返回任务输出。DeepSeek Harness 用工具回报,另有控制类工具用于中止与列举。


8. 同时能跑几个 ​

并发上限不只是资源限制,它定义了协作形态。

单调阻塞。 父级发出委派后本轮等待,并行只能靠「一次消息里发多个调用」。Claude Code 属于这一类:并行三个探索,必须在同一轮同时发出三个 Agent 调用,分三轮发就串行了。

固定上限加超时。 Codex 的配置给出三个数:默认并发上限 4 个线程,等待超时默认 30 秒,可配范围 10 秒到 1 小时。这三个数共同定义了一种形态——同时最多四个子级在跑,每次等待最多半小时,等待超时不算失败只是「还没好」。

独立任务。 OpenCode 把子代理作为独立任务管理,可列举、可等待,并发受提供方速率限制约束。

三个数(4、30 秒、1 小时)值得记,因为它们体现了非阻塞的代价:父级要自己维护「哪个子级对应哪个任务」的映射,而这个映射需要超时来兜底——超时太短会误判,太长会失去非阻塞的意义。


9. 答案之间的约束联动 ​

五个问题不能自由组合。几条明确的约束。

继承前缀 → 无法判断自己读过什么。 分叉的子级看到父级的工具结果,也看到自己的,两者在上下文里没有区分标记。因此需要归属判断的任务不能用分叉。

全新建 → 任务必须自包含。 零继承的子级没有父级上下文,任务描述写不全就会返工。这条约束把压力转移到了派发方:它必须在派发前想清「要传什么」。

工具收窄 → 需要按角色定义工具集。 按角色禁用工具要求每个角色有一份显式清单,加一个角色就多一份配置。

结构化回报 → 需要 schema 与校验。 约定字段之后,父级要能处理字段缺失与格式错误,这增加了父级的复杂度。

并发上限 → 需要任务映射与超时。 大于一个子级就要维护映射,有映射就要有超时与清理。

这些约束不是设计缺陷,是它们共同把设计空间收敛到了三条已经成熟的路线。

9.1 约束的传递方向 ​

约束不是对称的。有的约束是单向的,有的是双向的。

约束方向说明
继承前缀 → 无法判断归属单向反过来不成立:不继承也可以有归属问题(见下)
全新建 → 任务必须自包含单向分叉不要求自包含
工具收窄 → 需要角色清单单向全量授权不需要清单
结构回报 → 需要 schema单向自由文本不需要
并发上限 → 需要任务映射双向有映射也常催生并发需求

第一行值得展开。零继承也会有归属问题,只是形式不同:零继承的子级不知道自己读过什么,因为它从零开始,什么都没读。它的归属问题是「我不知道父级读过什么」,而分叉的归属问题是「我分不清哪些是我读的」。

两种归属问题都要求「需要归属判断的任务要用显式传参」这一条。区别在于传的内容:零继承传「父级已知的结论」,分叉传「哪些结论是父级的」。

第五行是唯一双向的。这个双向性解释了一个常见的架构演变:先做单 Agent,因为要并行加了并发,因为并发加了任务映射,因为映射需要状态又拆出了任务对象。

9.2 约束推导出的设计路径 ​

把五问的答案与约束串起来,能复现一条真实的设计路径。

起点:任务需要并行处理三个独立的探索方向。 第一问:全新建(探索不需要父级历史)。 第二问:零继承(同上)。 第三问:只读工具(探索不改东西)。 第四问:结构化回报(父级要汇总三份结果)。 第五问:并发三个。

约束联动:并发三个 → 需要任务映射与超时;结构化回报 → 需要 schema 与字段校验;只读工具 → 需要一份只读清单。

这条路径的每一步都是被前一步推出来的,没有一步是「觉得这样更好」。这是五问作为设计顺序的价值——它把设计从「选型」变成了「推导」。

反过来,如果从「我要用多 Agent」开始,就会在五个问题上都倾向于选「功能更全」的答案:继承前缀、全量工具、自由回报、不限并发。这四个选择共同导致一个后果:成本高、难归因、并发时互相干扰。


10. 三条收敛路线 ​

按任务特性组合,四家的实现分成三条路线。

探索型。 全新建、零继承、只读工具、小模型、并行多开、只回结论。

Claude Code 的 Explore 是典型:禁用编辑工具、不加载项目规则、外部用户用小模型、要求并行发起搜索。设计目标是速度——提示词里写「你是一个快速返回结果的代理」。

不加载项目规则这一条值得单独说:探索只需要理解代码,不需要理解「提交前要跑 lint」这类与执行相关的约定。把项目规则塞进探索上下文会浪费时间在无关规则上。

执行型。 全新建或不继承、可写工具、独占资源、串行或少开、结构化回报。

Claude Code 的 GeneralPurpose、Codex 的 spawn 加协作模式、OpenCode 的执行类子代理都属于这一类。设计目标是不出错,因为子级会真正改动东西。

复核型。 继承前缀、只读、独立结论、不参与执行、一般单开。

Claude Code 的 Verification 是典型,它的价值来自「独立」:不复用执行者的自检结论,自己重新核对。继承前缀让复核者能看到执行者的权衡过程,只读让它无法「帮忙改一下」从而破坏独立性。

三条路线的存在说明:五问的答案组合虽然理论上很多,实践中收敛到了少数几个稳定配置。新做一个多 Agent 系统时,先判断自己落在哪条路线上,比从头讨论五问更省时间。


11. 六项横向对照 ​

把五问加上「隔离粒度」,构成六项对照。

维度Claude CodeCodexOpenCodeDeepSeek Harness
创建方式角色化子代理 + 进程内分叉任务式派生配置化子代理类型注册表化委派后端
隔离粒度会话会话 + 协作模式会话按后端:会话或进程
上下文继承全新或全前缀默认全新按类型定义按后端:全新或已完成历史
权限收窄按角色禁用工具按协作模式与命名空间权限动作声明按后端配置
回报结构自由文本消息 + 等待任务输出工具回报
并发与配额单调阻塞,一次多调4 线程上限,30 秒默认等待任务管理按后端

两处细节需要单独指出。

DeepSeek Harness 的分叉只取已完成历史。 不包含当前进行中的回合。理由是让子级看到一个自洽的过去——如果包含正在进行的回合,子级会看到「父级刚说了一半」的状态,难以判断哪些已经确定。

Codex 的配额兜底逻辑。 当配置了 agents.max_concurrent_threads_per_session 时,实际值是配置值加一,多出的一个留给根代理本身。这个细节说明配额计的是「线程总数」,子级数比它少一个。


12. 跨运行时的额外代价 ​

跨运行时委派是第六条路线,只有 DeepSeek Harness 覆盖。代价集中在三处。

能力取交集。 父级只能用对面支持的机制。对面不支持中途发消息,就没有中途干预;对面没有列举接口,父级就不知道还有谁在跑。

回报格式转换。 每个运行时的结果结构不同,父级要写适配层。适配层的错误表现为「结果丢了某个字段」,而且很难定位。

权限范围不透明。 父级无法确知对面给了子级什么权限。它能做的只是「拒绝挂载权限过宽的后端」,这是一个粗粒度的控制。

这三处代价换来的能力是复用已有运行时的强项:让 Claude Code 做需要长上下文的代码理解,让 Codex 做需要严格沙箱的执行,父级只做编排。


13. 并发槽位与人机争用 ​

一个容易被忽略的设计点:并发配额怎么在「Agent 之间」和「Agent 与人的请求之间」分配。

多数系统把并发做成一个池子,先到先得。这带来一个具体问题:当所有槽位被自动任务占满时,人的请求要排队。对一个交互式工具,这直接表现为「我打字没反应」。

有系统显式解决了这一点:并发上限之外留一个额外槽位,专供人的消息与状态查询使用,并且人的唤醒优先于新任务启动。这条规则的效果是「新工作不能阻止人继续已有工作」。

这个设计的价值在于它把一个隐含假设写成了显式规则:自动化任务的紧急程度永远低于人的直接请求。没有这条规则,系统会在最需要人的时候把人挡在外面。


14. 五问的判断顺序 ​

实际做一个多 Agent 系统时,按这个顺序回答五问,能避免反复。

第一问,任务描述能否自包含。 能,走全新建;不能,判断缺的是「可查的」还是「不可查的」。可查的(代码、日志)交给子级自己查;不可查的(决策意图、判断标准)必须显式传。

第二问,子级需要判断归属吗。 需要(例如「检查有没有漏改」),走零继承;不需要,可以用分叉省去交代。

第三问,子级会改动东西吗。 会,按角色或任务收窄工具,并把回报结构化;不会,可以给全量工具但保持只读。

第四问,父级需要在中途干预吗。 需要,选非阻塞加消息通道;不需要,阻塞式更简单。

第五问,会有几个人同时用。 有并发需求,必须给人类请求留独立通道。

五问的答案组合完成后,再对照第 10 节的三条路线,看自己落在哪一条。落在某一条上说明配置是常见的,有现成经验可循;落在组合之外说明有特殊需求,应当先把特殊之处写清楚再动手。