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(如 explore 或 plan)发起请求。如果没有指定,则默认落入 general-purpose 模式。
2. 定义与加载机制
Subagent 的“人格”由定义文件决定。claude-code-opensource/src/tools/AgentTool/loadAgentsDir.ts 会统一解析内建、插件及用户自定义的 agent 定义。这些定义规定了子代理的:
- 工具权限:例如
Explore和Plan代理在exploreAgent.ts中被硬性禁用了Edit和Write工具,从而实现真正的“只读”。 - 技能与 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 协作模式下,它才会进入真正物理隔离的执行空间。
延伸阅读
- 如果你想了解多个智能体如何分工协作,请看 Agent Teams:多角色协作模型。
- 如果你关心子代理的任务进度如何被管理和追踪,请看 任务管理与编排:Task 系统的运作逻辑。
- 如果你想研究如何通过
Git Worktree实现物理隔离的并行执行,请看 并行会话与 Worktree 协作。
源码锚点
claude-code-opensource/src/tools/AgentTool/AgentTool.tsx: Subagent 的入口工具,负责分流 fork/worktree 请求。
📄 src/tools/AgentTool/AgentTool.tsx — Subagent 的入口工具,负责分流 fork/worktree 请求。
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` 的生命周期管理。
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 定义文件。
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 的底层分叉能力。
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 逻辑。
* 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 定义。
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