Skip to content

第 14 章:Claude Code Agent 与编排系统

← 返回目录 | 上一章:Claude Code 概述与定位 | 下一章:Claude Code 工具系统 →


上一章我们从宏观角度了解了 Claude Code 的技术栈和架构布局。本章将深入其核心:查询循环、工具编排、任务系统和 Coordinator 模式。这些机制共同构成了 Claude Code 的"大脑",决定了它如何接收指令、调度工具、管理上下文,并最终完成复杂的编程任务。

14.1 查询循环(Query Loop):核心引擎

Claude Code 的所有智能行为都源自一个函数:query.ts 中的 query()。这个文件长达 1729 行,是整个系统最核心的模块。

14.1.1 AsyncGenerator 架构

query() 被设计为一个 AsyncGenerator 函数,它不是一次性返回结果,而是通过 yield 持续向调用方输出流式事件:

typescript
export async function* query(params: QueryParams):
  AsyncGenerator<StreamEvent | Message | TombstoneMessage> {
  const terminal = yield* queryLoop(params, consumedCommandUuids)
  return terminal
}

query() 本身是一个薄包装层,真正的逻辑在 queryLoop() 中。这个函数内部是一个 while (true) 无限循环,每一轮迭代对应一次与 Claude API 的交互。

14.1.2 循环状态机

每轮迭代共享一个可变的 State 对象:

typescript
type State = {
  messages: Message[]              // 完整的对话历史
  toolUseContext: ToolUseContext    // 工具执行上下文
  autoCompactTracking: ...         // 自动压缩追踪
  maxOutputTokensRecoveryCount: number  // 输出超限恢复计数
  turnCount: number                // 当前轮次
  transition: Continue | undefined // 上一轮为何继续(调试用)
  // ...
}

每轮迭代的执行流水线如下:

Snip(历史裁剪) → Microcompact(工具结果压缩)
  → Context Collapse(上下文折叠) → Autocompact(全量摘要)
    → API 调用 → 流式接收响应 → 工具执行 → 判断继续/终止

如果模型的响应包含 tool_use 块,循环继续下一轮;如果没有,循环终止并返回最终结果。

14.1.3 与 Opencode 和 OmO 的对比

Opencode 的 Agent 循环位于 session/processor.ts,逻辑类似但简洁得多:发送消息、等待响应、执行工具、重复。它没有多层压缩、没有流式工具执行、没有特性开关驱动的分支逻辑。

OmO 在 Opencode 的循环之上增加了异步后台任务层,但底层的单轮执行逻辑并未改变。Claude Code 则从根本上重新设计了这个循环,使其成为一个功能完备的状态机,内置了错误恢复、上下文管理和预算追踪等能力。

特性OpencodeOmOClaude Code
循环类型同步 while 循环同步循环 + 异步任务层AsyncGenerator 状态机
上下文压缩单次 compaction单次 compaction四层压缩流水线
工具执行逐个串行Agent 级并行工具级流式并行
错误恢复基础重试基础重试多策略恢复(reactive compact 等)
Token 预算内置预算追踪器

14.2 工具编排:流式并行执行

在传统的 AI Agent 实现中,工具执行通常是串行的:模型生成一个 tool_use 块,系统执行它,再把结果送回模型。Claude Code 打破了这个范式,引入了两层并行机制。

14.2.1 分区策略

toolOrchestration.ts 中的 partitionToolCalls() 函数负责将模型返回的一组 tool_use 块分区为多个批次(Batch):

typescript
type Batch = { isConcurrencySafe: boolean; blocks: ToolUseBlock[] }

分区规则非常直观:连续的只读工具(如文件读取、搜索)被归入同一个并发批次;遇到非只读工具(如文件写入、Shell 命令)则单独成为一个批次,串行执行。这种设计确保了读操作的高吞吐量,同时保证写操作的顺序一致性。

并发上限通过环境变量 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 控制,默认值为 10。

14.2.2 流式工具执行器

更激进的优化来自 StreamingToolExecutor(530 行)。传统做法是等模型的完整响应结束后再执行工具,而这个执行器在模型流式输出的过程中就开始执行已完成的工具块:

