委派工作的上下文隔离
问题
当 Agent 将工作委派给子 Agent 时,每一块共享状态都是潜在的碰撞点。继承了父级完整上下文的子 Agent 可能基于过时假设行动;共享父级工作目录的子 Agent 可能覆盖父级正在读取的文件;能递归生成自己子级的子 Agent 会造成指数级的上下文膨胀。没有显式的隔离边界,一个子 Agent 的错误爆炸半径会波及整个会话。
这些问题出现在任何支持委派的 Agent 运行时中 — coordinator 模式、fork 模式、或任何形式的并行子 Agent 工作。它们是多 Agent 架构的固有特性,不限于任何特定实现。
黄金法则
零继承是最安全的默认
在 coordinator 模式中委派工作时,只传递显式的 prompt。子 Agent 不继承对话历史、不继承积累的上下文、不继承会话状态。这是最窄的边界:子 Agent 只能基于被告知的内容行动,父级会话中的任何信息都不会意外泄露。代价是 prompt 必须自给自足 — 子 Agent 完成工作所需的一切都必须明确写出。
全继承 fork 必须是单层的
当子 Agent 需要父级的完整上下文(fork 模式)时,复制上下文但强制执行单层边界:被 fork 的 Agent 不能再次 fork。没有这个约束,递归 fork 会指数级放大上下文成本 — 每层复制上层的所有内容,总成本在 fork 树深度上是 O(2^n)。单层边界将成本保持为线性。
文件系统隔离防止路径碰撞
当子 Agent 修改文件时,它需要自己的仓库工作副本。共享工作目录会产生竞态条件:父级读取文件,子 Agent 修改它,父级下次读取就返回意外内容。文件系统隔离(通过 worktree、临时目录或写时复制克隆)给每个 Agent 自己的视图。必须注入路径转换,让 Agent 操作隔离副本而非共享原件。
选择能用的最窄边界
隔离边界决定了子 Agent 错误的爆炸半径。零继承 worker 只能损坏自己的输出。全继承 fork 可能产出与父级状态不一致的结果。共享文件系统的 Agent 可以损坏父级的工作目录。始终从最窄边界开始,只在子 Agent 确实需要更多上下文时才放宽。
适用场景
- Agent 将工作委派给子 Agent 或生成并发 worker。
- 子 Agent 修改父级正在使用的同一仓库中的文件。
- 委派的子 Agent 产出相互矛盾或与父级状态矛盾的结果。
- 需要防止子 Agent 失败损坏父级会话。
- 并行 Agent 需要在同一代码库上工作而不互相踩脚。
权衡
| 决策 | 收益 | 代价 |
|---|---|---|
| 零继承委派 | 干净的上下文边界,无意外泄露 | 子 Agent 必须仅从 prompt 中自给自足 |
| 全继承 fork(单层) | 子 Agent 拥有完整上下文应对复杂任务 | 上下文成本翻倍;必须强制执行禁止递归 fork 规则 |
| 通过 worktree 文件系统隔离 | Agent 之间无文件级竞态条件 | Worktree 创建和销毁开销;磁盘成本 |
| 路径转换注入 | Agent 透明地操作自己的副本 | 转换逻辑必须覆盖所有文件操作工具 |
| 不可变共享状态 | 跨 Agent 安全并发读取 | 状态更新需要新快照,不能就地修改 |
| 单层 fork 边界 | 线性成本,非指数级 | 需要进一步委派的 fork Agent 必须改用 coordinator 模式 |
实现模式
- 对于 coordinator 模式委派,将子 Agent prompt 构建为自包含文档。在 prompt 中包含所有必要的上下文、约束和输出格式要求 — 不要依赖继承的会话状态。
- 对于 fork 模式委派,在 fork 时复制父级上下文并强制执行单层边界。被 fork 的 Agent 应该无法调用 fork 机制本身。如果被 fork 的 Agent 需要进一步委派,它必须为自己的子 Agent 使用 coordinator 模式(零继承)。
- 当子 Agent 修改文件时,在 Agent 启动前创建隔离的文件系统上下文(worktree、临时目录或写时复制克隆)。注入路径转换,使每个文件操作工具都指向隔离副本。
- 子 Agent 完成后,通过受控的集成点将结果合并回父级工作目录 — 不要让子 Agent 直接写入共享文件系统。
- 将父级和子 Agent 之间共享的所有状态标记为不可变。如果子 Agent 需要传达状态变更,应该作为返回值返回,而不是就地修改共享对象。
- 注册清理处理器,在子 Agent 完成或失败时销毁隔离的文件系统。泄露的 worktree 或临时目录会累积浪费磁盘。
- 当多个子 Agent 并行工作在同一代码库上时,尽可能分配不重叠的文件集。文件系统隔离处理通用情况,但不重叠的分配可以在集成点防止合并冲突。
踩坑指南
递归 fork 产生指数级成本。 如果被 fork 的 Agent 可以再次 fork,上下文成本在每层翻倍。三层递归 fork 意味着原始上下文的八份副本。在委派机制层面强制单层边界,不要只靠约定。
路径转换必须覆盖所有文件操作工具。 如果隔离机制注入了 worktree 路径但某个文件操作工具绕过了转换,该工具就会写入共享的原始目录。每个接触文件系统的工具都必须经过转换层。
零继承 prompt 必须真正自包含。 一个常见的失败模式是构建了一个隐式依赖父级拥有但子 Agent 没有的上下文的子 Agent prompt。审查零继承 prompt 是否有隐藏依赖:假设特定工作目录的文件路径、对早期对话轮次的引用、或对可用工具的假设。
隔离 Agent 的结果合并可能冲突。 当两个并行 Agent 在各自的 worktree 中修改同一文件时,将两者合并回来会产生冲突。设计任务分配以最小化重叠,并为不可避免的重叠准备冲突解决策略。
Worktree 清理必须在所有退出路径上发生。 如果清理只在成功完成时运行,失败或被杀的子 Agent 会泄露其 worktree。在进程级关闭处理器上注册清理,而不仅仅在成功路径上。
不可变共享状态不意味着没有通信。 子 Agent 仍然可以向父级返回结果 — 约束是它们返回值而不是修改共享对象。父级通过受控的更新路径将返回的结果集成到自己的状态中。
Claude Code 实证
Claude Code 的委派系统在多种 Agent 协调模式中实现了这些隔离原则:
零继承作为协调工作的默认。 当运行时在 coordinator 模式中派发子 Agent 时,子 Agent 只接收其显式的任务 prompt。不继承对话历史、不继承积累的记忆、不继承父级会话状态。这是一个刻意的设计选择:子 Agent 的爆炸半径仅限于其自身输出。代价 — 每个子 Agent prompt 都必须完全自包含 — 被认为是值得的,因为它消除了一整类状态泄露 bug。
单层 fork 边界。 Fork 机制将父级的完整对话上下文复制给被 fork 的 Agent,但强制被 fork 的 Agent 不能自己调用 fork 机制。如果被 fork 的 Agent 需要进一步委派,它必须为自己的子任务使用 coordinator 模式(零继承)。这将总上下文成本保持在父级上下文的 2 倍,而非 2^n。设计明确拒绝递归 fork,因为指数级成本使其在任何实际工作负载中都不现实。
基于 worktree 的文件系统隔离。 当子 Agent 需要修改文件时,运行时创建一个 git worktree,给 Agent 自己的仓库工作副本。注入路径转换,使每个文件操作工具都指向 worktree 而非父级的工作目录。这消除了并发 Agent 之间的文件级竞态条件。Worktree 在所有退出路径上清理,包括失败和被杀,通过进程级清理处理器。
跨并发 Agent 的不可变共享状态。 父级和子 Agent 之间共享的应用状态被包装在深度不可变类型中。子 Agent 不能就地修改这个状态。当子 Agent 产出结果时,它们作为值返回,由父级通过受控的更新路径集成。这个设计防止了最隐蔽的并发 bug 类别:共享对象的静默就地修改导致不同 Agent 看到不一致的状态。
爆炸半径作为首要设计标准。 每种委派类型的隔离级别是通过问"这个子 Agent 最坏能破坏什么?"来选择的。零继承 worker 只能产出糟糕的输出。全继承 fork 可能产出与父级上下文不一致的输出。共享文件系统的 Agent 可以损坏父级的工作目录。运行时默认使用最窄边界,只在用例需要时才放宽。