1. 前言
在上一篇文章中,我们深入剖析了 Context Management 的设计——Agent 如何在有限的上下文窗口中管理记忆、压缩历史和治理信息。如果说 Agent Loop 是 Agent 的"心跳",Tool System 是 Agent 的"双手",Context Management 是 Agent 的"记忆系统",那么 SubAgent System(子Agent系统)就是 Agent 的"团队协作能力"——它决定了单个 Agent 能否将复杂任务拆解、委托给多个专职子 Agent 并行执行,再将结果汇合为一个整体产出。
这是 Agent 从"单兵作战"升级为"团队协作"的关键一跃。考虑一个真实的编程场景:用户说"帮我重构这个模块,把数据库层从 PostgreSQL 迁移到 MySQL,同时重写所有测试"。在传统单 Agent 模式下,主 Agent 需要先读 Schema、再改 ORM 代码、再迁移数据、再改写测试——每一步的结果都灌进同一个上下文窗口,很快上下文就会膨胀到填满。更糟的是,这些任务天然可并行(改 ORM 和写测试完全可以同时进行),但单 Agent 只能串行。
SubAgent System 解决了这个根本矛盾,在保持主会话可控的前提下,将独立子任务剥离到独立的执行上下文中,并行推进,结果按需回流。这个设计目标看似简单,但要在工程上做好,涉及一套完整的子系统设计:子 Agent 如何创建?父子之间共享什么、隔离什么?子 Agent 之间如何通信?结果如何汇合?worktree 隔离做到什么程度?
最近这一年来,SubAgent System 的研究已经从实验室走向了超大规模的生产实践。2026 年初,Anthropic 研究员 Nicholas Carlini 进行了一项轰动一时的实验1:用 16 个并行 Claude Agent、近 2,000 个 session、两周时间,从零写出一个 10 万行的 C 编译器。 这个编译器能通过 GCC torture test suite 99% 的测试用例,能成功编译 Linux 6.9 内核、QEMU、FFmpeg、SQLite、Postgres 和 Redis。API 费用约 $20,000。有点小贵,但对比一个资深工程师团队两周的人力成本,已经进入了"经济上可行"的区间。与此同时,Anthropic 工程团队也公开了他们在构建**长运行 Agent(Long-running Agent)**时的系统性实践经验2,提出了一套让 Agent 跨越多个上下文窗口持续工作的 Harness 设计。
这些实践表明,SubAgent System 早已不是理论架构,而是正在被实际部署、能够产出工业级软件的真实工程系统。本文将从四个主流开源项目的源码分析入手,同时融入这些前沿实践的洞察,从工程角度总结 SubAgent System 的设计原则和关键权衡。
2. SubAgent System 的本质
2.1 从"函数调用"到"多Agent Runtime"
子 Agent 实现简单示例如下:
function spawn_subagent(task):
child = new_agent(task, reduced_tools)
result = child.run()
return result
但真实场景需要回答的问题包括:
- 子 Agent 是同步阻塞还是异步后台运行?
- 父子 Agent 之间共享哪些上下文,隔离哪些状态?
- 子 Agent 的错误、取消、超时如何传导回主 Agent?
- 多个子 Agent 并行时,如何防止文件系统互相踩踏?
- 子 Agent 能否递归创建孙 Agent?如果能,递归深度怎么控制?
- 子 Agent 的结果是直接返回给用户,还是由主 Agent 二次整理后再呈现?
- 子 Agent 的工具集如何裁剪?哪些能力不该下放?
这些问题促生了 SubAgent System 从单次函数调用,演进为一套边界清晰的多 Agent 运行时。
2.2 SubAgent System 的通用抽象
无论具体实现如何差异,所有成熟的 SubAgent System 都共享同一套核心抽象:
flowchart TD
A[父Agent判断任务可委托] --> B[Spawn: 创建子Agent运行时]
B --> C[Delegate: 构造子Agent的prompt与toolset]
C --> D[Execute: 子Agent独立运行Agent Loop]
D --> E[Await: 等待子Agent完成或取消]
E --> F[Fan-in: 结果回流与汇合]
F --> G[主Agent消费结果并继续]
这套分层抽象让主 Agent 在保持对用户最终发言权的前提下,把可独立的子任务交给受控的、能力裁剪过的子 Agent 异步执行,结果通过内部协议回流。
其实这很像一个 Tech Lead 的工作方式:自己负责理解需求、设计方案、与客户(用户)沟通,但把具体模块的实现委托给不同工程师并行推进,最后自己把关、整合、向客户汇报。好的 SubAgent System 就是让 Agent 拥有这种"团队管理"能力。
这里有个关键点是,决定是否启动子 Agent 这一判断本身,不同的项目不约而同地采用了同一个策略:不靠硬编码调度规则,而是把判断权交给模型。 运行时只负责提供 spawn / Agent 这类 tool 的能力描述,模型在 tool-selection 阶段根据当前任务特征自行决定是否委托。任务的复杂度、并行机会、上下文污染风险,这些判断本身就依赖对任务语义的深层理解,硬编码的启发式规则远不如模型自己的判断准确,这需要时刻注意。
3. 主流项目的 SubAgent System 设计
3.1 Codex CLI3:共享控制面、隔离执行面
Codex CLI 的设计最接近"平台级多 Agent 运行时"。它的核心思想是:子 Agent 不是父 Agent 的一个并发函数,而是同一 session tree 中受控、可通信、可恢复的独立线程。
架构上分三层——控制面负责整棵 agent tree 的生命周期管理(spawn/resume/shutdown),注册层维护并发 slot 和嵌套深度配额,执行层创建独立线程。子 Agent 拿到的是全新的 Session 和 event queue,spawn 时从父 turn 派生配置、计算深度、注册 slot、启动后台 completion watcher 监听终态。
Codex 最突出的设计是 “共享控制面、隔离执行面”——认证、模型、技能、MCP 等基础设施共享以降低启动成本,但 Session、ContextManager、rollout 等执行状态严格隔离。Agent 间通信也设计得干净:V2 使用结构化消息直接投递为接收方的 prompt item,子 Agent 完成后父 Agent 在下个 turn 中自然消费。递归深度用 agent_max_depth 硬控制,默认值 1,只允许一级委托。
3.2 Claude Code4:双轨并存,统一内核
Claude Code 的 SubAgent System 是四个项目中最复杂的——它同时存在两套子 Agent 机制,但共用同一个 query() 执行引擎:
- Subagent:一次性委托 worker,复用主进程的 Agent Loop,通过 sidechain transcript 和 Task 实现可暂停、可恢复的生命周期。
- Teammate / Swarm Worker:持续存活的并行协作者,支持 in-process 和 pane/tmux 两种形态,通过 mailbox、task list、permission sync 实现 agent 间协作。
架构上分四层:Spawn/Routing 层决定走哪条路径(普通/fork/background/remote/teammate),Runtime 层为每个 agent 构建独立的 ToolUseContext,Task/Persistence 层管理 background task 和 resume 路径,Swarm Coordination 层提供 agent 间 IPC。
两个核心设计值得关注。一是上下文隔离采用 capability-based 模型——默认隔离几乎所有可变状态,只在显式打开 shareSetAppState 等少数 flag 时才共享,安全性比"全部共享再逐步限制"高得多。二是 Swarm mailbox 本质上是轻量 IPC 总线——不只传文本消息,还承载权限请求/响应、shutdown 协商、idle 通知等结构化协议消息,是四个项目中唯一把 agent 间通信当作"协议总线"设计的。
但也要指出,“两套系统并存"更像是需求不断叠加的结果而非一开始就规划好的。Subagent 和 Teammate 在 spawn 路径、通信协议、结果汇合上走不同的代码路径,增加了理解和维护成本。
3.3 pi5:进程级隔离,Extension 层实现
pi 的子 Agent 与其他项目有本质不同:它不是内核 built-in 能力,而是通过 extension 层以独立进程方式实现的 delegation。 父 Agent 调用 subagent tool → 发现 agent 配置 → spawn 新 pi 子进程 → 子进程按独立 prompt、toolset、模型运行 → 父进程消费 stdout JSON event stream → 收集结果回灌。
几个鲜明的设计决策:
进程级强隔离。 子进程 --no-session、独立 prompt、独立工具配置,天然不继承对话历史、session tree 和 compaction state。隔离最彻底,但 spawn 成本也最高。
父子协议是 JSON event stream。 没有自定义 socket 协议,直接复用 pi 的 stdout JSONL 流。父进程解析事件投影子 Agent 的内部状态,而非共享内存。
三种委派模式。 Single 单任务、Parallel 有界 fan-out(上限 8 任务,并发度 4,输出 50KB cap)、Chain 顺序 handoff({previous} 占位符替换上一步输出)。Chain 模式极简——协议只有 11 个字符的占位符,但 handoff 完全依赖 prompt discipline,脆弱性明显。
无自动 worktree 隔离。 只支持 cwd 注入,多个子 Agent 同目录并行写时可能冲突。这是 pi 最明显的能力缺口。
pi 的哲学是"把子 Agent 当作可流式观察的外部进程”,隔离性最强但启动成本最高,适合任务粒度较大的场景。
3.4 nanobot6:做减法的后台 Worker
nanobot 的设计是四个项目中最克制的。它只有一条路径:主 Agent 调 spawn → 登记后台协程 → 子 Agent 复用主执行内核但缩小 toolset + 缩短迭代上限 → 完成后通过 MessageBus 回流 system message → 主 AgentLoop 消费并二次改写后呈现用户。
三个"做减法"的决策:
子 Agent 绝对不对用户发言。 执行权下放,发言权保留在主 Agent。子 Agent 完成后只构造内部 system message 回流,由主 Agent 负责自然语言汇总。这从根本上杜绝了多 agent 输出顺序混乱和风格不统一的问题。
上下文采用"显式委托"而非"历史继承"。 子 Agent 的初始 prompt 极小——一段身份说明 + 一条 task 文本。主会话历史、channel metadata、长期记忆全部不继承。主 Agent 必须在 task 里把背景交代清楚——用"显式交代"换"上下文卫生"。
工具集激进裁剪。 只有基础读写和搜索能力,刻意排除 message(不发言)、spawn(不递归)、cron(不调度)、MCP tools(不继承外部工具)。子 Agent 被严格限定为"执行者",不是"第二个主 Agent"。
nanobot 的哲学是"用减法换可预测性"——它把容易失控的点全卡住了,但也因此不适合需要深层递归分解的复杂任务。
3.5 实践视角:Anthropic 的 Agent Teams 与长运行 Harness
Anthropic 工程团队在 2025-2026 年间公开的两项实践研究,则提供了从"效果"角度的验证。它们证明了一件事:SubAgent System 的工程质量,直接决定了 Agent 能否从"demo"升级为"工业级产品"。
3.5.1 C 编译器实验:16 个并行 Claude 的协作范式
2026 年 2 月,Anthropic 研究员 Nicholas Carlini 发表了"Building a C compiler with a team of parallel Claudes"1 一文,详细记录了他如何让 16 个 Claude Agent 并行协作,从零写出一个 10 万行的 Rust C 编译器。这项实验的核心工程设置如下:
并行协调机制。 实验面临的首要问题是如何让 16 个 Agent 同时工作而不互相踩踏。Carlini 的方案非常工程化:
- Docker 容器隔离:每个 Agent 运行在独立的 Docker 容器中,拥有自己的仓库克隆副本。这与 Claude Code 的 worktree 隔离思路一致,但粒度更粗——进程级 + 文件系统级隔离,16 个 Agent 完全互不干扰。
- 文件级任务锁:Agent 通过在共享
current_tasks/目录下写文本文件来声明自己正在处理哪个任务。如果两个 Agent 同时声明同一个任务,Git 的同步机制会迫使第二个 Agent 选择不同任务。这是一种极简但有效的分布式锁,只靠 Git就能实现。 - 自主合并冲突解决:Agent 完成一个任务后,从上游 pull、自己处理合并冲突、再 push。这意味着 Agent 不只是"写代码",还要完成完整的 Git 协作工作流。
专职 Agent 角色。 并行不只是"把任务切成 N 份同时跑"。Carlini 发现,为 Agent 赋予不同角色能显著提升整体产出质量:
- Code Coalescer:专门寻找并合并重复代码,减少代码库的熵
- Performance Optimizer:专门优化编译器速度和输出效率
- Rust Critic:审查 Rust 代码质量,提出并执行结构优化
- Documenter:持续维护 README 和进度追踪文档
这四种角色不是一开始就设计好的,而是在实验过程中根据实际需要逐步演化出来的。这与软件工程中"团队角色自然浮现"的模式高度一致——好的 SubAgent System 应该允许这种角色演化,而不是把 Agent 角色写死。
实验也暴露了一些关键的工程教训:
- 模型不擅长追踪时间:Agent 可能在一个庞大的测试套件上无限运行。解决方案是为测试 harness 加
--fast选项,让每个 Agent 只跑 1%-10% 的测试子集。 - 上下文窗口污染:测试失败时,Agent 倾向于 dump 数千行无意义输出进上下文。解决方案是让测试失败时输出标准关键词(如
ERROR),便于 Agent 快速 grep 定位。 - 大规模并行场景中的 Oracle 模式:当 Agent 在编译 Linux 内核时反复互相覆盖修复,Carlini 使用 GCC 作为"已知正确的编译器 Oracle"——Agent 用 GCC 编译部分内核,用自己的编译器编译另一部分,逐步缩小 bug 搜索范围。
测试 harness 的设计、输出格式、Oracle 的可用性,这些看似"外围"的基础设施,实际上决定了 Agent 协作的天花板。这个项目也有一个天然的优势,即存在所谓的编译器Oracle GCC,这不是每个项目都能有的。对于大部分创新项目来说,天然还是存在一些障碍的。
4. SubAgent System 的关键设计维度
4.1 Spawn / Delegate / Await 生命周期
| 项目 | Spawn 机制 | Delegate 内容 | Await 方式 |
|---|---|---|---|
| Codex | 创建独立 CodexThread + Session | child config + 初始 user input | subscribe_status() 等终态 |
| Claude | runAgent() 或 fork agent | prompt messages + ToolUseContext | 同步等待 / 异步 task notification |
| nanobot | asyncio.create_task 后台协程 | 最小 prompt(system + task) | 事件驱动回流,不阻塞主 Agent |
| pi | spawn 新 pi 子进程 | agent persona + Task 文本 | 消费 JSON event stream,等进程 close |
核心权衡在同步 vs 异步回流:同步简单直观但不适合长任务,异步灵活但需要 notification 机制和 resume 路径。
4.2 Context 共享与隔离
| 项目 | 共享内容 | 隔离内容 | 隔离粒度 |
|---|---|---|---|
| Codex | Auth/Models/Skills/MCP Manager | Session, ContextManager, rollout_path | 线程级 |
| Claude | 少数 capability flag(opt-in) | readFileState, toolDecisions, UI callback 等 | 字段级 |
| nanobot | workspace 路径, provider 配置 | 主会话历史, ContextBuilder 产物 | 会话级 |
| pi | cwd, 环境变量, 文件系统 | 对话历史, session tree, compaction state | 进程级 |
共识很明确:默认隔离,显式共享。 隔离粒度从会话级到进程级不等,越彻底越安全但启动成本越高。nanobot 和 pi 选择让子 Agent 初始上下文极小,把"共享历史"换成了"显式委托指令"。
4.3 工具集裁剪
| 项目 | 裁剪机制 | 排除的典型能力 |
|---|---|---|
| Codex | Feature flag + tool surface 动态决定 | 按 flag 禁用(如 SpawnCsv/Collab) |
| Claude | agent definition + allowlist | 取决于 agent type |
| nanobot | 硬编码排除列表 | message, spawn, cron, MCP tools |
| pi | frontmatter tools allowlist | 取决于 agent 配置 |
两条共识:子 Agent 不应直接对用户发言(发言权归主 Agent),递归 spawn 必须受控(深度限制或直接禁止)。
4.4 子 Agent 通信协议
| 项目 | 通信协议 | 协议载体 | 子 Agent 间直连 |
|---|---|---|---|
| Codex | V2 结构化消息 / 兼容层 notification | 写入接收方 history | 不支持 |
| Claude | SendMessage / Swarm mailbox | task queue / file-based mailbox | 支持(teammate) |
| nanobot | InboundMessage(system/subagent) | 半结构化文本回流主 loop | 不支持 |
| pi | JSON event stream + {previous} 占位符 | stdout JSONL / task 文本替换 | 不支持 |
分歧点:Codex 和 Claude 把 agent 间通信当作一等公民(结构化协议、消息队列、状态同步),nanobot 和 pi 则简化为"子→父回流,父决定下一步"。Claude 的 Swarm mailbox 是唯一把权限同步、shutdown 协商等也纳入同一总线的设计。
4.5 Worktree 隔离
| 项目 | 自动 worktree | cwd 级隔离 | 清理机制 |
|---|---|---|---|
| Codex | 无,靠外层策略 | 支持 | 无内置 |
| Claude | isolation: "worktree" 显式创建 | 支持 | 自动回收无变更的 worktree |
| nanobot | 无 | 共享 workspace | 无 |
| pi | 无 | 支持 cwd 注入 | 无 |
Claude Code 是唯一内置自动 worktree 隔离的,任务结束无改动则自动回收。Docker 容器隔离是更"重"但更彻底的替代——隔离越彻底冲突越少,但结果合并成本越高。
4.6 结果汇合(Fan-in)
| 项目 | 同步汇合 | 异步汇合 | 多任务汇合 |
|---|---|---|---|
| Codex | tool_result 内联 | completion watcher → 结构化消息 | wait tool + CSV fanout |
| Claude | tool_result 内联 | task_notification | 无内置 join barrier |
| nanobot | 无(全部异步) | System message 回流主 loop | 逐条回流,per-session lock 串行 |
| pi | toolResult.content | 无异步模式 | parallel 文本拼接 + 50KB cap |
两种哲学:函数返回值式(当场内联,简单但阻塞)vs 消息驱动回流式(不阻塞但需要 notification 调度)。pi 的 50KB cap 是唯一在模型可见层做截断的设计。
4.7 递归深度控制
| 项目 | 是否支持递归 | 控制机制 | 默认行为 |
|---|---|---|---|
| Codex | 支持 | agent_max_depth 硬限制 | depth=1(不允许孙 Agent) |
| Claude | 部分支持 | fork child 禁止,普通允许 | fork 路径禁递归 |
| nanobot | 不支持 | 不注册 spawn tool | 硬禁止 |
| pi | 技术上可行 | 无显式 depth 控制 | 取决于 allowlist |
Codex 的 agent_max_depth 最干净;Claude fork child 禁递归是因为共享了父级 prompt cache 前缀,递归会导致 cache key 混乱。
5. 设计共识
抛开实现差异,所有项目在以下原则上高度一致:
子 Agent 是受控执行单元,不是第二个主 Agent。 执行权可以下放,但发言权和最终决策权必须留在主 Agent。nanobot 最极端——子 Agent 连
messagetool 都没有。默认隔离,显式共享。 子 Agent 默认不继承对话历史、运行时状态和上下文产物。共享的能力通过显式配置开放,而非默认暴露。
工具集必须裁剪。 至少移除直接对用户发言的能力和不受控的递归 spawn。裁剪越激进越可预测,但能力范围也越窄。
委托判断权在模型,不在运行时调度器。 是否启动子 Agent、选哪个 agent、用什么模式——这些决策依赖语义理解,硬编码规则不如模型自主判断。
回流走统一协议,不另起通道。 结构化消息、system message、JSON event stream——形态各异,但都复用主 Agent 的现有消息处理管线。
递归深度必须有显式上限。 机制可以不同(
agent_max_depth、fork gate、tool allowlist),但都不能放任无限嵌套。文件系统隔离是并行写安全的前提。 从 worktree 到 Docker 容器,本质是在预防冲突和解决冲突的成本之间权衡。目前只有 Claude Code 做到了自动集成。
这些共识都在回答同一个问题:如何在不引入失控复杂度的前提下,让单个 Agent 获得任务分拆与并行执行的能力。
6. 总结
SubAgent System 是 Agent 从"单兵作战"升级为"团队协作"的关键一跃。从朴素的 spawn + run + return result 到成熟的多 Agent Runtime。SubAgent System 的演进体现了分布式系统设计的核心思想:通过清晰的边界定义、能力的显式裁剪、上下文的审慎隔离、结果的可靠汇合,把"并发委托"的复杂度控制在可理解和可测试的范围内。
SubAgent System 的设计工程原则是:子 Agent 是受控的执行单元,不是独立的人格——执行权可以下放,发言权和最终决策权必须留在主 Agent。隔离不是目的,可控才是目的——共享什么、隔离什么,每一处都应该有明确的理由。 多 Agent 系统从"能跑"到"可靠"的关键跨越,不在于更复杂的调度算法,而在于更扎实的工程基础设施。
下一篇,我们将深入探讨 Agent 的 权限与安全系统(Permission & Security) 设计,分析如何让 Agent 在拥有强大执行能力的同时,不变成安全隐患。
参考文献
Nicholas Carlini, “Building a C compiler with a team of parallel Claudes,” Anthropic Engineering Blog, Feb 2026, https://www.anthropic.com/engineering/building-c-compiler ↩︎ ↩︎
Anthropic, “Effective harnesses for long-running agents,” Engineering at Anthropic, Nov 2025, https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents ↩︎
OpenAI, “Codex CLI,” https://github.com/openai/codex ↩︎
Anthropic, “Claude Code,” https://code.claude.com/docs ↩︎
nanobot, https://github.com/HKUDS/nanobot ↩︎