Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

第20章:Agent 派生与编排

定位:本章分析 Claude Code 如何通过子 Agent、Fork 和协调者三种模式实现多 Agent 派生与编排。前置依赖:第3章、第4章。适用场景:想了解 CC 如何派生子 Agent(Subagent/Fork/Coordinator)的读者,或想构建多 Agent 系统的开发者。

为什么需要多 Agent

单个 Agent Loop 的上下文窗口是有限资源。当任务规模超过单次对话所能承载的信息量——例如"调查这个 bug 的根因、修复它、跑测试、写 PR"——单 Agent 要么被迫在上下文中塞满中间结果,要么不断做压缩丢失细节。更本质的问题是:单 Agent 无法并行,而软件工程任务天然适合分治。

Claude Code 提供了三种递进的多 Agent 模式,从轻量到重量分别是:子 Agent(Subagent)Fork 模式协调者模式(Coordinator Mode)。它们共享同一个入口——AgentTool,但在上下文继承、执行模型和生命周期管理上有根本差异。本章将逐层解剖这三种模式,以及围绕它们构建的验证 Agent 和工具池组装逻辑。

队友系统(Teams)详见第20b章,Ultraplan 远程规划详见第20c章。


交互式版本点击查看 Agent 派生动画 — 观看主 Agent 如何派生 3 个子 Agent 并行工作,上下文传递与隔离。

20.1 AgentTool:统一的 Agent 派生入口

所有 Agent 派生都通过同一个工具完成。AgentTooltools/AgentTool/AgentTool.tsx 中定义,它的 name'Agent'(第 226 行),别名为旧的 'Task'(第 228 行)。

输入 Schema 的动态组合

AgentTool 的输入 Schema 不是静态的——它根据 Feature Flag 和运行时条件动态组合:

// tools/AgentTool/AgentTool.tsx:82-88
const baseInputSchema = lazySchema(() => z.object({
  description: z.string().describe('A short (3-5 word) description of the task'),
  prompt: z.string().describe('The task for the agent to perform'),
  subagent_type: z.string().optional(),
  model: z.enum(['sonnet', 'opus', 'haiku']).optional(),
  run_in_background: z.boolean().optional()
}));

基础 Schema 包含五个字段。当多 Agent 特性(Agent Swarms)启用时,还会合并 nameteam_namemode 字段(第 93-97 行);isolation 字段支持 'worktree'(所有构建)或 'remote'(内部构建);当后台任务被禁用或 Fork 模式启用时,run_in_background 字段会被 .omit() 移除(第 122-124 行)。

这种 Schema 动态组合有一个重要的设计意图:模型看到的参数列表精确反映它当前可以使用的能力。当 Fork 模式开启时,模型不会看到 run_in_background,因为 Fork 模式下所有 Agent 都自动后台化(第 557 行),模型无需也不应显式控制。

AsyncLocalStorage 上下文隔离

当多个 Agent 在同一进程中并发运行时(例如用户按 Ctrl+B 将一个 Agent 放入后台后立即启动另一个),如何隔离它们的身份信息?答案是 AsyncLocalStorage

// utils/agentContext.ts:24
import { AsyncLocalStorage } from 'async_hooks'

// utils/agentContext.ts:93
const agentContextStorage = new AsyncLocalStorage<AgentContext>()

// utils/agentContext.ts:108-109
export function runWithAgentContext<T>(context: AgentContext, fn: () => T): T {
  return agentContextStorage.run(context, fn)
}

源码注释(agentContext.ts 第 17-21 行)直接解释了为什么不用 AppState

When agents are backgrounded (ctrl+b), multiple agents can run concurrently in the same process. AppState is a single shared state that would be overwritten, causing Agent A's events to incorrectly use Agent B's context. AsyncLocalStorage isolates each async execution chain, so concurrent agents don't interfere with each other.

AgentContext 是一个判别联合类型(discriminated union),通过 agentType 字段区分两种上下文:

上下文类型agentType用途关键字段
SubagentContext'subagent'Agent 工具派生的子 AgentagentId, subagentName, isBuiltIn
TeammateAgentContext'teammate'队友 Agent(Swarm 成员)agentName, teamName, planModeRequired, isTeamLead

