AgentTool 深度解读 —— Claude Code 中最复杂的单个模块
AgentTool 不是一个普通工具 —— 它是 「生成 Agent 的 Agent」,负责子代理的定义加载、上下文隔离、执行编排、通信协调和生命周期管理。单文件 ~1400 行,加上 Swarm 系统总计超过 4000 行,是 Claude Code 中最复杂的子系统。
AgentTool 生态全景├── tools/AgentTool/ ← Agent 工具本体│ ├── AgentTool.tsx (1397 行) 工具定义 + UI 渲染│ ├── runAgent.ts (36KB) Agent 执行引擎│ ├── forkSubagent.ts (211 行) Fork 语义实现│ └── loadAgentsDir.ts (26KB) Agent 定义加载├── utils/swarm/ ← 多 Agent 编排系统│ ├── inProcessRunner.ts (1552 行) 进程内 Teammate 运行时│ ├── permissionSync.ts (928 行) 跨进程权限同步│ ├── teamHelpers.ts (683 行) 团队文件管理│ └── spawnInProcess.ts (329 行) Teammate 生成├── utils/worktree.ts (16KB) Git Worktree 隔离└── tasks/ ← 任务系统集成 ├── LocalAgentTask/ (682 行) 本地 Agent 任务 ├── InProcessTeammateTask/ (125 行) 进程内 Teammate 任务 └── RemoteAgentTask/ (855 行) 远程 Agent 任务1. Agent 定义与加载
Section titled “1. Agent 定义与加载”关键文件:tools/AgentTool/loadAgentsDir.ts
Agent 类型体系
Section titled “Agent 类型体系”// 基础定义type BaseAgentDefinition = { agentType: string // 如 "general-purpose", "Explore" tools: string[] | ['*'] // 可用工具列表,'*' 表示全部 model: string | 'inherit' // 使用的模型,'inherit' 继承父级 maxTurns: number // 最大轮次 permissionMode: string // 'default' | 'auto' | 'bypass' | 'bubble' getSystemPrompt(): string // 系统提示词生成 mcpServers?: McpServerConfig[] // Agent 专属 MCP 服务器}
// 三种来源type BuiltInAgentDefinition // 内置 Agent(代码定义)type CustomAgentDefinition // 用户自定义(~/.claude/agents/*.md)type PluginAgentDefinition // 插件提供6 种内置 Agent
Section titled “6 种内置 Agent”| Agent 类型 | 模型 | 工具集 | 模式 | 用途 |
|---|---|---|---|---|
| general-purpose | 继承父级 | 全部 (*) | default | 通用研究/执行 |
| Explore | Haiku (快速) | 只读工具,排除 Agent | ONE_SHOT | 代码库探索 |
| Plan | 继承父级 | 只读工具 | ONE_SHOT | 架构设计 |
| Verification | 继承父级 | 全部 | default | 「破坏性测试」验证 |
| Code Guide | 继承父级 | 7 个工具 | default | 交互式指导 |
| Statusline Setup | 继承父级 | 终端配置工具 | default | 状态栏设置 |
built-in → plugin → user (~/.claude/agents/) → project → flag → policy后加载的覆盖前面的(同名时)自定义 Agent 格式(Markdown Frontmatter)
Section titled “自定义 Agent 格式(Markdown Frontmatter)”---agentType: my-reviewertools: [Read, Grep, Glob]model: haikumaxTurns: 10permissionMode: auto---
你是一个代码审查专家...(系统提示词)- Explore Agent 用 Haiku 模型 —— 探索类任务不需要最强模型,用快速模型降本提速
- ONE_SHOT 模式 —— Explore 和 Plan Agent 执行一次就返回,不进入交互循环
- Agent 专属 MCP —— 每个 Agent 可以有自己的 MCP 服务器,生命周期与 Agent 绑定
2. AgentTool 输入与执行入口
Section titled “2. AgentTool 输入与执行入口”关键文件:tools/AgentTool/AgentTool.tsx
输入 Schema
Section titled “输入 Schema”const inputSchema = z.object({ // ═══ 核心参数 ═══ description: z.string(), // 任务描述(3-5 词) prompt: z.string(), // 完整任务提示
// ═══ Agent 选择 ═══ subagent_type: z.string().optional(), // Agent 类型(省略则 Fork) model: z.enum(['sonnet', 'opus', 'haiku']).optional(), // 模型覆盖
// ═══ 执行方式 ═══ run_in_background: z.boolean().optional(), // 后台运行 isolation: z.enum(['worktree']).optional(), // Worktree 隔离
// ═══ 团队协作 ═══ name: z.string().optional(), // Agent 名称(可通过 SendMessage 寻址) team_name: z.string().optional(), // 所属团队 mode: z.enum([...]).optional(), // 权限模式})type Output = | { type: 'sync_completion', result: string } // 同步完成 | { type: 'async_launched', taskId: string } // 异步启动 | { type: 'teammate_spawned', agentId: string } // Teammate 生成(内部) | { type: 'remote_launched', taskId: string } // 远程启动(内部)8 阶段执行流程
Section titled “8 阶段执行流程”call(input)│├─ Phase 1: 参数校验│ ├─ 防止嵌套团队生成│ └─ 校验 Agent 类型是否存在│├─ Phase 2: Agent 选择│ ├─ 有 subagent_type → 查找对应 Agent 定义│ └─ 无 subagent_type → Fork 模式(继承父上下文)│├─ Phase 3: 系统提示词构建│ ├─ Agent 自定义提示词│ ├─ + 工具使用说明│ └─ + 上下文注入(CLAUDE.md 等)│├─ Phase 4: 隔离环境设置│ ├─ Worktree 模式 → 创建 Git Worktree│ ├─ Remote 模式 → 连接远程 CCR 实例│ └─ 普通模式 → 使用当前工作目录│├─ Phase 5: 工具池组装│ ├─ tools: ['*'] → 继承父级全部工具│ ├─ tools: ['Read', 'Grep'] → 精确工具集│ └─ Fork 模式 → useExactTools=true(复制父级完整工具池)│├─ Phase 6: MCP 服务器准备│ ├─ 等待 Agent 专属 MCP 连接(最多 30s)│ └─ 合并继承的 + Agent 定义的 MCP 服务器│├─ Phase 7: 执行分支│ ├─ 同步执行 → runAgent() → 等待完成│ └─ 异步执行 → registerAsyncAgent() → 后台运行│└─ Phase 8: 清理 ├─ 关闭 Agent 专属 MCP 服务器 ├─ 清理 Worktree(如果没有变更) └─ 返回结果3. Fork 语义 —— Prompt Cache 共享的精髓
Section titled “3. Fork 语义 —— Prompt Cache 共享的精髓”关键文件:tools/AgentTool/forkSubagent.ts
Fork 是当 subagent_type 省略时的默认行为。它的核心思想是:子 Agent 继承父对话的完整上下文,并通过字节级相同的前缀最大化 Prompt Cache 命中率。
Fork 工作原理
Section titled “Fork 工作原理”父 Agent 对话:┌────────────────────────────────────────┐│ System Prompt │ ← 字节相同│ Message 1 (user) │ ← 字节相同│ Message 2 (assistant + tool_use) │ ← 字节相同│ Message 3 (tool_result) │ ← 字节相同│ ... │ ← 字节相同│ 当前 assistant 消息 (含 Agent tool_use) │ ← 字节相同└────────────────────────────────────────┘
Fork 子 Agent A: Fork 子 Agent B:┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐│ 【完全相同的前缀】 │ │ 【完全相同的前缀】 ││ tool_result: placeholder (相同) │ │ tool_result: placeholder (相同) ││ 子 Agent A 的具体指令 ← 唯一差异点 │ │ 子 Agent B 的具体指令 ← 唯一差异点 │└────────────────────────────────────────┘ └────────────────────────────────────────┘ ↑ ↑ 共享 Prompt Cache 共享 Prompt Cache关键实现细节
Section titled “关键实现细节”// 1. 生成合成 Fork Agent 定义const FORK_AGENT = { tools: ['*'], // 继承所有工具 model: 'inherit', // 继承模型 permissionMode: 'bubble', // 权限冒泡到父级 maxTurns: 200, // 高轮次上限}
// 2. 克隆父对话的所有 tool_use,创建相同的 placeholder tool_result// 这保证所有 Fork 子 Agent 的消息前缀字节级相同const placeholderResults = parentToolUses.map(tu => ({ type: 'tool_result', tool_use_id: tu.id, content: '[placeholder]' // 所有子 Agent 都用相同的 placeholder}))
// 3. 只有最后的「指令」不同const childDirective = ` Scope: ${input.prompt} Result: 必须包含 Key Files / Files Changed / Issues 10 条不可违反的规则(禁止递归 Fork、禁止对话、直接使用工具...)`递归 Fork 防护(双路径)
Section titled “递归 Fork 防护(双路径)”路径 1(主): querySource === 'agent:builtin:fork' → 如果当前已经是 Fork 子 Agent,禁止再次 Fork
路径 2(备): 扫描消息中的 <fork_boilerplate> 标签 → 防止 autocompact 后 querySource 丢失的情况- 字节级前缀相同 → Prompt Cache 命中 —— 这是成本优化的核心。多个 Fork 子 Agent 共享同一份 cache,避免重复计算
permissionMode: 'bubble'—— Fork 子 Agent 的权限请求「冒泡」到父 Agent,由父 Agent 的 UI 处理- 10 条不可违反规则 —— 用自然语言约束子 Agent 的行为边界,包括「禁止递归 Fork」「不要对话,直接干活」等
4. Agent 执行引擎
Section titled “4. Agent 执行引擎”关键文件:tools/AgentTool/runAgent.ts
执行流程(AsyncGenerator)
Section titled “执行流程(AsyncGenerator)”async function* runAgent(config): AsyncGenerator<Message> { // 1. 上下文初始化 const fileStateCache = parentCache.clone() // 克隆文件状态缓存 const perfTrace = createPerfettoAgent() // 性能追踪 const mcpServers = setupAgentMcp() // MCP 服务器 const systemPrompt = buildSystemPrompt() // 系统提示词 const hooks = registerAgentHooks() // Hook 注册
// 2. 进入查询循环 for await (const event of query({ messages: initialMessages, tools: toolPool, systemPrompt, maxTurns: agent.maxTurns, })) { // 3. 流式 yield 消息给父 Agent if (event is AssistantMessage) yield event if (event is ToolUseSummary) yield event if (event is Progress) yield event
// 4. 超过 maxTurns → 生成 TombstoneMessage if (turnCount > maxTurns) { yield TombstoneMessage("max turns reached") break } }
// 5. 清理 await cleanupMcpServers() await unregisterHooks()}Fork 路径的特殊处理
Section titled “Fork 路径的特殊处理”Fork 模式 vs 普通模式:
Fork 模式: - useExactTools = true → 完全继承父级工具池(不重新组装) - forkContextMessages → 携带完整父对话历史 - systemPrompt override → 使用父级系统提示词(保证字节相同)
普通模式: - useExactTools = false → 按 Agent 定义组装工具池 - 空消息历史 → 全新对话 - 独立 systemPrompt → 按 Agent 定义生成5. Swarm 系统 —— 多 Agent 编排
Section titled “5. Swarm 系统 —— 多 Agent 编排”5.1 进程内 Teammate 运行时
Section titled “5.1 进程内 Teammate 运行时”关键文件:utils/swarm/inProcessRunner.ts(1552 行)
Leader Agent Teammate Agent(进程内)┌──────────┐ ┌──────────┐│ │── sendMessage() ──→ │ ││ REPL │ │ 独立的 ││ UI │←── mailbox 通知 ── │ 查询循环 ││ │ │ ││ 权限 │←── 权限请求桥接 ── │ 共享 ││ 对话框 │── 权限结果返回 ──→ │ 进程空间 │└──────────┘ └──────────┘权限桥接(核心难题)
Section titled “权限桥接(核心难题)”子 Agent 在进程内运行,但权限对话框在父 Agent 的 UI 中。怎么办?
createInProcessCanUseTool() { // 方案 1(标准路径): 直接使用 Leader 的 React 对话框 // → Leader UI 显示 "[Worker: agent-name] 请求执行 git push" // → 用户批准/拒绝 // → 结果返回给 Worker
// 方案 2(Mailbox 回退): 当 Leader 不可用时 // → Worker 将权限请求写入 pending/ 目录 // → Leader 轮询 pending/ 目录(500ms 间隔) // → 处理后写入 resolved/ 目录 // → Worker 轮询 resolved/ 获取结果}5.2 跨进程权限同步
Section titled “5.2 跨进程权限同步”关键文件:utils/swarm/permissionSync.ts(928 行)
Worker 进程 Leader 进程┌──────────┐ ┌──────────┐│ 工具执行 │ │ REPL ││ ↓ │ │ UI ││ 需要权限 │ │ ││ ↓ │ │ ││ 写入 │──→ pending/perm-xxx.json │ ││ pending/ │ │ 扫描 ││ ↓ │ │ pending/ ││ 轮询 │ │ ↓ ││ resolved/│ │ 显示 ││ ↓ │←── resolved/perm-xxx.json│ 对话框 ││ 获取结果 │ │ ↓ ││ ↓ │ │ 写入 ││ 继续执行 │ │ resolved/│└──────────┘ └──────────┘权限请求数据结构:
type SwarmPermissionRequest = { id: string // perm-{timestamp}-{random} workerId: string // 发起请求的 Worker ID toolName: string // 工具名 toolUseId: string // 工具调用 ID input: Record<string, unknown> // 工具输入 status: 'pending' | 'resolved' feedback?: string // 用户反馈 permissionUpdates?: PermissionRule[] // 权限规则更新}5.3 团队文件管理
Section titled “5.3 团队文件管理”关键文件:utils/swarm/teamHelpers.ts
~/.claude/teams/{team-name}/├── config.json ← 团队配置文件│ {│ "members": [│ {│ "agentId": "reviewer@my-team",│ "tmuxPaneId": "...",│ "sessionId": "...",│ "mode": "auto",│ "color": "#ff6b6b"│ }│ ]│ }└── permissions/ ← 权限同步目录 ├── pending/ ← 待处理请求 └── resolved/ ← 已处理请求5.4 进度追踪
Section titled “5.4 进度追踪”type ProgressTracker = { toolUseCount: number // 工具使用次数 latestInputTokens: number // 最近一次输入 Token cumulativeOutputTokens: number // 累计输出 Token recentActivities: string[] // 最近 5 条活动(用于 UI 显示)}5.5 空闲通知
Section titled “5.5 空闲通知”Teammate 空闲时: 1. 检测到没有更多工具调用 2. 发送 TeammateIdle 通知给 Leader 3. Leader 可以: a. 发送新消息(SendMessage)继续任务 b. 等待其他 Teammate 完成 c. 终止 Teammate6. Worktree 隔离
Section titled “6. Worktree 隔离”关键文件:utils/worktree.ts
为什么需要 Worktree?
Section titled “为什么需要 Worktree?”多个 Agent 同时修改同一个代码库会产生文件冲突。Git Worktree 为每个 Agent 创建独立的工作树。
Worktree 生命周期
Section titled “Worktree 生命周期”创建: 1. getOrCreateWorktree(slug, sessionId) 2. git fetch origin (获取最新代码) 3. git worktree add -B claude-code/session-{id} .claude/worktrees/{slug}/ 4. 可选: sparse-checkout (只检出需要的文件) 5. 创建 symlinks → node_modules 等大目录(避免重复) 6. 触发 WorktreeCreate Hook
使用: - Agent 的 cwd 指向 worktree 路径 - 所有文件操作在隔离环境中进行 - 独立的 Git 分支
清理: 1. hasWorktreeChanges() → git diff + git status 2. 有变更 → 保留 worktree,返回路径和分支信息 3. 无变更 → git worktree remove --force + git branch -D 4. 触发 WorktreeRemove HookWorktree 目录结构
Section titled “Worktree 目录结构”repo-root/└── .claude/ └── worktrees/ └── {flattened-slug}/ ← 每个 Agent 一个目录 ├── .git ← 独立的 Git 工作树 ├── src/ ← 代码(独立副本) └── node_modules → ../../node_modules ← symlink(共享)// Slug 校验:防止路径遍历validateSlug(slug) { // 最大 64 字符 // 只允许 [a-zA-Z0-9._-] // 禁止 . 和 .. 段}
// 环境变量:防止凭据泄露env = { GIT_TERMINAL_PROMPT: '0', // 禁止交互式密码提示 GIT_ASKPASS: '', // 禁止密码对话框}stdin: 'ignore' // 不允许标准输入7. 三种 Agent 执行模式对比
Section titled “7. 三种 Agent 执行模式对比”| 维度 | 进程内 (InProcess) | 本地子进程 (Local) | 远程 (Remote) |
|---|---|---|---|
| 运行位置 | 同一进程 | 独立进程 | CCR 远程实例 |
| 状态共享 | 共享内存 | 文件系统通信 | HTTP/WebSocket |
| 权限桥接 | React 对话框直接访问 | Mailbox 文件轮询 | API 调用 |
| MCP 服务器 | 共享 + Agent 专属 | 独立 | 远程实例的 MCP |
| 文件隔离 | 共享(或 Worktree) | Worktree | 独立文件系统 |
| 生命周期 | AsyncLocalStorage | subprocess | HTTP session |
| 适用场景 | 快速任务、需要共享上下文 | 需要隔离的任务 | 跨机器协作 |
8. 架构洞察:多 Agent 协作的工程模式
Section titled “8. 架构洞察:多 Agent 协作的工程模式”模式 1: Context Isolation vs Context Sharing
Section titled “模式 1: Context Isolation vs Context Sharing”完全隔离(Remote) ←──────────────────→ 完全共享(Fork) 部分隔离(Worktree)Claude Code 提供了一个谱系,从完全隔离到完全共享,让用户根据任务需要选择。
模式 2: 权限冒泡
Section titled “模式 2: 权限冒泡”子 Agent(无 UI) ↓ 权限请求 冒泡 ↓父 Agent(有 UI) ↓ 显示对话框 用户决策 ↓ 结果传回子 Agent(继续执行)这解决了「子 Agent 没有 UI 但需要人工审批」的问题。
模式 3: Prompt Cache 经济学
Section titled “模式 3: Prompt Cache 经济学”成本对比: 普通模式: N 个子 Agent × 完整上下文 = N × 100% Token 成本 Fork 模式: 1 × 完整上下文 + N × 增量指令 ≈ 1 × 100% + N × 5%
假设父上下文 10K tokens,5 个子 Agent: 普通: 50K tokens(输入) Fork: 10K + 5×500 = 12.5K tokens(75% 节省!)模式 4: 故障域隔离
Section titled “模式 4: 故障域隔离”Worktree 隔离的价值: - 子 Agent A 在 worktree-a 中执行 `git reset --hard` → 不影响主仓库 - 子 Agent B 在 worktree-b 中修改 package.json → 不影响 Agent A - 执行失败 → 直接删除 worktree,零副作用模式 5: 渐进式自主性
Section titled “模式 5: 渐进式自主性”permissionMode 谱系: 'default' → 每次询问(最安全) 'auto' → ML 分类器自动判断(平衡) 'bypass' → 跳过大部分检查(高效) 'bubble' → 冒泡到父级(Fork 专用)子 Agent 可以有不同于父 Agent 的权限模式,实现「渐进式信任」。