typescript
class StreamingToolExecutor {
  private tools: TrackedTool[] = []
  
  // 模型每输出一个完整的 tool_use 块,立刻加入执行队列
  addTool(block: ToolUseBlock, assistantMessage: AssistantMessage): void
  
  // 收集已完成工具的结果,按原始顺序输出
  async *getRemainingResults(): AsyncGenerator<MessageUpdate>
}

每个工具经历四个状态:queued → executing → completed → yielded。并发安全的工具可以与其他并发安全工具并行执行;非并发安全工具则获得独占访问权。

一个精巧的细节是"兄弟中止控制器"(sibling abort controller):它是 toolUseContext.abortController 的子控制器。当一个 Bash 工具报错时,其他正在执行的兄弟子进程会被立即终止,避免浪费资源。但这个中止不会向上传播到父控制器,所以不会结束当前轮次。

14.2.3 三系统的工具执行对比

Opencode 的工具执行是最朴素的形式:一个工具执行完毕,才执行下一个。OmO 通过后台任务系统实现了 Agent 级别的并行(多个 Agent 同时工作),但单个 Agent 内部的工具执行仍然是串行的。

Claude Code 的创新在于将并行下沉到了工具级别。模型说"同时读这 5 个文件",系统真的会并行读取,而不是排队等待。这种设计在处理大型代码库时的性能优势尤为明显。

14.3 七大任务类型

Claude Code 通过 tasks/types.ts 定义了一个统一的 TaskState 联合类型,涵盖了所有可能的计算单元。每种任务类型都有独立的生命周期管理和状态追踪。

14.3.1 LocalShellTask(local_bash)

最基础的任务类型。直接在本地终端执行 Shell 命令,管理子进程的生命周期。支持前台/后台切换,用户可以将一个长时间运行的 Shell 任务放到后台继续执行。

14.3.2 LocalAgentTask(local_agent)

本地后台智能体。它拥有自己独立的查询循环(通过 runAgent() 启动),在后台自主执行任务。LocalAgentTask.tsx(683 行)实现了细致的进度追踪:

typescript
type ProgressTracker = {
  toolUseCount: number           // 工具调用次数
  latestInputTokens: number      // 最新输入 token(累计值)
  cumulativeOutputTokens: number // 累计输出 token
  recentActivities: ToolActivity[] // 最近 5 个工具活动
}

每个工具活动(ToolActivity)不仅记录工具名和输入参数,还通过 ActivityDescriptionResolver 生成人类可读的描述(如"Reading src/foo.ts"),这些信息会实时显示在 UI 的任务进度面板中。

14.3.3 RemoteAgentTask(remote_agent)

远程智能体任务,在 Anthropic 的云端环境(CCR,Claude Code Remote)中执行。这是 Claude Code 最复杂的任务类型之一,RemoteAgentTask.tsx 长达 856 行。

它支持五种远程任务子类型:

子类型用途
remote-agent通用远程 Agent
ultraplan远程规划,支持浏览器审批流程
ultrareview远程代码审查
autofix-pr自动修复 PR 问题
background-pr后台 PR 处理

远程任务通过 WebSocket 轮询(pollRemoteSessionEvents)获取执行状态。RemoteTaskCompletionChecker 模式允许为不同子类型注册自定义的完成检测逻辑。任务的元数据会持久化到磁盘,确保会话恢复时不会丢失正在运行的远程任务。

14.3.4 InProcessTeammateTask(in_process_teammate)

这是 Claude Code 最独特的任务类型。与 LocalAgentTask 在独立进程中运行不同,InProcessTeammate 运行在同一个 Node.js 进程中,通过 AsyncLocalStorage 实现隔离。

每个队友都有团队感知的身份标识:

typescript
type TeammateIdentity = {
  agentId: string    // 如 "researcher@my-team"
  agentName: string  // 如 "researcher"
  teamName: string
  planModeRequired: boolean
  parentSessionId: string
}