两种上下文都有 invokingRequestId 字段(第 43-49 行、第 77-83 行),用于追踪是谁派生了这个 Agent。consumeInvokingRequestId() 函数(第 163-178 行)实现了"稀疏边"语义:每次 spawn/resume 只在第一个 API 事件上发出一次 invokingRequestId,之后返回 undefined,避免重复标记。


20.2 三种 Agent 模式

模式一:标准子 Agent

这是最基本的模式。模型在调用 Agent 工具时指定 subagent_type,AgentTool 从已注册的 Agent 定义中查找匹配项,然后启动一个全新的对话。

路由逻辑在 AgentTool.tsx 第 322-356 行:

// tools/AgentTool/AgentTool.tsx:322-323
const effectiveType = subagent_type
  ?? (isForkSubagentEnabled() ? undefined : GENERAL_PURPOSE_AGENT.agentType);

subagent_type 未指定且 Fork 模式关闭时,默认使用 general-purpose 类型。

内置 Agent 定义在 builtInAgents.ts 中注册(第 45-72 行),包括:

Agent 类型用途工具限制模型
general-purpose通用任务:搜索、分析、多步骤操作所有工具默认
verification验证实现正确性禁止编辑工具继承
Explore代码探索--
Plan规划任务--
claude-code-guide使用指南--

子 Agent 的关键特征是上下文隔离:它从零开始,只看到父 Agent 传入的 prompt。系统提示词也是独立生成的(第 518-534 行)。这意味着子 Agent 不知道父 Agent 的对话历史——它就像"一个刚走进房间的聪明同事"。

模式二:Fork 模式

Fork 模式是一个实验性特性,通过 feature('FORK_SUBAGENT') 构建时门控和运行时条件共同控制:

// tools/AgentTool/forkSubagent.ts:32-39
export function isForkSubagentEnabled(): boolean {
  if (feature('FORK_SUBAGENT')) {
    if (isCoordinatorMode()) return false
    if (getIsNonInteractiveSession()) return false
    return true
  }
  return false
}

Fork 模式与标准子 Agent 的根本区别在于上下文继承。Fork 子进程继承父 Agent 的完整对话上下文和系统提示词:

// tools/AgentTool/forkSubagent.ts:60-71
export const FORK_AGENT = {
  agentType: FORK_SUBAGENT_TYPE,
  tools: ['*'],
  maxTurns: 200,
  model: 'inherit',
  permissionMode: 'bubble',
  source: 'built-in',
  baseDir: 'built-in',
  getSystemPrompt: () => '',  // 未使用——继承父级的系统提示词
} satisfies BuiltInAgentDefinition

注意 model: 'inherit'getSystemPrompt: () => ''——Fork 子进程使用父 Agent 的模型(保持上下文长度一致)和父 Agent 已渲染的系统提示词(保持字节完全一致以最大化提示词缓存命中)。

提示词缓存共享

