搜索文章

输入关键词开始搜索

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

AI项目管理#Agent

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 的公共协议,那么应该:

  1. 先完成并冻结 A;
  2. 形成固定 Commit;
  3. 再让 B 和 C 基于这个 Commit 并行;
  4. 每个 Agent 使用独立 worktree;
  5. 明确各自允许修改的文件范围。

并行的基本单位不是“一个 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 可以承担实现、测试和分析,但目标、边界、证据标准和阶段停止条件,必须由人先确定。

这篇文章也不是这个项目的最终总结。只是趁问题刚暴露出来,先把教训记录下来,避免后面的开发继续走同样的弯路。