Skip to content
源码分析手册

Subagent 架构:侧链代理、任务分叉与隔离执行

在 Claude Code 处理复杂项目时,你经常会看到它启动一个“Subagent”。这听起来像是主程序又开了一个 Claude 窗口,但源码显示,这套架构比简单的多进程要精妙得多。

本质

Subagent(子代理)本质上是主会话内部开启的一条独立侧链代理(Sidechain Agent)

它不是粗暴地启动一个新的 Claude CLI 进程,也不是单纯换个 Prompt 继续在主线聊天。它在当前会话中分叉(Fork)出一个拥有独立 agentId、独立 System Prompt、独立工具池(Tool Pool)和独立对话历史(Transcript)的执行单元。

Subagent 的核心价值在于上下文隔离:将漫长的文件搜索、琐碎的代码尝试或局部的逻辑推演从主对话历史中剥离出去。这样主线程既能拿到最终结论,又不会被中间产生的海量工具输出撑爆 Token 上下文。

从源码看实现

实现 Subagent 的逻辑主要收敛在 src/tools/AgentTool/ 和底层的 forkedAgent.ts 中。

1. 从工具触发的分叉(Forking)

主代理并不知道“子代理”是个特殊的系统组件,它只是在调用一个名为 AgentTool 的工具。 在 claude-code-opensource/src/tools/AgentTool/AgentTool.tsx 中,主代理根据 subagent_type(如 exploreplan)发起请求。如果没有指定,则默认落入 general-purpose 模式。

2. 定义与加载机制

Subagent 的“人格”由定义文件决定。claude-code-opensource/src/tools/AgentTool/loadAgentsDir.ts 会统一解析内建、插件及用户自定义的 agent 定义。这些定义规定了子代理的:

  • 工具权限:例如 ExplorePlan 代理在 exploreAgent.ts 中被硬性禁用了 EditWrite 工具,从而实现真正的“只读”。
  • 技能与 Hook:针对特定任务(如代码索引)注入的特殊处理逻辑。

3. 侧链执行逻辑

真正的执行发生在 claude-code-opensource/src/tools/AgentTool/runAgent.ts。它并不产生新进程,而是:

  • 生成新 agentId:确保消息历史(.jsonl 文件)与主线程分开。
  • 重构上下文:调用 getAgentSystemPrompt(...) 生成专属于该子代理的指令,并裁剪掉主线程中不必要的背景信息。
  • 递归调用 Query:在同一个进程内,使用这套新的上下文和工具池再次触发 query(...) 循环。

4. 特殊变体:/btw (Side Question)

/btw 是 Subagent 架构的一种极简化应用。 与普通 Subagent 追求“全能工具 + 独立上下文”不同,/btw 追求的是“零工具 + 全量上下文”。它通过 claude-code-opensource/src/utils/sideQuestion.ts 发起一个 maxTurns: 1 且禁止所有工具的轻量级 Fork,专门用于在不打断主任务的前提下,基于当前已有的缓存上下文回答用户的追问。

限制与陷阱

  • 状态不自动同步:Subagent 虽然共享物理文件系统,但它的对话历史是独立的。如果你在子代理运行期间修改了主会话的状态,子代理除非重新读取,否则无法感知这种变化。
  • 工具集是硬限制Explore 代理不能改写代码,不是因为它“想通了”,而是因为它拿到的工具箱里根本没有 Edit 工具。这是由 resolveAgentTools(...) 在运行时硬性裁剪的。
  • 权限冒泡(Bubbling up):尽管子代理在侧链运行,但它遇到的任何需要用户确认的权限请求(如写入敏感文件),都会穿透侧链,显示在主终端供用户点击。
  • 默认同进程,可选隔离:普通 Subagent 默认在同一个 Node.js 进程中运行。只有当你显式使用 worktree 模式或在 Team 协作模式下,它才会进入真正物理隔离的执行空间。

延伸阅读

源码锚点

  • claude-code-opensource/src/tools/AgentTool/AgentTool.tsx: Subagent 的入口工具,负责分流 fork/worktree 请求。
