THESIS / 核心主张
缺陷库的价值不是记录错误,而是让同类错误下一次更早被发现,最终不再依赖个人记忆。
OPERATING STEPS / 执行动作
把原则变成可以检查的动作。
- 记录触发条件与逃逸原因
- 标注应该在哪个 Gate 发现
- 将高频缺陷转成检查单、测试或拦截
- 定期合并重复项并删除失效规则
OUTPUTS / 交付物
每个阶段都要留下可复用的产物。
APPLIED CASE / 项目映射
这条方法如何落到真实项目?
GMV 重点缺陷包括日期越界、误写目标表、预览发生写入、规则命中但事业部为空、部分失败后仍刷新汇总。
FULL CHAPTER / 完整正文
从结论摘要,继续读到判断依据和执行细节。
正文保留 site-v3 的完整论证结构,并将贯穿示例改写为生态店铺 GMV 清洗迁移;原作者身份、原演示案例和未经证实的个人成果不进入本站。
AI 代码缺陷库:常见事故模式与修复方式
专业不是相信 AI 不会错,而是知道它最容易在哪里错——并且把"哪里"做成清单。
一、为什么 AI 的缺陷可以建库
人类工程师的失误偏随机(疲劳、疏忽、知识盲区因人而异),AI 的缺陷却高度模式化。原因在认知篇已经建立:AI 在未声明处按训练分布做默认假设,而训练分布是稳定的——语料里大多数代码是单机 demo,于是"默认单机""默认无重试""默认调用方可信"会跨任务、跨会话地稳定复现。
这个特性坏消息是缺陷一定会来,好消息是它们从哪里来是可预测的。可预测就可清单化,可清单化就可以做成事前防线。规模上这值得认真对待:多项独立评测显示接近半数 AI 生成代码样本含已知缺陷模式(见验证闭环的 Veracode 数据)。
下面十种模式来自真实交付中的反复观察,每种都标注了根源假设——根源假设就是训练语料里的"多数派写法"。
二、十种缺陷模式
先看全景,细节在后:
| # | 模式 | 根源假设(训练分布的多数派) | 后果等级 |
|---|---|---|---|
| 1 | 用进程内状态协调跨实例任务 | 教程代码都是单机 | 重复执行/状态错乱 |
| 2 | 忘记重跑语义 | 每次请求都是新请求 | 重复写入 |
| 3 | 运行批次缺少业务范围 | demo 里只关心技术 ID | 无法追溯 |
| 4 | 写入与完整汇总边界不清 | 示例代码不写失败路径 | 数据不一致 |
| 5 | 金额用浮点数 | 教程用 double 图省事 | 财务错误 |
| 6 | 只写 happy path 测试 | 示例测试只示范"怎么写测试" | 缺陷逃逸 |
| 7 | 吞异常 | catch-log 是最常见的样板 | 静默失败 |
| 8 | 权限缺失 | demo 里调用方可信 | 越权/泄露 |
| 9 | 日志不可定位 | 示例日志只打消息不打业务键 | 故障黑盒 |
| 10 | 为通过测试改生产逻辑 | 优化目标是"让检查通过" | 验证失效 |
1. 用进程内状态协调跨实例任务
synchronized void runBatch() { /* 更新本地运行状态 */ }
多实例部署下 synchronized、本地缓存、本地变量无法形成全局状态——任务可能重复触发、暂停和恢复语义互相冲突。
追问:运行状态存在哪里?谁拥有调度权? 验证:多实例语义审查 + 重复触发测试。
防线:体检第①维;常驻规则明确调度与运行实例边界。
2. 忘记重跑语义
每次请求都按新任务处理。网络重试、重复点击和补数会制造无法解释的重复写入。 方案:先确认覆盖、追加还是清理后重建,再让运行范围与结果可追溯。 验证:同一平台与日期范围连续执行两次,断言结果符合已确认的重跑策略。
3. 运行批次缺少业务范围
select max(id) from run_instance -- 只拿技术 ID 判断“最新一批”
技术 ID 不能解释平台、日期范围、目标表和规则版本,故障后无法回答这批数据怎样产生。 方案:技术主键之外记录业务范围、规则/流程版本和触发来源。 验证:从结果反查完整运行上下文。
4. 写入与完整汇总边界不清
某个平台写入成功、另一个平台失败,系统仍刷新完整汇总,下游得到看似完整的半成品数据。 方案:平台级结果与整批完整状态分离,任一失败不刷新完整汇总。 验证:故障注入后断言汇总门禁未触发。
5. 金额用浮点数
double amount; // 0.1 + 0.2 != 0.3
方案:BigDecimal + 显式舍入规则。 验证:小数、折扣、汇总、边界金额用例。
6. 只写 happy path 测试
生成的测试全绿、全是成功路径。上线后异常路径裸奔。 方案:测试要求逐条对应规格的 EARS 规则;从头全绿的测试报告按工作单约定视为坏信号。
7. 吞异常
try { ... } catch (Exception e) { log.error("failed", e); }
// 然后继续返回成功
调用方以为成功,数据实际不完整——比抛错更危险,因为没人知道出了错。 方案:异常要么转成明确业务错误、要么触发回滚、要么进补偿流程,三选一,不允许第四种。
8. 权限缺失
只凭 platform + dateRange 执行平台 GMV 清洗,不校验归属。方案:目标表只允许从受控配置中选择,拒绝任意表名输入并记录原因(TARGET_TABLE_NOT_ALLOWED 与 INVALID_DATE_RANGE 的语义设计见规格样例)。
9. 日志不可定位
generate gmv failed——没有 platform、dateRange、runId、targetTable 和 traceId,生产问题无从查起。
方案:关键日志必含业务键、操作者、异常类型、链路 ID(体检第⑦维的落地)。
10. 为通过测试修改生产逻辑
测试缺数据就改生产代码迁就、断言失败就弱化断言。这是 specification gaming 的编码形态(实证见架构边界),特殊性在于它专门破坏验证体系本身。 方案:测试与实现分单、互设禁区;变异测试抽查(见验证闭环)。
三、缺陷库的三个注入点:从事后总结到事前防线
缺陷库如果只是一份"常见错误汇总",它就只是又一篇博客。它的工程价值在于回流进交付链路的三个环节:
① 需求体检——每种模式的"追问"就是八维体检表第三列(AI 的典型默认假设)的来源。体检清单不是凭空设计的,是缺陷库反推的。
② Agent 工作单——高风险模式直接写进禁止事项和验收标准:
【实现前检查】(来自缺陷库,按本任务风险筛选)
- 禁止用进程内状态协调跨实例任务(模式1)
- 重跑策略必须显式且可验证(模式2)
- 金额一律 BigDecimal(模式5)
- 禁止为通过测试修改生产逻辑(模式10)
③ 验证闭环——每种模式的"验证方式"进入测试要求和 review 清单;第④道闸门沉淀的新失败模式在这里入库。
于是形成完整闭环:缺陷在验证中暴露 → 归纳成模式入库 → 反推进体检和工作单 → 下一次在生成前就被拦住。 每次事故让防线变厚一层,这就是"经验变成系统"的具体形态——个人踩过的坑,从此变成组织级的资产,而不是留在某个人的记忆里。
四、维护纪律
缺陷库和规则文件一样会腐烂,两条纪律:
- 入库门槛:同类问题出现两次才入库——出现一次的可能是偶然,清单无限膨胀会稀释真正的高频模式;
- 定期核销:某模式连续多个迭代零命中,考虑两种解释——防线已经把它挡在上游(好事,降级为归档),或者业务已不涉及该场景(删除)。清单只保留"仍在发生"的模式,才能维持它在工作单里的注意力权重。
五、本章小结
- AI 缺陷高度模式化,因为根源(训练分布的多数派写法)是稳定的——可预测,所以可清单化,所以可做成事前防线。
- 十种模式各有根源假设、验证方式和防线位置;模式 10(为通过测试改生产逻辑)最特殊,它破坏的是验证体系本身。
- 缺陷库的价值在三个注入点:反推体检清单、写进工作单禁区、进入验证清单——形成"暴露→入库→前置拦截"的闭环。
- 入库要门槛(两次成模式),核销要定期——清单只保留仍在发生的模式。
下一章 运行与解答,进入交付之后的下半场:让系统可排查、可自答。
参考资料
- Veracode, GenAI Code Security Report(2025)——近半数 AI 生成代码样本含已知缺陷模式,详见验证闭环。
- DeepMind, Specification Gaming: The Flip Side of AI Ingenuity(2020)——模式 10 的行为学依据。