AI协作开发中最容易反复犯的七类错误

最近我在用多个 AI Agent 并行推进一个客户端改造项目。
这个项目目前还没有完成,只实现了部分基础能力,后面还有不少功能需要继续开发。之所以现在就做复盘,不是为了总结项目成果,而是因为前一阶段已经暴露出了一些值得警惕的问题。
如果等项目全部结束后再复盘,这些问题很可能已经在后续开发中重复很多次了。
所以这里先做一次阶段性总结,把具体项目中出现的问题抽象出来,作为后续继续使用 AI 写代码时的检查清单。
一、需求不明确时,AI 会自动补全需求
人看到一个不完整的需求时,通常会找产品、业务方或者开发负责人确认。
AI 不一定会这样做。
当需求缺少目标用户、运行平台、核心场景或者非目标时,AI 很容易根据自己的理解补全缺失部分。而且它补出来的内容通常看起来很合理,所以一开始不容易发现问题。
比如一个需求只说“基于现有客户端开发新功能”,但没有明确首批用户、目标平台和最终交付形态。AI 可能会同时考虑跨平台、外部用户和完整产品体验,最后把一个内部工具设计成更复杂的通用产品。
代码可能没有问题,但解决的不是当前最需要解决的问题。
所以 AI Coding 开始前至少要写清楚:
- 给谁使用;
- 在什么环境运行;
- 最重要的使用场景是什么;
- 当前阶段明确不做什么;
- 本轮完成后用户能够看到什么。
需求中的空白不会一直保持空白。你不填写,AI 就会替你填写。
二、架构约束没有写成红线,AI 会选择最容易完成的方案
AI 很擅长完成边界清楚的独立任务。
问题是,最容易独立完成的方案,不一定是长期正确的方案。
例如,我们希望在一个现有开源客户端上扩展业务能力。真正的要求是保留原来的模型、会话、设置和升级能力,只通过公开扩展机制增加功能。
但如果 Prompt 里只写“基于这个客户端开发”,AI 可能会把它理解成“参考这个客户端的设计”,然后重新实现一个更容易控制的新客户端。
从当前任务看,重新实现可能更快;从长期维护看,这会带来两套客户端、两套功能和非常高的升级成本。
所以架构要求不能只写成建议,必须写成红线:
- 哪些现有能力必须保留;
- 哪些目录禁止修改;
- 只能通过哪些接口扩展;
- 哪些模块必须继续留在服务端;
- 哪些方案即使能运行也不能接受。
AI 会优化“如何把当前任务做完”。人要负责约束“哪些完成方式是不允许的”。
三、没有先检查事实,AI 会在错误的前提下高效工作
AI Coding 中一个很危险的问题是:Agent 可以在错误前提下工作很久,而且效率很高。
它可以快速写代码、补测试、生成报告,直到很晚才发现目标仓库不对、已有实现被忽略,或者当前代码和文档中的描述根本不是一回事。
前一阶段有一次,我们根据目录位置判断代码写错了项目。后来检查 Git worktree 才发现,物理目录虽然放在另一个项目下面,Git 归属其实没有错。
继续检查后又发现,目标仓库里已经有一批未跟踪的实现。之前只查看了 Commit 和分支,所以误以为这些功能不存在,差点让 Agent 从零重写。
这类问题不能靠“让 AI 更认真一点”解决,而要靠固定的 Preflight:
git rev-parse --show-toplevel
git branch --show-current
git status
git worktree list
除此之外,还要检查:
- tracked 文件;
- modified 文件;
- untracked 文件;
- ignored 文件;
- 当前代码和需求文档是否一致;
- 已有实现是否覆盖了部分需求。
先确认事实,再做判断。
如果前提错了,后面的代码、测试和报告越完整,返工成本反而越高。
四、AI 很容易追求局部最优,而不是最终产品结果
AI 喜欢明确、可计算、能判断成功或失败的任务。
测试通过、TypeScript 没有报错、Gate 返回绿色,这些都非常明确。相比之下,“这个功能是否真的能让用户完成工作”更模糊。
因此,当任务没有明确产品结果时,Agent 很容易把大量时间花在测试、报告和局部质量上。
例如,一个功能还没有真正接入客户端,只是在独立脚本里执行成功,Agent 就开始运行多轮 Gate、生成验收报告。报告越来越完整,但用户打开客户端后仍然看不到这个功能。
这得从优化目标上改,光补测试没用。
后续我会把任务分成两个层次。
第一层是用户结果:
- 用户从哪里进入;
- 做什么操作;
- 能看到什么结果;
- 失败后如何恢复。
第二层才是工程验证:
- 单元测试;
- Typecheck;
- 集成测试;
- 安全负例;
- 发布 Gate。
第二层只是用来证明第一层。前面那个功能,独立脚本跑通以后应该先把功能接进客户端,而不是继续刷 Gate 和报告。
在产品纵切还没有形成之前,大部分时间应该继续推进功能,而不是不断扩大测试范围。
五、多 Agent 并行如果没有依赖关系,只是在并行制造冲突
多 Agent 最容易产生的错觉是:同时启动的 Agent 越多,开发速度越快。
实际上,并行是否有效,主要取决于任务之间是否真的独立。
如果多个 Agent 同时修改路由、配置、公共类型和工具注册,它们并不是在并行完成项目,而是在分别生成几套互不兼容的实现。
最后通常只有两种结果:
- 整体选择一个版本,其他工作全部丢弃;
- 尝试拼接多个版本,花大量时间解决冲突。
更合理的拆分方式是先确认依赖关系。
例如 B 和 C 都依赖 A 的公共协议,那么应该:
- 先完成并冻结 A;
- 形成固定 Commit;
- 再让 B 和 C 基于这个 Commit 并行;
- 每个 Agent 使用独立 worktree;
- 明确各自允许修改的文件范围。
并行的基本单位不是“一个 Agent”,而是“一个没有共享写入面的任务”。
六、测试很多,不等于证据足够
AI 协作开发会产生很多不同类型的证据:
- 单元测试;
- Fixture;
- 独立脚本;
- 模拟服务;
- 真实客户端调用;
- 真实外部 API;
- 用户界面;
- 最终发布包。
这些证据不能互相替代。
一个工具在独立脚本里执行成功,只能证明工具本身可运行,不能证明客户端已经发现并调用它。
使用 Fixture 生成了一张图片,只能证明传输和数据结构可能正确,不能证明真实图片服务、认证、界面展示和生产打包已经完成。
另外,验收必须绑定固定 Commit。
如果验收完成后实现代码又发生变化,原来的验收只能证明旧 Commit,不能继续作为新版本的通过证据。
所以每次报告结果时,都应该明确:
- 验证的是哪个 Commit;
- 走的是真实路径还是 Fixture;
- 证明了哪一层;
- 哪些内容还没有验证;
- 工作区是否干净;
- 验证命令能否重新运行。
上次就是拿 Fixture 通过当全链路证据,结果客户端里根本调不起来。
七、阶段性收口不等于项目完成
复杂项目不可能等所有功能开发完以后,才第一次形成稳定版本。
但反过来,也不能因为某一批基础能力已经通过测试,就宣称整个项目已经完成。
这次前一阶段的问题之一,就是代码和证据长期散落在多个 worktree 和分支里,缺少一个可以继续开发的稳定基线。
后来我们对已经完成的部分做了阶段性收口:
- 把这一阶段的代码集中到统一分支;
- 保持工作区干净;
- 让验收绑定固定 Commit;
- 记录当前可以运行的命令;
- 给中间版本建立 Tag;
- 尚未完成的功能继续进入后续开发。
这一步的目的不是宣布项目完成,而是给后面的开发建立一个可信的起点。
阶段性版本应该明确记录三类内容:
- 这一阶段已经完成什么;
- 哪些能力只完成了部分;
- 后续还有什么没有实现。
如果这三点不区分清楚,很容易把“某个纵切通过”误写成“产品已经完成”。
后续使用 AI Coding 的开场检查
这个项目还在继续。后面的功能开发中,我会先确认下面这些内容:
目标:
- 用户是谁?
- 本轮要看到什么结果?
- 当前阶段明确不做什么?
架构:
- 哪些能力必须保留?
- 哪些目录禁止修改?
- 允许使用哪些扩展机制?
- 客户端和服务端如何分工?
事实:
- 当前到底是哪个仓库和分支?
- 工作区是否有 modified、untracked 和 ignored 文件?
- 是否已经存在可复用实现?
- 文档是否与当前代码一致?
执行:
- 任务之间有什么依赖?
- 哪些任务可以真正并行?
- 每个 Agent 负责哪些文件?
- 功能开发和测试分别占多少时间?
验收:
- 用户结果是什么?
- Test Contract 是什么?
- 验收绑定哪个 Commit?
- 使用的是真实路径还是 Fixture?
- 这一阶段完成了什么、还缺什么?
- 达到什么条件后建立阶段版本?
这次阶段性复盘给我的最大提醒是:
使用 AI 写代码,真正困难的不是让它生成更多代码,而是让它始终在正确的前提下,朝同一个产品结果前进。
AI 可以承担实现、测试和分析,但目标、边界、证据标准和阶段停止条件,必须由人先确定。
这篇文章也不是这个项目的最终总结。只是趁问题刚暴露出来,先把教训记录下来,避免后面的开发继续走同样的弯路。