第 十八 章 Agent 架构实操 深入学习 · 交互式 含 QA 测试

多 Agent 并行开发时的文件冲突,到底该怎么解

💡 受管 Git Worktree:Task / Claim / Binding 三条独立状态线。
任务所有权不等于文件系统隔离。第 18 章为每个项目任务建立受管 Git Worktree,并在每次工具执行前把可信工作目录解析到当前 claim 对应的 Worktree。手动与自动认领走同一 TaskClaimService。
本章进度
0%
1 本章要掌握的目标
  • 创建先 reserve 再执行 Git;失败保留 reserved binding 与 pending Task。
  • 手动 / 自动认领共用同一 TaskClaimService;自动只认领 active binding 的 ready 任务。
  • 每项工具在 Hook、权限、handler 前重新解析可信 Execution Context(cwd)。
  • 失效 claim 明确失败,绝不回落主 workspace。
  • remove 只接受 completed + 登记一致 + clean + branch tip 已进入显式 integration ref;失败转 needs_review。
2 核心知识点
为什么文件锁不是答案

锁把并行写变成有序覆盖,不能给两项并行工作提供独立版本。Git Worktree 提供物理目录隔离并复用同一个 Git 对象库。

repository-root/
├ .git/
├ .agent_tutorial/{tasks.sqlite3, worktrees/}
│   ├ alice/   branch: wt/alice
│   └ bob/     branch: wt/bob
└ source files   integration ref 所在主工作目录
Binding 是独立状态机

reserved → active → kept → removed;active 可失败转 needs_review。绑定创建不会把 Task 从 pending 推进 in_progress。

reserved -> active -> kept ---------> removed
                   |                  ^
                   +-> needs_review --+
                   |
                   +-----------------> removed
先 reserve 再调用 Git

先持久化意图(SQLite reserved + event),再 git worktree add;成功后凭读回证据才迁移 active。顺序反了会让「目录建了但没登记」这类孤儿副作用比多余状态记录严重得多。Git 子进程用 execFile 参数数组,不经过 shell;validateRepository 要求 workspace 正好是仓库根,子目录不行。

验证 Git 根 → 解析 integration_ref 为 baseline commit
→ 写入 reserved binding + reserve event
→ git worktree add -b wt/{name} {path} {baseline}
→ 验证新目录 HEAD/分支
→ 迁移 active + create event
cwd 是每次执行的可信上下文

扩展不可变 ToolContext(taskId/claimToken/worktreeName/executionScope)。每次工具调用重新执行 ToolContextProvider.resolve()(在 schema 校验后、Hook 与权限前),Hook 看到的就是最终执行上下文;解析失败报成对的 tool_context_error,handler 零调用。executionScope 是每回合新建的空冻结对象,用 WeakMap 映射到 claim token,生命周期正好一轮;不用 process.chdir()。

ToolContext {
  workspace, identity, idempotencyKey?,
  taskId?, claimToken?, worktreeName?, executionScope?,
}
同一 assistant 回复:
  call1 claim_task(A) → scope 绑定 claim token
  call2 write_file(...) → 重新解析已得 A 的 Worktree 路径
Remove 必须先证明可以删

依次证明:Task completed;binding 为 active/kept/needs_review;受管路径是 Git 登记的 root;共享 common dir;HEAD 仍是 wt/{name};git status 空(非零退出与空串区别对待,Git 报错不泄露 stderr);branch tip 与 integration ref 可解析;merge-base --is-ancestor 成功。全部成立才 detach + branch -d + worktree remove(不用 -D/--force);任一条不过转 needs_review 并带 review_reason,已是 kept/needs_review 的不重复迁移。

完成 proof 后才:
  git switch --detach <tip-sha>
  git branch -d wt/{name}
  git worktree remove <managed-path>
不使用 -D / --force;失败转入 needs_review
3 机制流程
1
create_worktree

task_id/name/integration_ref;reserved → active,Task 仍 pending。

2
claim(手动/自动同路)

只接受 active binding;claimNext 只选 active binding 的 ready 任务。

3
工具执行前解析 cwd

resolve ToolContext → PreToolUse → 权限 → handler(写进 Worktree)。

4
keep / remove

keep 显式保留(active→kept);remove 安全证明后清理。

4 术语表
WorktreeBindingtask 与隔离 Git 工作区/分支的持久绑定(五态);binding 迁移与审计事件同一事务,审计写失败回滚迁移。
append-only 审计数据库 trigger 拒绝对审计表的 UPDATE/DELETE;只追加。
Execution Context每次工具执行解析出的可信作用域(cwd/claim);resolve 在 Hook 之前,失败时 handler 零调用。
needs_review无法证明安全或 Git 失败时保留供人工处理的状态,必须带 review_reason。
integration_ref先 rev-parse --verify 解析成不可变 40 位 commit 再建 Worktree;只有其 tip 包含分支顶端才允许自动清理。
executionScope每回合新建的冻结对象,WeakMap 映射 claim token,生命周期正好一轮。
工具差量Lead 多三个 worktree 工具(create/remove/keep),Teammate 与 Subagent 一个都没有;组合根用引用相等强制三侧共用同一 TaskClaimService。
5 QA 测试环节(自测题)
已完成 0 / 6 · 答对 0
Q1. 两个 worker 写同名文件不互相覆盖靠?
Q2. 创建 Worktree 失败时保留什么?
Q3. 应该把 worktree 塞进 Task 字段吗?
Q4. 出租者声称完成任务但 lease 已过期?
Q5. 自动认领会怎样处理未绑定任务?
Q6. remove_worktree 需要证明什么?
6 验证与实验
  • npm run typecheck && npm run test:ch18:59 个测试文件(含前 17 章累积,全程离线);Lead 多 create/remove/keep 三个 worktree 工具,Teammate 与 Subagent 零新增。
  • 验证隔离、自动认领跳过未绑定、失效 token 不回落到主目录、clean+integrated 才安全清理。
  • 在独立 Git 仓库根目录运行:会看到写入只出现在各自 Worktree。