工程与管理Multi-Agent工程教训

110 个测试全过,但代码丢了——多 Agent 并发编辑事故复盘

今天遇到一个诡异的 bug:commit message 里写着 “shadow riskGate bypass”,但部署到线上的代码里根本没有这个逻辑。110 个测试全过,打包部署一气呵成,结果 feature 不工作。

排查后发现是多 Agent 并发编辑同一个文件的典型事故。


事故回放

背景:我在多个终端窗口里跑了多个 AI Coding Agent,并行处理同一个项目的不同 feature。

时间线:

  1. Session ASgrGridManager 模块里加了 shadow riskGate bypass 逻辑,写了测试,commit message 写好了
  2. Session B 同时也在改 SgrGridManager 模块,加的是 depth expansion、async queue 等改动
  3. Session B 的构建覆盖了 Session A 的产物,部署上线
  4. 最终 commit 包含了两个 session 的 message 合并,但 代码只有 Session B 的

结果:commit 421e221 声称有 bypass,实际没有。重启后等了 3 分钟等 depth WS 热启动,shadow 触发逻辑却始终不生效。


为什么测试没发现?

因为两个 session 的测试覆盖的是各自的改动范围。Session A 的测试验证了 bypass 逻辑正确,Session B 的测试验证了 depth expansion 正确。但没有人跑合并后的集成测试——两个改动在同一个文件里,合并后的代码是 Session B 的单方面版本。

这就像广告系统的检索漏斗:召回模块和排序模块各自单元测试通过,但没人测全链路,上线后 CTR 暴跌才反应过来。


本质是什么

并发写入冲突。和分布式系统里两个 writer 同时写同一个 key 没有区别。

Session A: read v1 → edit → write v2 (bypass logic)
Session B: read v1 → edit → write v2' (depth expansion)
                                  ↑ 覆盖了 v2

AI Coding Agent 的 Edit 工具基于文件快照做字符串替换。如果 Session B 读到的是 Session A 写入之前的版本,它的替换操作就会静默回退 A 的改动。没有冲突检测,没有 merge 提示——就像两个 git push --force 同时执行。


元结构映射:广告系统里的同类问题

广告系统里这种并发冲突太常见了:

场景冲突类型后果
OCPC 出价模型同时更新两个 trainer 写同一份模型文件线上出价参数错乱
索引增量构建两个 builder 写同一份倒排索引索引空洞,召回为空
正排数据更新两个 writer 更新同一广告主的 budget超播

广告系统的解法是什么?写入串行化——要么用锁,要么用版本号 CAS。同一个 partition 同一时刻只有一个 writer。

代码编辑也一样。多个 Agent 并发改同一个文件,必须有一个”排他写入”的机制。


怎么做

1. 部署前验证 artifact 内容

测试通过不等于代码在构建产物里。部署前:

# 验证关键模块是否包含预期逻辑
strings target/app | grep riskGate
# 或者反编译确认关键方法是否存在

2. 同一文件不要并行改

如果多个 Agent 都涉及同一个文件,串行执行。先让一个完成并 commit,另一个 rebase 后再开始。

3. 关键改动的 commit 要独立

不要让两个 feature 混在一个 commit 里。commit message 写了两个东西,出问题时根本不知道是哪一个丢了。

4. 部署后做一次 smoke test

不是跑全量测试,而是针对刚部署的 feature 做一次端到端验证。这次事故里,如果部署后立刻检查 shadow 是否触发,就能在 1 分钟内发现问题,而不是等了 3 分钟 WS 热启动后才困惑。


教训

测试全过 + 部署成功 ≠ 代码在线上。

AI Coding Agent 让并发开发的门槛降到极低——开几个窗口就能并行推进。但代码合并的冲突检测没有跟上。Agent 不会告诉你”刚才有人改了同一个文件”,它只会静默覆盖。

一句话:多 Agent 并发编辑同一个文件时,最后写入的 wins,而且没有冲突提示。唯一的安全网是部署后的 artifact 验证。