Fork 模式的核心价值在于提示词缓存共享buildForkedMessages() 函数(forkSubagent.ts 第 107-164 行)构造的消息结构确保所有 Fork 子进程产生字节相同的 API 请求前缀:

  1. 保留父 Agent 完整的 assistant 消息(所有 tool_use 块、thinking、text)
  2. 为每个 tool_use 块构造相同的占位 tool_result(第 142-150 行,使用固定文本 'Fork started — processing in background'
  3. 只在最后追加一个 per-child 的指令文本块
[...历史消息, assistant(所有 tool_use 块), user(占位 tool_result..., 指令)]

只有最后一个文本块因 child 不同而不同,最大化缓存命中率。

递归 Fork 防护

Fork 子进程的工具池中保留了 Agent 工具(为了缓存一致性),但在调用时会被拦截(第 332-334 行):

// tools/AgentTool/AgentTool.tsx:332-334
if (toolUseContext.options.querySource === `agent:builtin:${FORK_AGENT.agentType}`
    || isInForkChild(toolUseContext.messages)) {
  throw new Error('Fork is not available inside a forked worker.');
}

检测机制有两层:主检查通过 querySource(抗压缩——即使消息被 autocompact 重写也不会丢失),备用检查扫描消息中的 <fork-boilerplate> 标签(第 78-89 行)。

模式三:协调者模式(Coordinator Mode)

协调者模式通过环境变量 CLAUDE_CODE_COORDINATOR_MODE 激活:

// coordinator/coordinatorMode.ts:36-41
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

在这个模式下,主 Agent 变成一个不直接编码的协调者,它的工具集缩减为指挥工具:Agent(派生 Worker)、SendMessage(向 Worker 发送后续指令)、TaskStop(停止 Worker)等。Worker 拥有实际的编码工具。

协调者的系统提示词(coordinatorMode.ts 第 111-368 行)是一份详尽的编排规程,定义了四阶段工作流:

阶段执行者目的
ResearchWorker(并行)调查代码库,定位问题
Synthesis协调者阅读结果,理解问题,编写实现规格
ImplementationWorker按规格修改代码,提交
VerificationWorker测试变更是否正确

提示词中最强调的原则是**"永远不要委托理解"**(第 256-259 行):

Never write "based on your findings" or "based on the research." These phrases delegate understanding to the worker instead of doing it yourself.

getCoordinatorUserContext() 函数(第 80-109 行)生成 Worker 工具上下文信息,包括 Worker 可用的工具列表和 MCP 服务器列表。当 Scratchpad 功能启用时,还会告知协调者可以使用一个共享目录进行跨 Worker 的知识持久化(第 104-106 行)。

补充:/btw Side Question 作为无工具 Fork

/btw 不是第四种 Agent 模式,但它是理解 Claude Code 能力矩阵时一个非常重要的侧信道特例。命令定义本身是 local-jsximmediate: true,因此它可以在主线程仍在流式输出时保持一个独立 overlay,不会被普通工具 UI 覆盖。

执行路径上,/btw 不是走主 Loop 插队,而是 runSideQuestion() 调用 runForkedAgent():它继承父会话的 cache-safe 前缀和当前对话上下文,但通过 canUseTool 显式拒绝所有工具,把 maxTurns 限制为 1,并设置 skipCacheWrite,避免为这个一次性后缀写入新的缓存前缀。换句话说,/btw 是一个"完整上下文 + 零工具 + 单轮回答"的能力降维版本。

从能力矩阵看,它与标准子 Agent 形成了一种对称关系:

  • 标准子 Agent:保留工具能力,但通常从新上下文开始
  • /btw:保留上下文能力,但去掉工具和多轮执行

这种对称性很重要,因为它揭示了 Claude Code 的委托系统不是一个二元开关,而是在"上下文、工具、回合数"三个维度上独立裁剪。用户要的并不总是"再开一个能干所有事的 Agent",有时只是"用当前上下文回答一个无副作用的侧问题"。

三种模式对比

graph TB
    subgraph 标准子Agent["标准子 Agent"]
        SA1["上下文: 全新对话"]
        SA2["提示词: Agent 定义自带"]
        SA3["执行: 前台/后台"]
        SA4["缓存: 无共享"]
        SA5["递归: 允许"]
        SA6["场景: 独立小任务"]
    end

    subgraph Fork模式["Fork 模式"]
        FK1["上下文: 完整继承父级"]
        FK2["提示词: 继承父级"]
        FK3["执行: 强制后台"]
        FK4["缓存: 共享父级缓存"]
        FK5["递归: 禁止"]
        FK6["场景: 需要上下文的并行探索"]
    end

    subgraph 协调者模式["协调者模式"]
        CO1["上下文: Worker 独立"]
        CO2["提示词: 协调者专用"]
        CO3["执行: 强制后台"]
        CO4["缓存: 无共享"]
        CO5["递归: Worker 不可再派生"]
        CO6["场景: 复杂多步骤项目"]
    end

    AgentTool["AgentTool 统一入口"] --> 标准子Agent
    AgentTool --> Fork模式
    AgentTool --> 协调者模式

    style AgentTool fill:#f9f,stroke:#333,stroke-width:2px
维度标准子 AgentFork 模式协调者模式
上下文继承无(全新对话)完整继承无(Worker 独立)
系统提示词Agent 定义自带继承父级协调者专用提示词
模型选择可覆盖继承父级不可覆盖
执行方式前台/后台强制后台强制后台
缓存共享共享父级缓存
工具池独立组装继承父级Worker 独立组装
递归派生允许禁止Worker 不可再派生
门控方式始终可用构建+运行时构建+环境变量
适用场景独立小任务需要上下文的并行探索复杂多步骤项目

20.4 验证 Agent

验证 Agent 是内置 Agent 中设计最精致的一个。它的系统提示词(built-in/verificationAgent.ts 第 10-128 行)长达约 120 行,堪称一份"如何进行真正验证"的工程规范。

核心设计原则

验证 Agent 有两个明确声明的失败模式(第 12-13 行):

  1. 验证回避(Verification avoidance):面对检查时找理由不执行——阅读代码、叙述测试步骤、写 "PASS",然后继续
  2. 被前 80% 迷惑:看到漂亮的 UI 或通过的测试套件就倾向于通过,没注意到一半按钮不起作用

严格的只读约束

验证 Agent 被明确禁止修改项目:

// built-in/verificationAgent.ts:139-145
disallowedTools: [
  AGENT_TOOL_NAME,
  EXIT_PLAN_MODE_TOOL_NAME,
  FILE_EDIT_TOOL_NAME,
  FILE_WRITE_TOOL_NAME,
  NOTEBOOK_EDIT_TOOL_NAME,
],

但它可以在临时目录(/tmp)写入临时测试脚本——这个权限足够编写临时的测试工具但不会污染项目。

VERDICT 判定

验证 Agent 的输出必须以严格格式的判定结尾(第 117-128 行):

判定含义
VERDICT: PASS验证通过
VERDICT: FAIL发现问题,包含具体错误输出和复现步骤
VERDICT: PARTIAL环境限制导致无法完全验证(非"不确定")

PARTIAL 仅用于环境限制(没有测试框架、工具不可用、服务器无法启动),不能用于"我不确定这是不是 bug"。

对抗性探测

验证 Agent 的提示词要求至少运行一个对抗性探测(第 63-69 行):并发请求、边界值、幂等性、孤儿操作等。如果所有检查都只是"返回 200"或"测试套件通过",说明只确认了快乐路径,不算真正的验证。


20.7 工具池的独立组装

每个 Worker 的工具池是独立组装的,不继承父 Agent 的限制(第 573-577 行):

// tools/AgentTool/AgentTool.tsx:573-577
const workerPermissionContext = {
  ...appState.toolPermissionContext,
  mode: selectedAgent.permissionMode ?? 'acceptEdits'
};
const workerTools = assembleToolPool(workerPermissionContext, appState.mcp.tools);

唯一的例外是 Fork 模式:Fork 子进程使用父级的精确工具数组(useExactTools: true,第 631-633 行),因为工具定义的差异会破坏提示词缓存。

MCP 服务器的等待与验证

Agent 定义可以声明所需的 MCP 服务器(requiredMcpServers)。AgentTool 在启动前会检查这些服务器是否可用(第 369-409 行),并在 MCP 服务器仍在连接中时等待最多 30 秒(第 379-391 行),带有提前退出逻辑——如果某个必需的服务器已经失败,就不再等待其他服务器了。


20.8 设计洞察

为什么三种模式而非一种? 这源于一个根本性的权衡:上下文共享 vs. 执行隔离。标准子 Agent 提供最大隔离但没有上下文;Fork 提供最大上下文共享但不能递归;协调者模式在中间——Worker 隔离但协调者保持全局视图。不存在一种通用方案能同时满足所有场景。

平面团队结构的设计哲学。禁止队友派生队友不仅是技术约束——它反映了一种组织原则:在一个有效的团队中,协调应该集中在一个节点(Leader),而不是形成任意深度的委托链。这与软件工程中"避免过深的调用栈"的直觉一致。

验证 Agent 的"反模式清单"设计。验证 Agent 的提示词显式列出了 LLM 作为验证者时的典型失败模式(第 53-61 行),并要求它"认出自己的合理化借口"。这种 meta-cognition 提示是对 LLM 固有弱点的工程补偿——不是期望模型不犯这些错误,而是让模型知道它倾向于犯这些错误。


用户能做什么

利用多 Agent 模式提升工作效率:

  1. 善用子 Agent 做独立调查。当需要在不干扰主对话上下文的情况下完成一个独立子任务(如"查找这个 API 的所有调用方"),让模型启动一个子 Agent 是最佳选择。子 Agent 有自己的上下文窗口,完成后返回摘要,不会污染主对话。

  2. 理解协调者模式的四阶段流程。如果你的组织启用了协调者模式(CLAUDE_CODE_COORDINATOR_MODE=true),了解其 Research → Synthesis → Implementation → Verification 的四阶段流程有助于更好地与之协作。特别注意:协调者不会直接编码,它只负责理解问题和分配任务。

  3. 利用验证 Agent 进行质量把关。当完成复杂变更后,可以显式要求运行验证 Agent。它的只读约束和对抗性探测设计使其成为可靠的"第二双眼睛"。

  4. Worktree 隔离保护主分支。当 Agent 使用 isolation: 'worktree' 时,所有修改都在临时 git worktree 中进行。无变更的 worktree 会自动清理,有变更的则保留分支——这意味着你可以放心让 Agent 尝试实验性修改。


20.9 远程执行:Bridge 架构

前面的章节分析了 Agent 派生的三种模式——子 Agent、Fork、协调者——它们都运行在本地进程中。但 Claude Code 不仅仅是一个本地 CLI 工具。Bridge 子系统(restored-src/src/bridge/,共 33 个文件)将 Agent 的执行能力延伸到网络边界之外,使得用户可以从 claude.ai 的 Web 界面远程触发本地机器上的 Agent 会话。如果说 Fork 是"本地进程级别的 Agent 分裂",那么 Bridge 就是"跨网络的 Agent 投射"。

三组件架构

Bridge 的设计遵循经典的客户端-服务器-工作者模式。整个系统由三个组件构成:

flowchart LR
    subgraph Web ["claude.ai Web 界面"]
        User["用户浏览器"]
    end

    subgraph Server ["Anthropic 服务端"]
        API["Sessions API<br/>/v1/sessions/*"]
        Env["Environments API<br/>环境注册 & 工作分发"]
    end

    subgraph Local ["本地机器"]
        Bridge["Bridge 主循环<br/>bridgeMain.ts"]
        Session1["Session Runner #1<br/>子进程 claude --print"]
        Session2["Session Runner #2<br/>子进程 claude --print"]
    end

    User -->|"创建会话"| API
    API -->|"分发工作"| Env
    Bridge -->|"轮询工作<br/>pollForWork()"| Env
    Bridge -->|"注册环境<br/>registerBridgeEnvironment()"| Env
    Bridge -->|"派生子进程"| Session1
    Bridge -->|"派生子进程"| Session2
    Session1 -->|"NDJSON stdout"| Bridge
    Session2 -->|"NDJSON stdout"| Bridge
    Bridge -->|"心跳 & 状态上报"| Env
    User -->|"权限决策"| API
    API -->|"control_response"| Bridge
    Bridge -->|"stdin 转发"| Session1

Bridge 主循环bridgeMain.ts)是核心编排者。它通过 runBridgeLoop() 函数(第 141 行)启动一个持久的轮询循环:向服务端注册本地环境,然后反复调用 pollForWork() 获取新的会话请求。每当收到新工作,Bridge 使用 SessionSpawner 派生一个子 Claude Code 进程来执行实际的 Agent 任务。

