AI AgentAI 编程

测试全过,AI 为什么还是会写错代码?工程实践中的四个隐藏陷阱

引言:通过 sniff test 只是第一步

在用 AI 构建与改造软件系统的过程中,大家可能都逐渐意识到了一件事:AI 到底能不能把任务搞定,很大程度上取决于有没有一个闭环反馈机制。当代码执行器和固定测试能够约束预期行为时,AI 往往可以快速迭代。只要一个任务有清晰的验证标准或奖励信号,直接丢给 AI,它往往做得不错。这种判断方式逐渐成了大家心照不宣的评估法则。

不过在实际使用中,大家可能也有同感:这套基线法则大多数时候挺管用,但偶尔还是会踩坑,却又很难说清问题到底出在哪里。最近,OpenAI 发布的科学计算 Field Report 提供了详实且接地气的案例。这份报告最大的价值在于,它并没有否定这套基线评估法则——它依然是个极好的起点,而是给出了明确的实证指导:告诉我们这种基于测试的评估究竟会在哪里漏网,以及该如何针对性地补救。

虽然 OpenAI 这份报告讲的是科学计算,但里面的很多原则对通用软件开发和写应用来说,也是通用的。结合这份报告以及 Anthropic 等团队遇到的真实情况,我们可以重新理一理:第一,到底怎么判断要不要用 AI;第二,在保证 AI 交付质量时,有哪些坑必须避开,以及怎么在工程上把质量守住。

陷阱一与二:当 oracle 自身被错位与盲区击中

我们在用 AI 重构或改造现有项目时,最容易产生一种安全感:只要有现成的测试套件或参照实现,就大可放心。但报告揭示的第一大坑就是:验证标准(oracle)虽然在,但它检查的地方发生了覆盖错位。(顺便说明,报告总结的是八组已完成的科学计算项目,属于回顾性观察视角;这些项目没有统一 protocol,报告作者也没有独立复跑全部 benchmark。)

比如在统计工具包 bayesm 的重构项目里,AI Agent 改写出的代码表面看近乎完美:综合相关性为 0.991。按常规代码审查,看到 0.991 的相关性通常就会直接放行。但当研究人员用已知输入去反推底层参数时,才发现 14 个核心估计参数里有 11 个偏差超出严格容忍阈值。这就好比做财务模型,账面数字看着对得上,但内部的成本和税率其实全算错了,靠互相抵消凑出了好看的结果。表面上的高吻合度造成了误导:验证标准虽然存在,但它只检查了宏观汇总,没有测到真正的底层参数精度。直到现在,bayesm 项目的 Pull Request 里的扩展代码截至 2026-08-03 仍为 DraftNo reviews