这种设计的优势是通信延迟极低(进程内函数调用),劣势是所有队友共享同一个进程的内存空间。源码注释中记录了一个真实的生产事故:某个会话(9a990de8)在 2 分钟内启动了 292 个 Agent,内存峰值达到 36.8GB。为此,团队引入了 TEAMMATE_MESSAGES_UI_CAP = 50 的消息上限,只在 AppState 中保留最近 50 条消息用于 UI 显示,完整对话历史则存储在磁盘上。

InProcessTeammate 还支持计划模式审批(awaitingPlanApproval)和空闲/活跃的生命周期切换,使其在需要人工介入审查的工作流中也能流畅运作。

14.3.5 其他任务类型

LocalWorkflowTask:执行预定义的本地工作流序列,通常是针对特定场景(如代码重构、文档生成)优化的多步骤指令。

MonitorMcpTask:监控 MCP 服务器的连接状态和工具可用性,确保外部工具源的稳定集成。

DreamTask:最富想象力的一种任务类型,用于"记忆整理"。它是一个后台运行的记忆巩固子 Agent,分为 starting(启动)和 updating(更新记忆文件)两个阶段。DreamTask 会回顾历史会话,提炼出值得长期记住的信息,并写入 MEMORY.md 文件。它追踪已审阅的会话数、修改的文件列表和最近 30 轮的对话摘要。

14.3.6 任务系统对比

Opencode 只有一种任务形态:通过 Task 工具同步调用子 Agent,父 Agent 阻塞等待结果。OmO 在此基础上引入了后台任务和 category 分类系统,但任务类型本身没有分化。

Claude Code 的七种任务类型体现了一种"为每种计算场景定制运行时"的理念。本地 Shell、本地 Agent、远程 Agent、进程内队友,各自有最适合的执行策略和资源管理方式。这种精细的分化使得系统能在不同场景下做出最优的调度决策。

14.4 Coordinator 模式:多 Worker 编排

Coordinator 模式是 Claude Code 最接近 OmO Sisyphus 编排器的功能,但它的实现路径截然不同。

14.4.1 触发与切换

当环境变量 CLAUDE_CODE_COORDINATOR_MODE 被设为真值时,Claude Code 的主 Agent 从"全能执行者"变为"纯编排者"。这个切换是运行时的,不需要重启:

typescript
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

系统还会追踪会话的模式状态。当恢复一个旧会话时,matchSessionMode() 会自动将当前模式切换到会话创建时的模式,避免 Coordinator 会话在普通模式下被恢复(或反过来)。

14.4.2 Coordinator 的行为规范

进入 Coordinator 模式后,主 Agent 的系统提示词被完全替换为 getCoordinatorSystemPrompt() 生成的专用提示词。这段提示词定义了严格的行为规范:

角色定位:Coordinator 只做三件事:与用户沟通、指挥 Worker、综合结果。它不直接使用文件读写工具,所有实际工作都委派给 Worker。

可用工具:仅限 AgentTool(创建 Worker)、SendMessageTool(向已有 Worker 发送后续指令)和 TaskStopTool(终止 Worker)。

工作流阶段

阶段执行者目标
ResearchWorker(并行)调查代码库,理解问题
SynthesisCoordinator阅读 Worker 发现,制定实施方案
ImplementationWorker按方案修改代码,提交
VerificationWorker测试验证改动是否正确

其中 Synthesis 阶段是 Coordinator 最核心的职责。系统提示词中明确要求:不允许写"based on your findings"这类偷懒的委派语句。Coordinator 必须阅读 Worker 的研究结果,理解问题本质,然后用具体的文件路径、行号和修改方案来指导下一步工作。

14.4.3 Worker 上下文隔离

一个关键的设计约束是:Worker 看不到 Coordinator 与用户的对话。每次创建 Worker 或发送后续消息时,提示词必须是自包含的,包含 Worker 完成任务所需的全部信息。

Worker 可用的工具列表由 ASYNC_AGENT_ALLOWED_TOOLS 常量定义,并过滤掉内部工具(TeamCreate、TeamDelete、SendMessage、SyntheticOutput)。如果有 MCP 服务器连接,Worker 也能访问对应的 MCP 工具。