Session RunnersessionRunner.ts)负责管理每个子进程的生命周期。它通过 createSessionSpawner() 函数(第 248 行)创建一个工厂,每次调用 .spawn() 都会启动一个新的 claude --print 子进程,配置为 --input-format stream-json --output-format stream-json 的 NDJSON 流模式(第 287-299 行)。子进程的 stdout 通过 readline 逐行解析,提取工具调用活动(extractActivities)和权限请求(control_request)。

JWT 认证流程

Bridge 的认证基于 JWT(JSON Web Token)的双层体系:外层是 OAuth 令牌用于环境注册和管理 API,内层是会话入口令牌(Session Ingress Token,前缀 sk-ant-si-)用于子进程的实际推理请求。

jwtUtils.ts 中的 createTokenRefreshScheduler()(第 72 行)实现了一个精巧的令牌续期调度器。它的核心逻辑是:

  1. 解码 JWT 有效期decodeJwtPayload() 函数(第 21 行)剥离 sk-ant-si- 前缀后,解码 Base64url 编码的 payload 段,提取 exp 声明。注意这里不验证签名——Bridge 只需要知道过期时间,验证由服务端完成。

  2. 提前续期。调度器在令牌过期前 5 分钟(TOKEN_REFRESH_BUFFER_MS,第 52 行)主动发起刷新,避免使用过期令牌导致请求失败。

  3. 世代计数防竞态。每个 session 维护一个 generation 计数器(第 94 行),schedule()cancel() 都会递增世代号。当异步的 doRefresh() 完成时,它会检查当前世代是否与启动时一致(第 178 行)——如果不一致,说明该 session 已被重新调度或取消,刷新结果应该丢弃。这个模式有效避免了并发刷新导致的孤立计时器问题。

  4. 失败重试与熔断。连续失败 3 次(MAX_REFRESH_FAILURES,第 58 行)后停止重试,避免在令牌源彻底不可用时无限循环。每次失败后等待 60 秒再重试。