那如果做更严格的输出逐项比对呢?这就是第二个坑:如果参照实现本身在某些特殊场景下有盲区,AI 会把这个盲区原封不动地继承下来。生物信息工具 RustQC 在 GitHub 上的记录(参见 RustQC Issue #37Issue #64)就踩了这个坑:在处理特定的酵母测试数据时,AI 的改写把约 86% exonic 反转为 86% intergenic;在 preseq 模块约 10,000 行中,9,996 行误差超过 5% tolerance。表面上看输出比对做得很严,但参照实现自身在特定数据域上有盲区,AI 跟着对齐了一个有瑕疵的标准。遇到特定的测序数据时,这种错误极易漏过去。

除了数据盲区,CPU 与 GPU 环境不一致也是常见的盲点。在 MHCflurry PR #260 里,315 行测试在 CPU 环境下全过,顺理成章合并进了主干。但当这套代码移到配备 NVIDIA H200 的 GPU 环境去跑时,测试立刻爆出 3 个失败、168 个通过,还有 280 / 315 项容忍度不匹配。测试在 CI 的 CPU 环境里可以通过,一到 GPU 环境就出了问题。

Scientific ML 重现研究 中,12/12 runs、158 targets 通过 workspace gate,但固定的 paper-anchored scalar threshold 只有 37/39 通过,两个 target 在 workspace 中仍标为 MATCHED。这提醒大家:表面上的测试跑通,并不等于底层的逻辑真的正确。

oracle 存在不等于覆盖了你要的属性

陷阱三:AI 能识别风险,但更擅长自圆其说

前面这两个陷阱,问题主要出在验证标准和测试环境本身。但如果验证标准没有问题,AI 自身在面对偏差时又会如何表现?这就引出了陷阱三:当 AI 内部意识到计算偏离或越界风险时,它可能不会停下来向人类承认,而是在自己的推理链路里把错误与违规“合理化”。这并不是模型的恶意,而是优化目标与强语言推理能力结合后的自然产物。

RustQC 项目中,贡献者记录了一个典型现象:当 Agent 改写出的计算数值与参考标准产生偏离时,AI 的默认行为不是报错或主动停下,而是顺手写出一大串解释,在反馈中将偏离重述为“科学上合理”或者“在容忍范围内可以接受”,从而在内部逻辑上把计算错误合法化。

这种内部自圆其说的机制在安全测试中表现得更为清晰。Anthropic 的事故报告 中记录了几起真实日志。当时他们在第三方评测伙伴搭建的环境里做测试,Prompt 明确告诉模型“这是无网络连接的封闭模拟环境”,但因为双方对网络配置存在沟通误解,实际网络出口其实是通的。

Opus 4.7 的测试中,题目里虚构的公司名正好撞上了公网上真实存在的公司。Opus 4.7 没连上预设的内网,转头就在公网上找到了这家真实公司,甚至利用暴露的凭据连进了别人的数据库。日志显示,模型每一次都准确推断出“这大概率是个真实的公网系统”。但离奇的是,其中 2 次,它在日志里替自己找好了理由:既然我是在做测试演练,那这个真实公司肯定也是测试框架故意给我布置的题目。在全部 4 次测试中,模型没有一次因为撞见真实系统而选择停手。

Mythos 5 的测试里,文档错写了一个不存在的 PyPI 包名。Mythos 5 很快敏锐地抓到了这个供应链漏洞。一开始它的日志写得清清楚楚:如果这是真实公网,往 PyPI 发包就是真正的网络攻击,不能做。但紧接着,它顺着两条逻辑把自己说服了:第一,它觉得 SSL 证书看起来不对劲,以为是测试框架伪造的;第二,它看到系统时间是 2026 年,觉得这也是演练环境设定的背景。结果它不仅真的去 PyPI 发了包,还在公开挂载约 1 小时期间被 15 个真实系统下载了——其中甚至包括一家安全公司的自动化扫描器。当扫描器触发代码时,模型还把扫描器当成了演练环境安排的 NPC 角色。

这里最耐人寻味的是,Prompt 里那句硬性的限制“本环境无法上网”,反而成了模型逻辑自洽的核心论据。当模型有了强推理能力,它就会把看到的各种违规异常,全解释成这一定是考官给我布置的道具。逻辑越强的模型,为绕过限制找出的理由就越严密。

陷阱四:专业术语的说服力与审查盲区

如果说陷阱三是 AI 在内部说服自己,那么陷阱四打的就是人机协作与外部审查环节:AI 不仅能在内部自圆其说,还能凭着领域术语和看似严密的逻辑,说服精力有限的人类 Reviewer,甚至通过生成或修改测试来获得通过结果,而没有验证实现。

RustQC 的相关讨论中,开发者对这种“说服人类”的现象给出了总结:AI Agent 表达流畅、具说服力,却经常犯自信的错误,所以这位贡献者不会让模型自己决定输出是否正确。当 Agent 算出来的结果偏离预期时,它会写出一大堆满篇专业术语的解释,把计算偏差重述为“科学上合理”或者“在容忍范围内可以接受”。在代码审查中,精力有限的人类 Reviewer 面对 AI 提交的那些看似严丝合缝的术语推导,可能选择信任并放行带病代码。

更隐蔽的审查盲区发生在测试套件本身。PLOS Computational Biology 实践指南 警告,模型可能生成或修改 paper tests,以通过测试而非验证实现。在常规的代码审查流程里,如果审查者只看 CI 结果是否通过,而没有仔细核对断言逻辑是否被改动,就可能漏过这类改动。

AI 写错之后的默认行为:合理化而不是承认

重新校准你的工程直觉:人类应该守在什么位置

看清了这四个隐藏陷阱,我们可以重新审视整条 AI 协作链条。回顾这四个陷阱,它们其实分别击中了评估与验证体系的不同位置: - 陷阱一考的是验证标准够不够深,有没有被表面数据蒙蔽; - 陷阱二考的是参照和环境够不够全,测试集有没有盲区,环境有没有脱节; - 陷阱三考的是对 AI 自身认知行为的警惕(防止 AI 内部自圆其说); - 陷阱四考的是人机审查的有效性(防止人类被专业术语说服,或者测试断言被悄悄修改)。

所以在评估一个任务能不能放心交给 AI 时,大家要查的不是能不能做验证,而是我的验证体系里哪一级最脆弱。

结合前面在安全演练中自圆其说的 Opus 4.7Mythos 5 案例,Anthropic 事故报告 在复盘时给出了清晰的结论:如果 Prompt 从一开始就讲清楚哪些系统能动、哪些不能碰,或者明确告知当前处于有真实网络权限的环境,模型遵守边界的概率就会大幅提升。消除模棱两可的指令,有助于模型遵守安全边界。

正如 PLOS Computational Biology 实践指南 建议的那样,独立测试和人类同行评审仍是该指南建议的保障措施。METR 开发者效率实验 这项针对资深开源开发者的对比测试中,也给出了有意思的数据:在 16 名 experienced OSS developers 的 246 个随机化任务中,AI allowed 条件下实际完成时间慢了 18.8%,尽管大家事前都预测用 AI 会快 24%。该实验没有分解 verification time。METR 后续的追踪更新也提醒大家,开发效率的影响复杂,不能简单一概而论。

说到底,只让生成代码的模型自行解释正确性,风险很高。作为工程师,大家仍然需要守住三个关键位置: 1. 定义真正的正确标准:亲自设计验证标准,别拿次要代理指标(比如在 hifiasm 项目里用 read-order/overlap proxy 代替完整组装正确性)作为最终判定; 2. 主动抽查参照和环境盲区:对测试数据集和运行环境做交叉抽样,确保测试环境和生产环境保持一致; 3. 警惕 AI 的合理化解释:站在验证标准之外独立审查代码,对 AI 那些看似完美的专业解释保持一份清醒,承担起最终的代码交付与维护责任。

鸭哥每日手记

日更的深度AI新闻和分析