Coordinator 模式还支持 Scratchpad 目录,这是一个共享的临时文件目录,Worker 可以在其中读写文件而无需权限确认。这为跨 Worker 的知识传递提供了一个轻量级的持久化通道。

14.4.4 Continue vs Spawn 决策

系统提示词中详细规定了何时继续使用现有 Worker(通过 SendMessageTool),何时创建新 Worker:

  • Continue:Worker 之前探索的正好是需要修改的文件;纠正失败或延续近期工作
  • Spawn fresh:研究范围广但实现范围窄(避免拖入无关上下文);验证他人代码(需要新鲜视角);第一次实现方向完全错误(避免锚定效应)

决策依据是上下文重叠度:重叠高则继续,重叠低则重新创建。

14.4.5 与 OmO Sisyphus 的对比

OmO 的 Sisyphus 编排器和 Claude Code 的 Coordinator 模式解决的是同一个问题:如何让一个 AI 指挥其他 AI 高效协作。但两者的实现哲学大相径庭:

维度OmO SisyphusClaude Code Coordinator
编排逻辑嵌入在系统提示词中的行为指令独立的运行时模式,替换整个系统提示词
Worker 类型按 Category 分类(visual、ultrabrain 等),每类对应不同模型统一的 Worker 类型,使用默认模型
探索策略专用的 Explore/Librarian 侦察 AgentWorker 既能探索也能实现
知识传递通过 session_id 延续对话上下文通过 Scratchpad 目录或 SendMessage 继续
计划审查Metis(分析需求)→ Momus(审查计划)Coordinator 自身负责 Synthesis 阶段

简言之,OmO 倾向于"专人专事",为每种职能配备专属 Agent;Claude Code 倾向于"通用 Worker + 精确指令",让 Coordinator 的提示词质量决定最终效果。

14.5 上下文压缩层级

长时间的编程会话会不断积累对话历史,最终超出模型的上下文窗口。Claude Code 为此设计了一套多层级的压缩体系,每一层针对不同的场景和粒度。

14.5.1 第一层:Snip(历史裁剪)

特性开关 HISTORY_SNIP 控制。snipCompact.ts 负责对过早的历史消息进行轻量级裁剪。它是最快的压缩手段,直接移除旧消息,返回释放的 token 数量(tokensFreed)。裁剪后如果 token 数降到阈值以下,后续更重的压缩步骤可以跳过。

14.5.2 第二层:Microcompact(工具结果压缩)

针对工具调用结果的精细压缩。工具返回的结果(如完整的文件内容、Shell 输出)通常占据大量 token,但对后续推理的价值递减。Microcompact 按 tool_use_id 逐条压缩这些结果,保留关键信息。

它还有一个缓存感知的变体(特性开关 CACHED_MICROCOMPACT),在压缩时考虑 Anthropic API 的提示缓存机制,避免因内容变化导致缓存失效。

14.5.3 第三层:Context Collapse(上下文折叠)

特性开关 CONTEXT_COLLAPSE 控制。这是一种介于 Microcompact 和 Autocompact 之间的策略。它将一组相关消息折叠为摘要,但以"提交日志"的方式管理这些折叠操作,使得折叠可以在多轮迭代间持久化。applyCollapsesIfNeeded() 在每轮迭代时重放折叠日志,确保投影视图的一致性。

Context Collapse 在 Autocompact 之前运行。如果折叠就能将 token 数控制在阈值内,Autocompact 就无需触发,从而保留更细粒度的上下文信息。

14.5.4 第四层:Autocompact(全量摘要)

当 token 数超过 上下文窗口 - 13000(AUTOCOMPACT_BUFFER_TOKENS) 时触发。autoCompact.ts 会调用 compactConversation() 将整个对话历史压缩为一段简洁的摘要。

为防止摘要本身过长,系统预留了 20000 个 token 的输出空间。如果 Autocompact 连续失败 3 次(MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES),触发断路器停止重试,避免在不可恢复的情况下浪费 API 调用。

14.5.5 第五层:Reactive Compact(响应式压缩)