Session 转发与权限代理

Bridge 最精妙的设计在于权限的远程代理。当子进程需要执行敏感操作(如写文件、运行 shell 命令)时,它通过 stdout 发出 control_request 消息。sessionRunner.ts 的 NDJSON 解析器检测到这类消息后(第 417-431 行),调用 onPermissionRequest 回调将请求转发给服务端。

bridgePermissionCallbacks.ts 定义了权限代理的类型契约:

// restored-src/src/bridge/bridgePermissionCallbacks.ts:3-8
type BridgePermissionResponse = {
  behavior: 'allow' | 'deny'
  updatedInput?: Record<string, unknown>
  updatedPermissions?: PermissionUpdate[]
  message?: string
}

用户在 Web 界面上做出的 allow/deny 决策通过 control_response 消息回传到 Bridge,Bridge 再通过子进程的 stdin 转发给 Session Runner。这形成了一个完整的权限回路:子进程请求 → Bridge 转发 → 服务端 → Web 界面 → 用户决策 → 原路返回。

令牌更新也通过 stdin 完成。SessionHandle.updateAccessToken()sessionRunner.ts 第 527 行)将新令牌封装为 update_environment_variables 消息写入子进程 stdin,子进程的 StructuredIO 处理器会直接设置 process.env,使后续的认证头自动使用新令牌。

