最近用Codex改真实项目时,有一种情况特别容易让人产生错觉:

代码改完了,测试也绿了,Diff看起来也没什么问题。

于是你很自然地会觉得:

这次应该可以合并了。

但真正合并到主分支,甚至进入测试环境以后,却发现功能还是出了问题。

有时候是接口返回不对。

有时候是某个旧功能突然失效。

有时候单独测试完全正常,一进入完整业务流程就开始报错。

更麻烦的是,这种问题表面看起来甚至不像“AI写错代码”。

因为你重新回头看:

代码逻辑合理。

测试通过。

Lint正常。

Build也没失败。

那为什么最后还是会出问题?

真正的原因往往不是Codex不会写代码。

而是:

“测试通过”只证明了一部分事情成立,它并不能证明整个系统在真实环境里仍然正确。

这也是AI越来越多进入真实项目以后,一个很容易被低估的问题。


一、先看一个很典型的真实场景

假设现在有一个用户权限接口。

需求很简单:

给管理员新增一个权限判断。

你让Codex修改。

它很快完成了几件事:

修改权限判断函数。

补充单元测试。

更新对应接口逻辑。

运行测试。

测试全部通过。

从任务结果上看,没有任何问题。

但代码合并以后,测试环境里却出现了一个异常:

普通用户访问某个旧接口时,也被错误拦截了。

你回头看Codex改的那几行代码,逻辑没有明显错误。

新增测试也覆盖了管理员场景。

问题出在哪里?

最后可能发现:

原来的权限函数不仅被新接口调用。

还有另外三个旧模块也依赖它。

Codex完成的是:

“管理员权限这个任务正确了。”

但系统真正要求的是:

“管理员权限任务正确,同时不能破坏其他依赖这个函数的旧行为。”

这两个标准并不是一回事。


二、测试通过,究竟证明了什么?

很多人潜意识里会把“Tests Passed”理解成:

代码已经正确。

但工程上更准确的理解应该是:

当前测试集合所表达的这些假设,暂时没有被代码破坏。

注意这里有两个限制:

第一,测试只能验证“已经写出来的条件”。

第二,测试只能验证“它实际执行到的路径”。

所以测试通过真正证明的是:

Known Cases Passed。

而不是:

Everything Is Correct。

这两个差别非常大。

假设一个函数有10种业务状态。

测试只覆盖其中4种。

那么测试全绿,只能说明那4种目前没问题。

剩下6种情况究竟会不会出错,测试其实什么都没有告诉你。

这也是为什么AI开发里,“自动补测试”虽然很重要,但不能把它理解成最终验证。

AI往往会围绕当前需求生成测试。

当前任务要求修复A。

于是AI会重点验证:

A有没有修好。

但真正项目里的风险常常来自:

修A的时候,有没有意外改变B、C、D。


三、最常见的原因:局部正确,不代表集成正确

这是这类问题最核心的工程机制。

Codex处理任务时,很容易形成一个相对清晰的局部闭环:

读取相关代码。

找到目标函数。

修改逻辑。

补测试。

运行测试。

任务完成。

从局部看,这套流程完全合理。

但真实软件不是一组互相独立的文件。

而是一个相互依赖的系统。

一个很小的修改,都可能影响:

调用链。

接口契约。

共享状态。

数据结构。

配置。

缓存。

权限。

数据库。

异步任务。

外部服务。

所以有时候你会发现:

每一步单独都正确,组合起来却不正确。

例如:

一个函数返回值从null改成空数组。

调用它的当前模块没问题。

测试也通过。

但另一个旧模块原本依赖null判断业务状态。

于是那个旧模块出错。

Codex当前修改没有任何明显Bug。

真正被破坏的是:

模块之间原本没有明确写出来的隐含契约。


四、第二类问题:AI看得到代码,却不一定看得到业务约束

真实项目里最危险的东西,很多时候不是代码。

而是:

没有写在代码里的规则。

比如:

“这个字段虽然允许为空,但线上流程实际上一定会有值。”

