Skip to main content

执行链路总览

一条 Agent(prompt="修复 bug") 调用的完整路径:

子 Agent 的三种路径

AgentTool.call() 根据 subagent_type 参数和 Fork 实验开关,走三条不同的路径:
Fork 实验的门控函数 isForkSubagentEnabled() 需要同时满足三个前提:FORK_SUBAGENT feature flag 已启用、当前不在 Coordinator 模式中、且不是非交互式会话。任一条件不满足时,省略 subagent_type 会静默降级为 General-purpose Agent,而非触发 Fork。
Fork 路径的设计核心是 Prompt Cache 共享:所有 fork 子进程共享父 Agent 的完整 assistant 消息(所有 tool_use 块),用相同的占位符 tool_result 填充,只有最后一个 text 块包含各自的指令。这使得 API 请求前缀字节完全一致,最大化缓存命中。

Fork 递归防护

Fork 子进程保留 Agent 工具(为了 cache-identical tool defs),但通过两道防线防止递归 fork:
  1. querySource 检查(压缩安全):context.options.querySource === 'agent:builtin:fork'
  2. 消息扫描(降级兜底):检测 <fork-boilerplate> 标签

模型解析优先级

子 Agent 的模型选择遵循严格的优先级链(src/utils/model/agent.ts):
其中 inherit 不是简单的模型传递——它经过 getRuntimeMainLoopModel() 解析,确保 plan mode 下的 opusplan→Opus 等运行时映射正确生效。当 Agent 指定的模型族(如 haiku)与父模型同族时,直接复用父模型的精确 ID,避免跨 provider 降级。

命名 Agent 的工具池独立组装

内置 Agent

系统预定义了几个内置 Agent(packages/builtin-tools/src/tools/AgentTool/builtInAgents.ts),各有明确的职责和模型配置: 用户还可通过 .claude/agents/ 目录或 settings 定义自定义 Agent,作用域优先级为:managed settings > CLI --agents > 项目级 .claude/agents/ > 用户级 ~/.claude/agents/ > plugin。 命名 Agent(包括 General-purpose 回退)不继承父 Agent 的工具限制——它的工具池完全独立组装。Fork 子进程则通过 useExactTools: true 直接继承父 Agent 的原始工具池,以保持 Prompt Cache 中工具定义的字节一致性。 命名 Agent 的工具池组装逻辑:
关键设计决策:
  • 权限模式独立:子 Agent 使用 selectedAgent.permissionMode(默认 acceptEdits),不受父 Agent 当前模式的限制
  • MCP 工具继承appState.mcp.tools 包含所有已连接的 MCP 工具,子 Agent 自动获得
  • Agent 级 MCP 服务器runAgent() 中的 initializeAgentMcpServers() 可以为特定 Agent 额外连接专属 MCP 服务器

工具过滤的 resolveAgentTools

runAgent.ts:508 在工具组装后进一步过滤:
resolveAgentTools() 会根据 Agent 定义中的 tools 字段过滤可用工具,将 ['*'] 映射为全量工具。

Hook 事件

子 Agent 支持 Agent 定义 frontmatter 和全局 settings.json 两种级别的 Hook:

Worktree 隔离机制

isolation: "worktree" 参数让子 Agent 在独立的 git worktree 中工作(AgentTool.tsx:863):
Worktree 生命周期:
  1. 创建:在 .git/worktrees/ 下创建独立工作副本
  2. CWD 覆盖runWithCwdOverride(worktreePath, fn) 让所有文件操作在 worktree 中执行
  3. 路径翻译:Fork + worktree 时注入路径翻译通知(buildWorktreeNotice
  4. 清理cleanupWorktreeIfNeeded):
    • Hook-based worktree → 始终保留
    • 有变更 → 保留,返回 worktreePath
    • 无变更 → 自动删除

生命周期管理:同步 vs 异步

异步 Agent(后台运行)

run_in_background=trueselectedAgent.background=true、或系统判定应强制异步(如 assistantForceAsyncproactiveModule 激活)时,Agent 立即返回 async_launched 状态:
如果异步 Agent 提供了 name 参数,还会注册到 agentNameRegistry,支撑 SendMessage 工具通过名称路由到该 Agent。 异步 Agent 获得独立的 AbortController,不与父 Agent 共享——用户按 ESC 取消主线程不会杀掉后台 Agent。

同步 Agent(前台运行)

同步 Agent 的关键特性是 可后台化AgentTool.tsx:1107):
在 agentic loop 的每次迭代中,系统用 Promise.race 竞争下一条消息和后台化信号:
后台化后,前台迭代器被终止(agentIterator.return()),新的 runAgent()isAsync: true 重新启动,当前台的输出文件继续写入。

结果回传格式

mapToolResultToToolResultBlockParam() 根据状态返回不同格式: 对于一次性内置 Agent(Explore、Plan),当不存在 worktree 隔离时,<usage> 块和 agentId 尾部被省略——每周节省约 1-2 Gtok 的上下文窗口。存在 worktree 时仍需返回 worktreePathworktreeBranch 信息。

MCP 依赖的等待机制

如果 Agent 声明了 requiredMcpServerscall() 会等待这些服务器连接完成(AgentTool.tsx:576):
早期退出条件:任何必需服务器进入 failed 状态时立即停止等待。工具可用性通过 mcp__ 前缀工具名解析(mcp__serverName__toolName)判断。等待结束后如果仍有必需服务器未就绪,call() 会抛出错误并明确列出缺失的服务器名称。

适用场景

并行研究

多个 fork 子进程并行搜索不同方向,共享 Prompt Cache 前缀,只有指令不同

专业委派

使用命名 Agent(Explore/Plan/verification)执行专业任务,受限工具集 + 独立权限

隔离实验

isolation: "worktree" 在独立工作副本中尝试方案,不影响主分支

后台构建

run_in_background: true 启动长时间构建/测试任务,主 Agent 继续工作