Claude Code 101|11|Subagents and Swarm

Claude Code 的多 Agent 能力从 AgentTool 开始,向后台任务、worktree 隔离、remote agent 和 teammate/swarm 扩展。

Claude Code 101|11|Subagents and Swarm

多 Agent 很容易被讲成“让几个角色一起讨论”。这种叙事适合演示,却很难支撑真实代码工作。真实工程里的多 Agent 首先不是聊天角色问题,而是执行上下文问题:谁在执行任务,使用什么工具,有什么权限,在哪个目录修改文件,是否后台运行,结果如何回传,失败如何恢复,多个执行者是否会互相覆盖修改。

Claude Code 的 Subagents and Swarm 更接近一个任务调度系统。AgentTool 把子 Agent 包装成可执行任务,LocalAgentTask 让后台 agent 可以持续运行和汇报进度,worktree isolation 让并发修改具备文件系统隔离,teammate / swarm 则把协作扩展到终端 pane、进程和权限桥接层。

这一篇要回答的工程问题是:一个 Coding Agent Runtime 如何把“多个模型实例”组织成可隔离、可追踪、可通信、可恢复的执行上下文,而不是把多 Agent 变成 prompt 层角色扮演。

工程问题

在代码场景中,并行化的诱惑很强:一个 agent 写实现,一个 agent 写测试,一个 agent 做 review,一个 agent 查资料。但如果这些 agent 共享同一个工作目录、同一套权限、同一条 transcript、同一个 UI 输出通道,就会很快失控。

典型风险包括:

  • 两个 agent 同时修改同一文件,互相覆盖。
  • 子 Agent 获得了主 Agent 不应转交的权限。
  • 后台任务完成后没有可靠通知,结果丢失。
  • 主 Agent 无法知道子任务使用了多少工具和 token。
  • 子 Agent 的上下文污染主会话,导致后续推理混乱。
  • 多进程 teammate 无法同步 permission request。

因此多 Agent 的核心不是“多几个智能体”,而是 runtime 资源治理。每个 Agent 都应该有明确身份、工作目录、工具集合、权限模式、模型配置、输入输出通道和生命周期。

概念边界

上一篇 Session Resume 讨论如何从 transcript 恢复单个会话的 runtime state。Subagents and Swarm 在这个基础上扩展:当 runtime 可以派生子执行上下文时,每个上下文都需要自己的状态、日志和边界。

下一篇 TUI Observability 会讨论 runtime event 如何投影给用户和工程系统。多 Agent 正是可观测性压力最大的场景:后台任务进度、teammate 状态、permission bridge、工具活动、token 使用都需要可见,否则用户无法判断系统在做什么。

Claude Code 这个案例覆盖了 agent 调度、后台任务、消息投递、worktree 隔离、swarm 权限和 UI 集成。它说明多 Agent 不是“多几个角色”,而是多个受治理执行上下文的生命周期管理。

机制一:AgentTool 是调度入口,不是二次问答

如果把 subagent 理解为“再调用一次模型”,会漏掉它真正复杂的地方。Claude Code 的 AgentTool 输入不仅包含 prompt,还包含 description、subagent_type、model、run_in_background、name、team_name、mode、isolation、cwd 等调度参数。src/tools/AgentTool/AgentTool.tsx 中的 schema 和执行逻辑说明,它负责选择 agent 定义、模型、权限、工具、工作目录以及运行模式。

这意味着 AgentTool 是一个 runtime 调度器。主 Agent 通过它把一个任务委派给子 Agent,但委派的不是一段文本,而是一个受约束的执行上下文。子 Agent 需要自己的 system/user context、工具列表、permission mode、agent id、sidechain transcript 和 tracing。

这样的设计解决两个问题。

第一,隔离上下文。子 Agent 可以专注于某个任务,不必继承主会话全部思考链和 UI 状态。它的输出以结果形式回到主 Agent,而不是把内部过程全部混入主上下文。

第二,治理能力。主 Runtime 可以限制子 Agent 可用工具、模型和权限,也可以记录它的成本、工具调用和最终输出。如果 subagent 只是 prompt 技巧,就很难做这些治理。

机制二:同步 subagent 与后台任务是两种生命周期

多 Agent 的一个关键分叉是同步执行还是后台执行。同步 subagent 像当前 turn 的子过程:主 Agent 等待它完成,再使用它的结果继续推理。后台 agent 则更像一个任务:它可以在主会话继续时独立运行,之后通过通知或消息通道回到用户视野。