“这个接口不能改返回顺序,因为旧客户端依赖这个顺序。”

“这个任务必须先写数据库,再发消息。”

“这个权限判断虽然看起来可以抽象,但另一个内部系统依赖当前行为。”

这些规则可能存在于:

历史经验。

产品约定。

团队习惯。

线上兼容需求。

旧系统债务。

甚至某个开发者脑子里。

而Codex只能根据它实际能够读取到的信息判断。

如果这些规则没有写进:

测试。

类型。

接口定义。

文档。

AGENTS.md。

项目约束。

那么对AI来说,它们很可能根本不存在。

于是就会出现一种特别典型的情况:

AI写出的代码在程序逻辑上是合理的,但在业务系统里是不成立的。

这也是为什么真实项目越复杂,AI任务验证就越不能只看“有没有报错”。


五、第三类问题:单元测试通过,但真实运行环境不同

还有一种非常常见的情况:

本地测试完全正常。

合并以后却失败。

原因通常来自环境差异。

例如:

环境变量不同。

数据库数据不同。

依赖版本不同。

缓存状态不同。

权限不同。

外部服务响应不同。

Feature Flag不同。

测试数据库里只有干净数据。

而真实环境里可能已经存在几年历史数据。

某段代码在测试环境里处理100条数据没问题。

线上面对100万条记录时可能直接超时。

所以:

逻辑正确 ≠ 环境正确。

AI能够帮你验证逻辑。

但如果测试环境本身没有模拟真实状态,那么测试通过仍然无法覆盖实际风险。


六、还有一个很隐蔽的问题:测试本身也可能跟着错误一起被修改

这是用AI改代码时尤其值得注意的一点。

假设原来有一个测试:

expected = 旧行为

Codex修改了功能。

发现测试失败。

然后根据“新逻辑”顺手把测试也改成:

expected = 新行为

最后测试通过。

看起来非常漂亮。

但问题在于:

谁证明这个“新行为”真的是业务需要的?

如果AI同时修改:

实现。

测试。

预期结果。

那么测试很可能已经失去了独立验证能力。

它只是变成了:

AI用自己生成的规则去验证自己生成的代码。

这在工程上是一个非常重要的风险。

所以真正高质量的验证,不应该只问:

“测试有没有通过?”

还应该问:

测试验证的是原始业务需求,还是验证了AI自己重新定义的行为?


七、为什么AI编程越普及,这类问题反而会越来越明显?

因为AI正在显著降低“修改代码”的成本。

以前开发者改一个跨模块功能,可能会因为风险高而非常谨慎。

先读代码。

再确认依赖。

再慢慢修改。

现在Codex几分钟就能生成完整Diff。

代码生成速度提高以后,人很容易产生一种心理变化:

既然修改这么快,那就多改一点。

于是一次任务原本改2个文件。

现在可能改8个。

原本只修Bug。

现在顺手重构。

原本不补测试。

现在顺便补一整套。

看起来效率提高了。

但修改面也扩大了。

而修改面越大,潜在的集成约束越多。

于是未来开发里真正昂贵的部分会逐渐从:

“代码怎么写?”

转向:

“我怎么证明这个修改没有破坏其他东西?”


八、怎么排查这类问题?

遇到“测试通过但合并后仍然出问题”,我一般不会第一时间重新让AI再改一遍。

更有效的是先从四个方向检查。

1. 看影响面,而不是只看修改文件

不要只看:

“Codex改了哪几个文件?”

还要看:

这些函数被谁调用?

这些类型被谁依赖?

这些配置被哪些模块读取?

这些返回值有没有外部消费者?

一个修改真正的影响面,往往远大于Diff本身。


2. 区分单元测试和集成验证

单元测试证明局部逻辑。

集成验证才证明多个模块能不能一起正常运行。

如果改动涉及:

接口。

数据库。

权限。

状态流。

跨模块调用。

只跑单元测试通常是不够的。


3. 检查测试有没有被“顺着实现一起改掉”

如果AI同时修改了测试和实现,重点看:

测试的预期值为什么改变?

这个变化来自需求,还是来自新代码?

如果解释不清楚,就应该重新确认。


4. 让Codex主动列出“没有验证的东西”

这个方法其实非常实用。

不要只让Codex回答:

“任务完成了吗?”

而是要求它额外输出:

已验证内容。

未验证内容。

潜在影响模块。

可能存在的边界情况。

需要人工确认的位置。

你会发现,这类信息有时候比“测试通过”更有价值。


九、怎么降低以后再次发生的概率?

真正有效的方法,不是让AI更谨慎一点。

而是把项目里的隐含规则变得更显式。

例如把重要约束写进:

测试。

类型。

接口Schema。

文档。

AGENTS.md。

CI规则。

静态检查。

验收标准。

你要尽量把:

“只有人知道的规则”

变成:

“机器也可以读取和验证的规则”。

因为只要约束仍然只存在于人的经验里,AI就永远可能绕过它。


十、给自己测一个指标:集成回退率

这篇我建议只观察一个指标:

集成回退率

计算方式很简单:

最近一段时间,AI完成并且本地验证通过的任务中,有多少在合并、集成测试或后续环境中还需要返工?

例如最近20次Codex修改:

15次直接合并正常。

5次虽然本地Tests Passed,但合并后又需要重新修改。

那么集成回退率就是:

25%。

这个数字非常有意义。

低于10%

说明你的:

任务边界。

测试体系。

项目约束。

AI使用方式。

已经比较成熟。

AI产出的结果大多数能够稳定进入后续流程。

10%—25%

说明局部验证还不错,但集成约束没有完全被系统化。

这时候最值得做的是补齐:

集成测试。

影响面分析。

业务约束。

高于25%

如果大量AI修改都是:

本地绿 → 合并出问题 → 再返工,

那么瓶颈已经不是AI写代码的能力。

而是工程验证体系本身。

这时候继续单纯提高AI使用量,只会更快地产生更多需要返工的代码。


十一、Plus和Pro应该怎么判断?

这个问题最后其实可以直接根据“集成回退率”判断。

如果你的集成回退率还比较高,例如20%、30%甚至更高:

说明现在最大问题不是任务跑得不够多。

而是AI任务进入真实项目以后还不够稳定。

这种阶段更值得先做的是:

缩小任务范围。

补集成测试。

写清业务约束。

要求AI输出影响面。

完善验证Workflow。

这类情况下,Plus通常已经足够你把流程打磨成熟。

因为即使增加更多AI容量,也很可能只是制造更多返工。


如果你的集成回退率已经很低:

大部分Codex任务都能够稳定完成。

测试可信。

影响面可控。

合并以后很少返工。

但你开始经常遇到:

多个长任务排队。

高频调用。

项目上下文很大。

一天需要连续处理很多独立开发任务。

这时候AI侧容量才真正开始成为限制。

到了这个阶段,Pro带来的更高使用强度才更容易直接转化成开发吞吐量。

换句话说:

先让AI产出稳定,再扩大AI产能。

这个顺序通常比一开始就追求更高容量更重要。


最后

以后用ChatGPT、Codex做真实开发,有一句话我觉得会越来越重要:

测试通过,不等于任务真正完成。

真正可靠的修改至少要同时满足:

代码逻辑正确。

测试结果可信。

集成关系没有破坏。

业务约束仍然成立。

风险可以接受。

AI越来越擅长完成前面的“写代码”和“跑测试”。

但后面的系统性验证,反而会越来越成为开发者真正需要管理的部分。

所以当你下一次看到:

All Tests Passed

不要只问:

“是不是可以合并了?”

更应该再问一句:

这些测试,到底证明了什么?又有什么东西,它其实还没有证明?

这往往才是从“AI能写代码”,走到“AI能稳定参与真实工程”的关键一步。

持续分享 Codex、大模型开发与 AI 编程实战内容。
长期深度使用各类代码大模型,也整理了稳定的
Plus/Pro会员订阅渠道,有需要可自取。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