最后一道防线。特性开关 REACTIVE_COMPACT 控制。它并非按阈值提前触发,而是在 API 返回 prompt_too_long 错误时才启动。这意味着前四层的预防措施都未能阻止超限,系统需要紧急响应。

14.5.6 压缩体系对比

Opencode 和 OmO 都只有单一的 compaction 机制:一个专用的 compaction Agent 将对话压缩为摘要。这种方式简单直接,但颗粒度粗,且只有一种触发条件。

Claude Code 的五层压缩体系体现了"渐进式降级"的思想:优先使用轻量级手段(Snip、Microcompact),保留尽可能多的原始上下文;只有在轻量手段不够时才动用重型压缩(Autocompact);最后保留一个紧急恢复机制(Reactive Compact)。这种设计在保持上下文质量和控制 token 成本之间取得了精妙的平衡。

14.6 Agent 运行器(runAgent)

所有子 Agent 的实际执行都汇聚到 tools/AgentTool/runAgent.ts 这个 973 行的核心函数。无论是 LocalAgentTask、InProcessTeammateTask 还是 Coordinator 模式下的 Worker,最终都通过 runAgent() 启动。

14.6.1 隔离与递归

runAgent() 为每个子 Agent 创建独立的执行上下文:

  • 独立的 AbortController(可以单独终止子 Agent 而不影响父级)
  • 独立的工具集合(根据 Agent 定义和权限模式筛选)
  • 独立的权限模式(Worker 的权限不继承父 Agent 的临时授权)
  • 独立的 transcript 路径(每个子 Agent 的对话记录保存在单独的文件中)

最关键的是,runAgent() 本身也是一个 AsyncGenerator,它内部调用的正是 query() 函数。这构成了一个递归架构:主查询循环通过工具调用启动子 Agent,子 Agent 运行自己的查询循环,子 Agent 甚至可以再启动孙 Agent。整个系统是自相似的。

14.6.2 参数丰富度

runAgent() 的参数列表反映了 Claude Code 对子 Agent 行为的精细控制能力:

  • agentDefinition:Agent 的定义(系统提示词、工具、模型)
  • model:可选的模型覆盖
  • maxTurns:最大轮次限制
  • worktreePath:Git worktree 隔离路径(支持在独立分支中工作)
  • allowedTools:工具白名单(替换而非追加父级权限)
  • contentReplacementState:内容替换状态(用于恢复中断的 Agent 会话)
  • preserveToolUseResults:是否保留工具结果(InProcessTeammate 需要,因为用户可以查看其 transcript)

与 Opencode 的 Task 工具相比,差异非常明显。Opencode 的 Task 工具只需三个参数:Agent 名称、提示词、和一个可选的附件。Claude Code 的 runAgent() 则提供了近 20 个参数,涵盖了从资源隔离到缓存策略的方方面面。

14.7 小结

Claude Code 的 Agent 与编排系统是一个精心设计的多层架构:

  1. 查询循环是一切的基础,一个带状态的 AsyncGenerator 无限循环
  2. 工具编排将并行下沉到工具级别,通过流式执行最大化吞吐量
  3. 七大任务类型为不同计算场景提供定制化的运行时
  4. Coordinator 模式将主 Agent 提升为纯编排者,形式化了多 Worker 协作流程
  5. 五层压缩体系确保长时间会话的上下文质量
  6. runAgent 递归架构使整个系统具备无限嵌套的子 Agent 能力

如果说 Opencode 的 Agent 系统是一辆手动挡汽车(简单、可控、透明),OmO 给它加上了自动变速箱和巡航控制(后台任务、分类调度),那么 Claude Code 就是一辆自动驾驶汽车(流式并行、多层压缩、形式化编排)。三者各有适用场景,但 Claude Code 在系统复杂度和工程投入上显然领先一个量级。

下一章我们将深入 Claude Code 的工具系统,看看那 50 多个工具是如何通过统一的 buildTool 工厂函数构建,以及权限模型如何在安全性和便利性之间取得平衡。


← 返回目录 | 上一章:Claude Code 概述与定位 | 下一章:Claude Code 工具系统 →