src/tasks/LocalAgentTask/LocalAgentTask.tsx 提供了后台 agent 的任务形态。它维护 progress tracker、toolUseCount、tokenCount、recentActivities、pendingMessages、output file 和 completion notification 等状态。src/tools/SendMessageTool/SendMessageTool.ts 则说明主会话或用户可以向后台 agent 投递消息。

这种生命周期差异非常重要。同步 subagent 的返回值可以作为当前模型调用的输入;后台任务的结果不能假设立即可用,它需要状态存储、进度展示、取消/完成语义、消息队列和通知。否则后台 agent 只是一个失控的异步进程。

对 Coding Agent 来说,后台任务尤其适合长耗时活动:跑测试、分析大型代码库、准备迁移方案、生成报告。但它必须被 runtime 管理,而不是 shell 级别“放到后台”。

机制三:worktree isolation 解决并发修改风险

代码协作最硬的边界是文件系统。两个 Agent 同时在同一个 working tree 里编辑文件,会遇到和人类协作一样的问题,但更难察觉:一个 Agent 可能基于旧版本生成 patch,另一个 Agent 已经改了同一区域;工具调用成功并不代表合并语义正确。

Claude Code 在 AgentTool 中引入 isolation / cwd 等参数,并在相关逻辑中调用 worktree 创建、检查变更和清理。src/tools/AgentTool/AgentTool.tsx 引用了 worktree 创建、变更检测和移除能力;src/utils/getWorktreePathsPortable.tssrc/tools/EnterWorktreeTool/EnterWorktreeTool.ts 也体现 worktree 是 runtime 可见的工程边界。

worktree isolation 的意义是让子 Agent 在独立分支或临时工作区中行动。任务完成后,如果没有修改,可以清理;如果有修改,可以保留路径、分支和 metadata,等待用户或主 Agent 合并。这比让多个 Agent 共享 cwd 更接近真实工程协作。

它也改变了多 Agent 的产品语义。子 Agent 不只是“给建议”,而是可以在隔离空间里完成可检查的代码变更。主 Agent 或用户随后评估 diff、运行测试、决定合并。这是从对话协作走向工程协作的关键一步。

机制四:sidechain transcript 让子过程可追踪但不污染主线

多 Agent 系统需要记录子 Agent 做了什么,但不能把所有内部消息都直接塞回主会话。否则主上下文会迅速膨胀,用户也会被大量细节淹没。

Claude Code 的 subagent 机制包含 sidechain transcript、agent metadata、tracing 和 SDK event 队列等概念。子 Agent 的执行需要可追踪,但它的详细过程可以作为 sidechain 存在,主 Agent 只接收摘要或结果。

这是多 Agent 可扩展性的关键。每个子 Agent 都可能经历自己的模型循环、工具调用、权限请求和错误恢复。如果所有事件都进入主上下文,主会话会变成全局日志;如果完全不记录,调试和恢复又无从谈起。sidechain 的作用是在“可追踪”和“不污染”之间建立边界。

机制五:teammate / swarm 是进程、终端和权限编排

Swarm 不只是多个模型一起生成文本。Claude Code 的 teammate / swarm 涉及终端后端、进程组织、权限同步、环境继承和 UI 布局。关键不在“角色讨论”,而在多个执行者如何共享权限、消息和可观测状态。

这类设计要解决的是“多个执行者如何共享一个产品空间”。如果 leader 在 tmux 中,可以通过 pane 组织 teammate;如果不在 tmux 中,也可能使用独立 session 或 in-process teammate。无论哪种模式,都要继承 CLI flags、模型配置、settings、provider、plugin、权限上下文等,否则 teammate 和 leader 的运行环境会不一致。

权限桥接尤其关键。一个 worker 可能触发工具权限请求,但真正拥有交互界面的可能是 leader。系统需要把 permission request 从 worker 传到 leader,再把用户决定传回 worker。否则多进程 Agent 要么无法请求权限,要么绕过权限系统。

这说明 swarm 是 runtime 编排问题:终端、进程、权限、环境、消息和布局都在其中。prompt 层“专家小组”无法覆盖这些工程边界。

机制六:通信要显式建模

多 Agent 需要消息通道。同步 subagent 可以通过返回值通信,后台任务需要 pending messages,teammate 需要注入用户消息,worker 需要 permission mailbox。src/tools/SendMessageTool/SendMessageTool.tssrc/tasks/LocalAgentTask/LocalAgentTask.tsxsrc/tasks/InProcessTeammateTask/src/screens/REPL.tsx 中的相关导入说明,通信不是一个隐含副作用,而是被显式纳入 runtime。

