AI 写代码快了,交付怎么才靠得住:我们踩过的坑和现在的做法
AI 让改代码变快了,可改坏了谁发现、退回到哪、由什么证明它是好的,这些问题并没有变简单。本文写我们在一套排程系统的开发中踩过的六个坑,以及现在的做法和还做不到的事。
先说结论
- AI 让改代码变快了,可改坏了谁发现、退回到哪个版本、由什么证明那个版本是好的,这三个问题并没有变简单。
- 我们把「完成」拆成六段:改了、测了、提交了、推送了、上线了、在真实环境里走通了;每一段单独留证据,「测试通过」「服务在线」都不算交付完成。
- 踩过的坑里最难发现的是「静默退回」:模型调用失败退回模板、规则读取失败退回默认值,页面上一切正常;现在宁可让系统明确报错、停下来。
- 评估一家用 AI 协同开发的交付方,可以问四个问题:怎样定义「完成」,出了问题退回到哪个版本、由什么证明它是好的,AI 生成的内容怎样标明来源,做不到的事写在哪里。
用 AI 写代码,速度的变化很直观:需求讲清楚,几分钟后就能看到一段能运行的改动。改得快是好事,随之而来的是三个问题:改坏了,谁来发现?发现了,退回到哪个版本?退回之后,由什么证明那个版本是好的?
本文写我们在自研排程系统 APSer-Aps 的开发中,用 AI 编程工具写代码、改代码时踩过的坑和现在的做法。这套排程系统本身也用到大模型,但职责很窄:排程结果由约束求解引擎计算,排程内核不接入大模型;大模型只在外围做几件事:解读预警和急单方案、回答提问、按问题挑选要展示的视图。本文说的「AI 协同」,指的是用 AI 编程工具编写和修改这套系统。
这件事里有三个角色:我们定目标和规矩、拍板、做真实验收;AI 编程工具作为执行器写代码;我们自研的工作平台 APSer-Atelier 作为主控,负责组织:登记每一件事、决定交给哪个执行器、核对结果、挂起待拍板的问题、留下验证记录。下文的单写入者、提交与推送时的检查,就是主控在把关。平台的来历见《APSer-Atelier 的场景锚定与价值定位,以及实践总结》。
这里说的 APSer-Atelier 主控包括两部分:面对我们的主控会话(一段 Claude Code 或 Codex 对话),负责组织和派出;Atelier 平台,负责登记每一件事、挂起待拍板、记下要求、按规矩放行并留下记录。
「完成」要分哪几段来确认?
我们把「完成」拆成六段:改了、测了、提交了、推送了、上线了、在真实环境里走通了。每一段单独留证据,前一段的证据顶替不了后一段。「测试通过」「接口返回正常」「服务在线」都只证明了其中一段;在真实环境里把真实的业务路径走一遍,才算交付完成。
分工上,业务目标、范围取舍,以及正式交付、合同报价、对外承诺这些对外动作,由人决定;写代码、写测试、提交、部署和真实环境验收,由 AI 在人定下的规矩里连续完成,做完一次性汇报。不可逆的数据库操作、凭据、安全策略这类高风险动作,必须在任务开始时写明范围、备好回退办法;目标或回退办法不清楚时就停下,不靠猜测继续。
我们踩过哪些坑?
以下六条是我们犯过、并且认为最有普遍意义的错。
一、AI 解读悄悄退回了模板
- 发生了什么:配置的模型名在本地模型服务里并不存在,每次调用都失败,几处 AI 解读全部悄悄退回模板文案;页面上的 AI 标识却一直固定写着模型名,看上去一切正常。
- 学到了什么:退回模板这条路如果没有可见的标记,失败就被吞掉了。
- 现在怎么做:模型按候选列表逐个尝试;页面上显示实际调用到的模型名;全部失败、退回模板时,页面明确标「规则生成」。
二、读不到规则,就用默认规则照常排产
- 发生了什么:数据库被锁时,读取排程规则失败,系统悄悄改用默认规则照常排产,并把结果写了回去。页面上看不出异常,物料齐套相关的指标却全变了。
- 学到了什么:拿不准的时候继续执行,比停下来危险得多。
- 现在怎么做:读不到规则就拒绝排产,返回明确的错误并记日志。系统宁可不执行,也不写入一份错误的计划。
三、部署后只看「服务在线」
- 发生了什么:我们另一个在线服务的一次部署,恰好打断了一个正在执行的用户请求,用户当即收到超时报错;部署后只检查了进程状态和新代码是否到位,就报告了「成功」。
- 学到了什么:「进程在线」和「业务能用」是两回事。
- 现在怎么做:推送前先看有没有正在执行的请求;推送后按真实方式调用一次并计时;没做真实验收,这一轮工作不算完成,开发环境会把它打回来补做。
四、没有出处的数字,被包装成「已论证」
- 发生了什么:AI 协作起草的一份内部文档里出现了一个没有出处的调研数字,还附上了「已论证」的说法。后来起草对外材料时,AI 把它当作权威来源引用,被当场指出:真实样本小得多,那个比例用真实样本也算不出来。对外发出前已全部纠正。
- 学到了什么:没有溯源的数字,加上权威的措辞,就会一路畅通。
- 现在怎么做:看到「已论证」「已验证」这类词,先当作警觉信号;对外使用的数字回到源头重新核算,并交叉核对。
五、两个 AI 同时改一个代码仓
- 发生了什么:主控会话提交自己的改动时按整个文件提交,把另一个正在开发的 AI 还没做完的代码一起带上了线,服务启动失败;随后的补救又出了一次错。另有一次,两个 AI 同时往变更记录里追加条目,互相撞车。
- 学到了什么:同一个代码仓同时有两个写入者,迟早出事。
- 现在怎么做:同一个代码仓同一时间只允许一个写入者;代码只有一条主线;提交时只添加本次改过的具体文件;推送时按复核过的具体版本推送;没做完的功能用开关关着。
六、AI 自己造了一个业务概念
- 发生了什么:为了实现方便,AI 造了一个客户业务语言里没有的中间概念,把客户原有的单据层级压缩了一级,并一路写进了代码、页面和文档,直到被追问来源才发现。
- 学到了什么:软件方发明的概念,最后要由客户的员工来学。
- 现在怎么做:引入任何业务对象或术语之前,先在客户提供的原始资料里找到出处;找不到的标为实现术语,确认之后才写进客户看得到的页面。
现在长期在做哪些事?
除了上面各条「现在怎么做」,还有几件事是长期在做的。
验收通过的版本另做标记
每次上线先在真实环境验收,通过后由人给这个版本打上带时间的标记,写明验收要点;没验收的版本不打。需要回退时,最近一个标记就是「上一个验证过的好版本」。
恢复可以演练
备份包含代码、数据库、运行配置,以及全部表的行数与内容校验值,本机和另一台设备各存一份;密钥不进备份。恢复默认只恢复到临时目录,再自动比对行数、校验值和下面说的业务规则;要覆盖真实环境必须显式声明,并在覆盖前自动再备份一次。这套做法启用不久。
业务上不可能的状态,写成代码检查
把排程里不可能出现的状态写成代码检查,例如:开工时间不早于所需物料的到货时间;分配两端的数量守恒。定时自动任务执行前后各检查一次,违例增加就整次回滚;取消、收货等人工写操作同样检查,变差即拒绝。这样,跨模块改动之后,即使每个模块自己的测试都通过,业务上说不通的结果也能被发现。
文案、行业特判与回归比对
- 面向用户的文案检查:扫描前后端全部面向用户的文本,拦截内部编号和内部过程用语。
- 行业分叉检查:扫描内核与接口代码,拦截按客户名、行业名写的判断分支;改造前已有的几处分叉登记在放行清单里,计划逐步清零。
- 回归比对:基准数据用固定种子生成,对排程结果计算校验值,内核有改动就重跑比对;全量测试固定了求解方式和「今天」的日期,结果一变,就是代码行为真的变了。
规矩写成确定性检查
长时间连续工作时,靠提醒和自觉执行的规矩迟早会漏。能让机器判断的,我们尽量写成不调用大模型的检查脚本,在提交、推送、收工等时点自动运行,例如:写时间之前必须先读系统时钟,不许改凭据文件,不许直接写别的系统的数据库,不许批量「全部添加」。同样的输入总得到同样的判断,出了问题可以复现。
工程知识写进代码仓
架构决策、已知的坑、运行纪律,写在代码仓里多种 AI 编程工具都能读取的开放格式文档中;接手的人或工具按「项目说明、当前状态、待办清单」的顺序读,就能接着做。
哪些事可以放手让 AI 自动做完,哪些要停下来等人,我们按犯错的后果来分:可以撤回的内部改动自动往下走,涉及客户、对外承诺和不可逆的动作一律等人确认。《权力与预测》一书里有一个相近的例子:一家做客服自动化的公司,对免费用户的咨询自动处理了 98%,对付费用户只自动处理 85%,因为对付费用户出错的代价更高 [1]。
哪些做法随系统交付,哪些是我们的工作规矩?
上面的做法分两类,评估时宜分开看:
- 随排程系统一起交付的:显示实际调用的模型名、失败时标「规则生成」;读不到规则就拒绝排产;业务不可能状态的检查与回滚;备份与可校验的恢复工具。
- 我们开发时的工作规矩:「完成」六段与真实验收、验收标记、单写入者与单主线、提交与推送时的检查脚本、文案与行业分叉检查、回归比对、术语溯源、数字回源核算、工程知识写进代码仓。这一类约束的是我们自己的开发过程。
还有哪些做不到?
- 部分检查还靠纪律:文案检查、行业分叉检查、回归比对按「每批必跑」执行,还没有接入提交前的自动检查,漏跑时没有机器兜底。
- 检查脚本本身也会失效:开发机的一个系统组件升级后,检查脚本曾静默停止运行。现在有一个页面汇总检查脚本近期的运行和报错,能较早发现这类失效,根因还没有消除。
- 行业分叉检查有盲区:它只认字面判断,通过函数调用做的行业分派要靠人工复核。
- 跨工具接手的记录还少:另一家的 AI 编程工具参与过独立复核和少量改动,但还没有一次由另一个工具从零接手、完成完整功能的记录。
- 运行时间短:上面多数做法建立不久,长期效果还要时间检验。
以下是我们的看法
AI 降低了写的成本,确认的成本没有随之降低。 改动几分钟就能写出来,确认它没有改坏别的东西、在真实环境里确实能用,所需的时间没有同比例缩短。所以我们把投入放在确认这一侧:分段留证、真实验收、验收标记、可演练的恢复。
失败要看得见。 我们踩过的坑里,最难发现的几次都是「静默退回」:模型调用失败退回模板,规则读取失败退回默认值,页面上一切正常。宁可让系统明确报错、停下来,也不要让它带着错误继续写入。
如果您正在评估一家用 AI 协同开发的交付方,可以问四个问题:怎样定义「完成」?出了问题退回到哪个版本、由什么证明它是好的?AI 生成的内容怎样标明来源、失败时页面显示什么?做不到的事写在哪里?这些答案,比写代码的速度更能说明交付质量。