容量管理

Bridge 必须处理多个并发会话的容量问题。types.ts 定义了三种派生模式(SpawnMode,第 68-69 行):

模式行为适用场景
single-session单会话,结束即退出默认模式,最简单
worktree每个会话独立 git worktree多会话并行,互不干扰
same-dir所有会话共享工作目录轻量但有冲突风险

bridgeMain.ts 的默认最大并发会话数为 32(SPAWN_SESSIONS_DEFAULT,第 83 行),并通过 GrowthBook Feature Gate(tengu_ccr_bridge_multi_session,第 97 行)控制多会话功能的渐进式发布。

capacityWake.ts 实现了容量唤醒原语(第 28 行的 createCapacityWake())。当所有会话槽位已满时,轮询循环进入休眠。两种事件会唤醒它:(a) 外部 abort 信号(关机),或 (b) 某个会话完成释放了槽位。这个模块将之前 bridgeMain.tsreplBridge.ts 中重复的唤醒逻辑抽象为共享原语——正如其注释所说:"both poll loops previously duplicated byte-for-byte"(第 8 行)。

每个会话还有超时保护:默认 24 小时(DEFAULT_SESSION_TIMEOUT_MStypes.ts 第 2 行)。超时的会话会被 Bridge 的看门狗主动 kill,先发 SIGTERM,宽限期后再发 SIGKILL。

与 Agent 派生的关系

Bridge 是本章前半部分讨论的 Agent 派生机制在网络维度上的自然延伸。如果我们把三种 Agent 模式和 Bridge 放在同一张光谱上:

维度子 AgentFork协调者Bridge
执行位置同进程子进程子进程群远程子进程
上下文继承完整快照摘要传递无(独立会话)
触发来源LLM 自主LLM 自主LLM 自主用户通过 Web
权限模型继承父级继承父级继承父级远程代理回传
生命周期父级管理父级管理协调者管理Bridge 轮询循环管理

Bridge 会话本质上是一个没有上下文继承的远程子 Agent——它使用完全相同的 claude --print 执行模式,只是会话的创建、权限决策和生命周期管理都跨越了网络边界。sessionRunner.ts 中的 createSessionSpawner() 与 AgentTool 的子进程派生在概念上同构,区别仅在于触发源和通信信道。

这种设计的优雅之处在于:无论 Agent 在本地还是远程执行,其核心的 Agent Loop(详见第3章)完全不需要改变。Bridge 只是在 Loop 的外围包裹了一层网络传输和认证协议,保持了内核的简洁性。