📄 src/tools/AgentTool/AgentTool.tsx — Subagent 的入口工具,负责分流 fork/worktree 请求。L122-124 of 1398
tsx
  return isBackgroundTasksDisabled || isForkSubagentEnabled() ? schema.omit({
    run_in_background: true
  }) : schema;
  • claude-code-opensource/src/tools/AgentTool/runAgent.ts: 核心侧链执行器,负责新 agentId 的生命周期管理。
📄 src/tools/AgentTool/runAgent.ts — 核心侧链执行器,负责新 `agentId` 的生命周期管理。L347-353 of 974
typescript
  const agentId = override?.agentId ? override.agentId : createAgentId()

  // Route this agent's transcript into a grouping subdirectory if requested
  // (e.g. workflow subagents write to subagents/workflows/<runId>/).
  if (transcriptSubdir) {
    setAgentTranscriptSubdir(agentId, transcriptSubdir)
  }
  • claude-code-opensource/src/tools/AgentTool/loadAgentsDir.ts: 负责加载和解析各种 agent 定义文件。
📄 src/tools/AgentTool/loadAgentsDir.ts — 负责加载和解析各种 agent 定义文件。L12-15 of 756
typescript
  type McpServerConfig,
  McpServerConfigSchema,
} from '../../services/mcp/types.js'
import type { ToolUseContext } from '../../Tool.js'
  • claude-code-opensource/src/utils/forkedAgent.ts: 提供了跨会话复用 Prompt Cache 的底层分叉能力。
📄 src/utils/forkedAgent.ts — 提供了跨会话复用 Prompt Cache 的底层分叉能力。L59-61 of 690
typescript
  systemPrompt: SystemPrompt
  /** User context - prepended to messages, affects cache */
  userContext: { [k: string]: string }
  • claude-code-opensource/src/utils/sideQuestion.ts: 实现 /btw 命令的轻量级、无工具 Fork 逻辑。
📄 src/utils/sideQuestion.ts — 实现 `/btw` 命令的轻量级、无工具 Fork 逻辑。L5-9 of 156
typescript
 * Uses runForkedAgent to leverage prompt caching from the parent context
 * while keeping the side question response separate from main conversation.
 */

import { formatAPIError } from '../services/api/errorUtils.js'
  • claude-code-opensource/src/tools/AgentTool/built-in/exploreAgent.ts: Explore 代理的只读限制与 Prompt 定义。
📄 src/tools/AgentTool/built-in/exploreAgent.ts — `Explore` 代理的只读限制与 Prompt 定义。L13-42 of 84
typescript
function getExploreSystemPrompt(): string {
  // Ant-native builds alias find/grep to embedded bfs/ugrep and remove the
  // dedicated Glob/Grep tools, so point at find/grep via Bash instead.
  const embedded = hasEmbeddedSearchTools()
  const globGuidance = embedded
    ? `- Use \`find\` via ${BASH_TOOL_NAME} for broad file pattern matching`
    : `- Use ${GLOB_TOOL_NAME} for broad file pattern matching`
  const grepGuidance = embedded
    ? `- Use \`grep\` via ${BASH_TOOL_NAME} for searching file contents with regex`
    : `- Use ${GREP_TOOL_NAME} for searching file contents with regex`

  return `You are a file search specialist for Claude Code, Anthropic's official CLI for Claude. You excel at thoroughly navigating and exploring codebases.

=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
This is a READ-ONLY exploration task. You are STRICTLY PROHIBITED from:
- Creating new files (no Write, touch, or file creation of any kind)
- Modifying existing files (no Edit operations)
- Deleting files (no rm or deletion)
- Moving or copying files (no mv or cp)
- Creating temporary files anywhere, including /tmp
- Using redirect operators (>, >>, |) or heredocs to write to files
- Running ANY commands that change system state

Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools - attempting to edit files will fail.

Your strengths:
- Rapidly finding files using glob patterns
- Searching code and text with powerful regex patterns
- Reading and analyzing file contents

基于 Claude Code v2.1.88 开源快照的深度分析