昨天说了怎么让 AI 先交验证命令。今天说另一件更容易翻车的事:同时开两个 AI 改同一个仓库。
我试过最蠢的一次是这样的:左边窗口让 AI 改用户服务的入参校验,右边窗口让它给同一个服务加审计日志。两个都跑得很顺,各自跑完都告诉我「改完了,测试通过」。合并的时候 git 没报冲突------因为它们改的是同一个文件里的不同函数。
问题是:加审计日志那个把错误处理统一包了一层,改校验那个在同一个函数里加了自己的 try/catch。单独看都对,合起来变成报错被吞了两次,前端永远收到 200。
并行开发的冲突,很多时候不在 git 里,在语义里。
一、动手前先划三类边界
我现在开多个任务之前,会先在纸上(真的是纸上)写下三列:
| 边界类型 | 具体做法 | 目的 |
|---|---|---|
| 文件级归属 | 每个任务列出「允许改的文件」,交叉即冲突 | 让冲突在开工前暴露 |
| 共享文件 | 类型定义、常量、路由表、配置,只允许一个任务改 | 这几类文件最容易产生语义冲突 |
| 同一验证命令 | 所有任务合并前跑同一套命令 | 保证判定标准一致 |
第一列最有用。两个任务的文件清单一旦有交集,就别并行,改成排队------排队的成本远低于事后拆语义冲突的成本。
二、共享文件才是真正的雷区
按我的经验,并行任务里真正打架的通常不是业务代码,而是下面这几类:
· 类型定义 / interface:一个任务加字段,另一个删字段,git 能自动合,类型却对不上
· 常量表:枚举值改了一个,另一个任务还在用旧值
· 路由 / 菜单配置:两处都往同一个数组里 push,顺序错了但能跑
· i18n 文案:key 不同但语义重复,后期没人敢删
所以我的规则很死:**共享文件在并行期间,只能有一个人改。**另一个人需要加东西,先写到临时地方(比如自己的注释或者 issue 里),等第一轮合并完再统一加。
三、用 worktree 隔离,别用同一个目录
两个 AI 在同一个工作目录里跑,最危险的不是冲突,是互相看到对方的中间状态。
我在同一个目录里跑过两个 agent:A 正在改 user_service.py,B 跑了一次全量测试,测到一半 A 把文件存了,B 的测试结果就变成了混合态。B 得出「我的改动让测试挂了」的结论,然后开始瞎改。
现在的做法是每个任务一个 worktree:
git worktree add ../wt-user-a feature/user-a
git worktree add ../wt-user-b feature/user-b
一个目录一个分支一个 agent,互不可见。合并的顺序按「谁动共享文件谁先合」来定,先合的负责把共享文件那部分改动做完,后者只做 rebase。
四、合并时先跑命令,再看 diff
顺序很重要。我现在是反过来的:
-
先 rebase 到主干
-
跑那套固定的验证命令(跟昨天那篇里的写法一样)
-
命令全过,才去看 diff 有没有语义问题
先看 diff 容易被「看起来整洁」骗过去。昨天那个 offset 的例子就是------diff 越干净,越容易让人跳过验证。
五、什么任务适合并行,什么不适合
| 适合并行 | 不适合并行 |
|---|---|
| 不同模块的新功能 | 同一个函数的多处修改 |
| 前端页面 + 后端接口(约定好契约) | 改公共类型定义 |
| 补测试 + 修文档 | 重构 + 加功能同时进行 |
| 两套独立脚本 | 迁移数据库 + 改业务逻辑 |
判断标准就一句:**两个任务的改动,会不会在同一个函数里相遇。**会,就排队;不会,才并行。
下一步
如果你今天就要开两个 AI 任务,先做一件事:把它们各自「允许改的文件」列出来,写在任务描述的第一行。有交集的部分,砍掉一个放到下一轮。
下一篇写改动预算------为什么我要求 AI 一次改动不超过 3 个文件,以及超了之后返工率为什么会翻倍。
这是「AI 改代码怎么验收」系列的第 2 篇。上一篇讲验证命令,这一篇讲并行边界,后面还有改动预算和回读复核。系列目录我放在主页置顶了,从第 1 篇看起更顺。