显式通信有两个好处。

第一,消息可以被排队、展示、记录和恢复。后台 agent 忙碌时,发给它的消息不能丢失;它完成后,通知也不能只存在于 stdout。

第二,通信可以受权限和身份约束。不是所有 agent 都应该能向所有任务发送消息,也不是所有 worker 都能直接影响 leader 状态。通道建模让 runtime 有机会做治理。

TypeScript-style pseudocode

下面用伪代码抽象多 Agent 调度形状:

type AgentExecutionRequest = {
  prompt: string
  agentType?: string
  model?: string
  runInBackground: boolean
  isolation: 'shared' | 'worktree'
  cwd?: string
  name?: string
  teamName?: string
}

type AgentExecutionContext = {
  id: AgentId
  identity: AgentIdentity
  model: ModelConfig
  tools: ToolDefinition[]
  permissions: PermissionPolicy
  workspace: WorkspaceHandle
  transcript: SidechainTranscript
  parentSession: SessionId
}

async function dispatchAgent(req: AgentExecutionRequest, parent: RuntimeContext) {
  const identity = await loadAgentIdentity(req.agentType)
  const workspace = await allocateWorkspace({
    parentCwd: parent.cwd,
    requestedCwd: req.cwd,
    isolation: req.isolation,
  })

  const context: AgentExecutionContext = {
    id: createAgentId(),
    identity,
    model: chooseModel(req.model, identity, parent),
    tools: chooseTools(identity, parent.policy),
    permissions: derivePermissionPolicy(identity, parent.permissions),
    workspace,
    transcript: createSidechainTranscript(parent.sessionId),
    parentSession: parent.sessionId,
  }

  if (req.runInBackground) {
    return startManagedAgentTask(context, req.prompt)
  }

  return await runAgentToCompletion(context, req.prompt)
}

async function startManagedAgentTask(ctx: AgentExecutionContext, prompt: string) {
  const task = createTaskRecord({
    agentId: ctx.id,
    workspace: ctx.workspace,
    status: 'running',
    progress: [],
    pendingMessages: [],
  })

  runAsync(async () => {
    try {
      const result = await runAgentLoop(ctx, prompt, {
        onToolUse: event => task.trackToolUse(event),
        onProgress: event => task.updateProgress(event),
        onMessage: event => task.appendActivity(event),
      })
      task.complete(result)
    } catch (error) {
      task.fail(error)
    }
  })

  return task.handle
}

这段伪代码刻意把 workspace、permission、transcript 和 task record 放进 context。多 Agent 的难点不在 runAgentLoop 本身,而在运行前后如何分配和治理这些资源。

工程启发

第一,多 Agent 要从执行上下文建模开始。给每个 Agent 明确身份、工具、权限、目录、日志和生命周期。没有这些边界,多 Agent 只是多个模型共享一团全局状态。

第二,并发写代码必须先解决隔离。worktree、branch、diff、metadata、merge 策略,比“让多个角色讨论”更基础。只要 Agent 会写文件,就不能忽略文件系统冲突。

第三,后台任务必须是 runtime 对象。它要有进度、状态、消息队列、结果文件、完成通知和取消语义。不要把后台 agent 简化为一个 detached process,否则用户无法理解它在做什么,系统也无法恢复它。

第四,权限不能因为多 Agent 而旁路。worker、teammate 和 subagent 的权限请求都应该回到统一策略,必要时通过 leader bridge 请求用户确认。多 Agent 会扩大行动面,权限系统更不能弱化。

第五,sidechain 是必要结构。子 Agent 的内部过程需要可追踪,但不应该污染主上下文。摘要、结果和引用进入主线,详细 transcript 留在子链,才有扩展性。

小结

Claude Code 的 Subagents and Swarm 展示了多 Agent 在工程中的真实形态:AgentTool 是调度入口,LocalAgentTask 管理后台生命周期,worktree isolation 处理并发文件修改,sidechain transcript 记录子过程,teammate / swarm 编排进程、终端和权限。

多 Agent 不是“更多角色”,而是“更多受治理的执行上下文”。当这些上下文开始并行运行,用户和工程系统必须能看见它们的状态。下一篇 TUI Observability 会讨论 Claude Code 如何把 runtime event 投影到终端 UI、telemetry、session tracing 和性能时间线中,让复杂 Agent 系统可用、可调试、可演进。