把并行 agent 收进一个可合并的交付面:子代理边界实战
并行 agent 最常见的翻车,不是模型不够聪明,而是两个人同时碰同一块地。一个在改接口,一个顺手重命名共享类型;另一个刚好在补测试,最后合进来的代码看着都合理,组合起来却炸。多开窗口没有天然的吞吐增益,先把交付面切开才有。
Claude Code 的 subagent 是独立上下文里的专用执行者,可以配置各自的系统提示、工具权限和权限模式;它返回摘要给主会话,而不是把搜索日志全塞回主上下文。[1] 这个结构适合把“查清楚”和“改文件”拆开。但独立上下文不等于独立文件系统:如果两个 agent 都能写同一工作区,它们照样会互相覆盖。所以并行策略的第一条不是“拆成更多任务”,而是给每个任务一份明确的文件所有权。
先画写入边界,再下任务#
把一次改动按产物切,而不是按看起来顺手的功能词切。比如“给支付页加优惠码”,不要分成“前端 agent”“后端 agent”。更稳的分法是:A 只读,找调用链并列出风险;B 只改 src/pricing/ 的 UI 和单测;C 只改 src/coupons/ 的服务与集成测试;主代理保留路由、共享类型、依赖升级和最终合并。每张任务卡都写清四项:允许写哪些路径、禁止碰哪些路径、验收命令、交付给主代理的摘要格式。
这会牺牲一点“顺手修一下”的自由,换来的是可预测性。共享文件没有唯一 owner 时,任何一个 agent 的小修都可能让另一个 agent 的假设过期。把共享文件留给主代理,是一个简单但管用的规则:主代理掌握全局意图,也负责决定接口究竟长什么样。
工具权限要和交付物对齐#
官方把 Explore 定义为只读的代码库探索 agent,Write 和 Edit 被拒绝;它适合搜入口、追依赖、盘点测试,不适合顺手提交修改。[1] 先派只读 agent 把“哪些文件会受影响、现有测试跑什么”写成短报告,再派写入 agent 做局部实现,主上下文会干净很多,也少一次探索途中误改文件的机会。
自定义子代理文件可以放在项目的 .claude/agents/,也可以放在用户目录;前者随项目走,后者对机器上的项目可用。[1] 团队流程里优先把项目专用的边界写进仓库。这样同事和 CI 里启动的 Claude 都拿到同一套约束,不靠某个人记得在聊天里补一句“别改这个目录”。
别把权限限制当装饰。子代理只需要读代码,就不给 Bash、Edit、Write;只需要修改一个目录,就在提示里列出路径,并把共享目录列为禁止项。工具白名单不能替代路径规则,却能砍掉很多意外动作。官方也把“限制子代理可用工具”列为 subagent 的用途之一。[1]
快速上手:两读一写一集成#
先在仓库创建一个只读勘察 agent:
<!-- .claude/agents/impact-scout.md -->
---
name: impact-scout
description: 找出改动影响面;只在需要调用链、测试入口和风险清单时使用
tools: Read, Grep, Glob
model: haiku
---
只读工作。输出:1) 涉及文件;2) 共享文件;3) 可运行的验收命令;4) 未确定项。
不要提出未经代码证实的结论。
接着把写入任务发成可验收的合同,而不是一句“把功能做完”:
只修改 src/coupons/ 与 tests/coupons/。
不得修改路由、共享类型、锁文件和 package.json。
完成后运行 pnpm test -- coupons,并报告:修改文件、命令退出码、仍需主代理处理的共享接口。
主代理收到报告后,先检查 git diff -- src/coupons tests/coupons,再处理共享接口并跑全量验证。若任务确实需要隔离副本,Claude Code 的子代理支持 isolation: worktree;官方说明它会在临时 git worktree 中运行,未产生改动时会自动清理。[1] 这适合两个写入任务必须并行、又不该共享未提交改动的场景。它不是免验收卡:最终仍要由一个集成者把变更放到同一分支,跑一次完整测试。
用 hook 把越界变成硬错误#
提示写“不要改 package.json”还不够。Claude Code 的 PreToolUse hook 在工具调用执行前触发,可以阻止调用;hook 输入会以 JSON 送到命令,规则可按工具名和条件筛选。[2] 对高冲突仓库,可以让写入 agent 的项目配置在编辑共享文件时直接拒绝。下面的规则只示意边界,路径名单应按项目维护:
{
"hooks": {
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-shared-files.sh"
}]
}]
}
}
脚本从 stdin 读取 tool_input.file_path,命中 package.json、共享类型目录或锁文件时向 stderr 写原因并以退出码 2 结束。官方指南将这种做法用于保护 .env、锁文件和 .git/,并说明退出码 2 会阻止编辑。[3] 先用一条伪造 JSON 在终端验证脚本,再开启 hook;规则误伤时,agent 至少会得到清楚的替代路径,而不是安静地失败。
并行的目标不是同时让更多 agent 写代码,而是同时消化互不重叠的不确定性。勘察交给只读 agent,局部实现交给有边界的写入 agent,共享决定留给主代理。最后那次全量测试,谁都不能替你省掉。
Sources#
[1] https://code.claude.com/docs/en/sub-agents — Claude Code: Create custom subagents [2] https://code.claude.com/docs/en/hooks — Claude Code: Hooks reference [3] https://code.claude.com/docs/en/hooks-guide — Claude Code: Automate actions with hooks