AI 生成的代码,哪些地方最容易埋坑?

开篇

AI 生成的代码,最危险的地方是什么?

很多人会回答:

text 复制代码
语法可能有问题
接口可能调用错
代码可能运行不起来

这些问题当然存在。

但它们通常比较容易被发现。编译器、类型检查、单元测试和本地启动,都有机会把它们暴露出来。

真正麻烦的是另一类问题:

  • 代码可以运行,但业务规则理解错了。
  • 测试可以通过,但边界条件没有覆盖。
  • 接口可以返回结果,但权限校验放错了位置。
  • 数据可以保存,但并发时会出现重复或覆盖。
  • 日志看起来很完整,却泄露了敏感信息。
  • 代码结构很"标准",却和当前项目的真实约定不一致。

上一篇文章,我们用 AI 建立了陌生项目的代码库导览。

当 AI 开始基于项目上下文生成代码后,下一步就不是继续追求"写得更快",而是要知道哪些地方必须人工审查。

这篇文章整理一份我会固定检查的风险清单。

text 复制代码
能编译
  ↓
能运行
  ↓
符合需求
  ↓
符合项目约定
  ↓
边界、安全和并发可靠

前两步只是起点,不是交付标准。

本文不会讨论什么

本文不是一份针对某个编程语言的完整安全规范,也不是说 AI 生成的代码一定不能使用。

本文不会:

  • 认为人工编写的代码就天然没有问题。
  • 建议逐行重写所有 AI 生成的代码。
  • 用静态检查工具代替业务评审和测试。
  • 把"代码风格不喜欢"直接等同于严重缺陷。
  • 只列出风险,却不给出可执行的审查方法。

本文关注的是:

哪些风险最容易被"看起来合理"的 AI 代码隐藏,以及我们应该如何提前把它们问出来。

一、第一类坑:AI 把业务规则补错了

AI 最常见的问题,不是不会写代码,而是在信息不足时擅自做决定。

例如需求是:

text 复制代码
用户可以修改收货地址。

这句话没有说明:

  • 用户能否修改已经发货的订单?
  • 修改后是否需要重新计算运费?
  • 一个订单是否允许多次修改?
  • 地址是否需要经过风控校验?
  • 修改地址后是否需要通知仓库?

AI 可能会生成一段逻辑:

java 复制代码
if (order.getUserId().equals(currentUserId)) {
    order.setAddress(newAddress);
    orderRepository.save(order);
}

代码没有明显语法问题,但它可能绕过了订单状态、地址有效性、仓库同步和审计要求。

审查时要问什么

text 复制代码
请审查这段实现是否完整覆盖了需求中的业务规则。

请分别列出:
1. 代码明确处理的规则。
2. 代码隐含假设的规则。
3. 需求中尚未被代码覆盖的规则。
4. 需要产品或业务确认的问题。

不要因为代码可以运行,就默认业务行为正确。

看到 AI 代码中的 if、默认值和兜底分支时,要特别关注:

它是在实现已确认的规则,还是在替我们发明规则?

二、第二类坑:边界条件只写了"正常情况"

AI 很容易先完成主流程,再用几个简单判断补充异常。

但真实系统的失败场景通常不止一种。

以分页查询为例,下面这段代码看起来很常见:

java 复制代码
int offset = (page - 1) * size;
return repository.find(offset, size);

它可能遗漏:

  • page 为 0 或负数。
  • size 过大导致数据库压力。
  • (page - 1) * size 整数溢出。
  • 排序字段不稳定导致分页重复或漏数据。
  • 查询结果为空时的返回约定。
  • 用户是否有权限查看全部数据。

建立边界检查表

类型 需要检查的内容
空值 null、空字符串、空集合是否有明确行为
数值 0、负数、最大值、溢出和精度
字符串 长度、格式、特殊字符和编码
集合 空集合、重复元素、超大数量
状态 状态已完成、已取消、已删除时还能否操作
时间 时区、过期、跨天和并发时间窗口
资源 文件不存在、网络超时、数据库连接失败

可以让 AI 专门做第二轮边界审查:

text 复制代码
请不要修改代码,只审查边界条件。

请按"输入、状态、时间、数据量、依赖失败、并发"六类分析:
1. 当前代码已经覆盖的场景。
2. 当前代码遗漏的场景。
3. 每个遗漏场景可能造成的结果。
4. 建议补充的测试用例。

三、第三类坑:异常处理把真实问题吞掉了

为了让程序"不要报错",AI 有时会生成过度宽泛的异常处理:

java 复制代码
try {
    return paymentClient.pay(request);
} catch (Exception e) {
    log.error("支付失败", e);
    return PayResult.failed();
}

这段代码的问题不只是捕获范围太大。

支付请求超时,并不一定代表支付没有发生。如果直接返回失败,用户可能再次支付,最终形成重复扣款。

异常审查至少要确认:

  • 捕获的异常是否过宽。
  • 是否区分参数错误、业务拒绝、超时和系统故障。
  • 异常发生时数据是否已经部分写入。
  • 是否需要回滚、重试或人工补偿。
  • 返回给用户的信息是否足够明确。
  • 日志是否保留了排查所需的上下文。

可以使用这段 Prompt:

text 复制代码
请审查这段代码的异常处理,不要只检查有没有 try-catch。

请逐项回答:
1. 哪些异常可以直接返回失败?
2. 哪些异常代表结果未知,不能简单重试?
3. 是否存在部分成功或部分写入?
4. 是否可能吞掉真正的系统故障?
5. 日志和用户提示是否分别满足排查与体验需要?
6. 是否需要回滚、幂等、重试或补偿机制?

异常处理的目标不是"所有情况都返回一个结果",而是让系统在失败时保持可理解、可恢复。

四、第四类坑:权限校验写了,但位置不对

AI 经常会补充权限判断,但权限并不只是一个 if

下面这段代码看起来像是做了权限控制:

java 复制代码
if (!currentUserId.equals(request.getUserId())) {
    throw new ForbiddenException();
}

但它仍然可能存在问题:

  • request.getUserId() 是否可以被用户篡改?
  • 管理员是否拥有特殊权限?
  • 资源实际归属是否需要从数据库查询确认?
  • 查询接口是否已经在权限校验前返回了敏感信息?
  • 列表接口是否只校验了页面,而没有校验每条资源?
  • 删除、导出、批量操作是否使用了同样的权限规则?

审查权限时,我会让 AI 先画出"身份、资源、动作"的关系:

text 复制代码
谁:当前用户、管理员、服务账号
对什么:订单、文件、用户资料
做什么:读取、修改、删除、导出
在什么条件下:资源归属、组织范围、状态限制

对应 Prompt:

text 复制代码
请审查这段代码的鉴权和越权风险。

请不要只判断"有没有权限判断",还要分析:
1. 身份来自哪里,是否可信。
2. 资源归属在哪里确认。
3. 当前用户可以执行哪些动作。
4. 是否存在水平越权和垂直越权。
5. 列表、批量和导出场景是否可能绕过单条校验。
6. 权限判断发生在敏感数据返回之前还是之后。

权限校验应该靠近业务边界,并且覆盖所有能够改变或暴露资源的入口。

五、第五类坑:SQL、命令和文件操作存在安全风险

AI 生成外部输入相关代码时,最容易出现"示例能跑,生产不安全"的问题。

重点检查这些位置:

  • SQL 拼接。
  • Shell 命令拼接。
  • 文件路径拼接。
  • URL 或重定向地址拼接。
  • HTML、Markdown 和模板渲染。
  • 反序列化和反射调用。
  • 日志内容中的用户输入。

例如:

java 复制代码
String sql = "select * from user where name = '" + name + "'";

代码可能可以执行,但输入一旦来自用户,就存在注入风险。

安全审查 Prompt 可以这样写:

text 复制代码
请对这段代码做一次输入安全审查。

请重点检查:
1. 用户输入流向了哪些数据库、命令、文件、HTML、URL 或日志位置。
2. 是否存在拼接、未编码、未校验或未限制长度的输入。
3. 当前使用的防护是否真正覆盖了对应场景。
4. 是否可能造成注入、越权、路径穿越、敏感信息泄露或资源滥用。
5. 请给出最小修改建议,不要直接大范围重写。

不要只问 AI"这段代码安全吗"。

要把输入从哪里来、最后去了哪里写清楚,审查结果才更具体。

六、第六类坑:并发、重复提交和数据一致性被忽略

很多 AI 生成的代码在单线程、单请求环境下表现正常,但线上请求永远不是这样。

典型问题包括:

  • 两个请求同时创建相同资源。
  • 先查询再插入导致重复数据。
  • 库存扣减出现超卖。
  • 重复消费消息。
  • 重试导致重复支付、重复发券或重复通知。
  • 缓存更新早于数据库提交。
  • 多个线程同时修改同一条记录。

例如:

java 复制代码
if (couponRepository.findByUserId(userId) == null) {
    couponRepository.insert(userId, couponId);
}

只要两个请求同时通过查询,就可能插入两次。

审查并发问题时可以让 AI 按时间顺序推演:

text 复制代码
请对这段代码进行并发和幂等审查。

至少模拟以下场景:
1. 两个相同请求同时到达。
2. 请求执行到一半后重试。
3. 数据库写入成功但响应丢失。
4. 消息被重复消费。
5. 外部接口超时但实际已经成功。

请说明:
- 哪一步会产生竞态。
- 当前代码是否有唯一约束、锁、版本号或幂等键。
- 可能造成什么重复或不一致。
- 应该通过代码、数据库还是消息层修复。

并发安全不能只靠 AI 在代码里加一个锁。

要结合数据库约束、事务、消息语义和业务幂等一起判断。

七、第七类坑:测试看起来很多,却没有覆盖真正风险

AI 很擅长生成测试样例,但它容易围绕"代码分支"写测试,而不是围绕"业务风险"写测试。

例如,测试覆盖了:

text 复制代码
有效参数 → 成功
无效参数 → 失败

却没有覆盖:

  • 权限不足。
  • 重复请求。
  • 状态不允许操作。
  • 依赖超时。
  • 数据库写入后消息发送失败。
  • 同一个资源被并发修改。
  • 敏感字段没有出现在响应和日志中。

可以让 AI 先做测试矩阵,而不是直接生成测试代码:

text 复制代码
请根据这段实现设计测试矩阵,暂时不要写测试代码。

请按以下类别输出:
1. 正常流程。
2. 参数边界。
3. 业务状态。
4. 权限安全。
5. 并发幂等。
6. 数据库和外部依赖失败。
7. 日志、响应和敏感信息。

每项包含:
- 前置条件
- 操作
- 预期结果
- 验证重点
- 当前测试是否已有覆盖

测试数量多,不代表风险覆盖完整。

八、一次可复用的 AI 代码风险审查 Prompt

当一段 AI 代码准备进入项目时,我会先使用下面这份 Prompt:

text 复制代码
请作为一名严格的代码审查者,审查下面这段 AI 生成的代码。

已知需求:
<填写需求和验收标准>

已知项目约束:
<填写项目分层、异常、鉴权、事务和测试规范>

请按严重程度输出问题:
- Blocker:可能导致严重数据、安全或资金问题
- High:可能导致核心功能错误或线上故障
- Medium:边界、维护性或可观测性问题
- Low:风格、可读性或改进建议

重点检查:
1. 业务规则和隐含假设
2. 空值、边界和状态流转
3. 异常、回滚、重试和补偿
4. 鉴权、越权和敏感数据
5. SQL、命令、文件和模板注入
6. 并发、幂等和数据一致性
7. 日志、监控和可观测性
8. 测试是否覆盖关键风险
9. 是否符合现有项目约定

每个问题请包含:
- 严重程度
- 文件和代码位置
- 问题描述
- 触发条件
- 可能后果
- 最小修改建议
- 建议增加的测试

如果没有足够上下文,请明确列出"无法确认项",不要自行假设。

最后请给出:
1. 必须修复的问题
2. 建议修复的问题
3. 可以暂不处理的问题
4. 进入测试前还需要补充的上下文

这份 Prompt 的价值在于,它要求 AI 说明"什么情况下会出问题",而不是只给出模糊评价。

九、我会按这 3 轮审查,而不是只问一次

一次审查通常不够。

我更倾向于分三轮进行:

第一轮:需求一致性

text 复制代码
这段代码是否实现了正确的业务规则?

重点看范围、状态、权限和隐含假设。

第二轮:工程可靠性

text 复制代码
这段代码在异常、并发、重试和依赖失败时是否可靠?

重点看事务、幂等、数据一致性和可恢复性。

第三轮:交付完整性

text 复制代码
这段代码是否有足够的测试、日志、监控和文档支持?

重点看验证闭环,而不是只看主流程。

分轮审查的好处是避免把所有问题混在一起,也方便开发者逐项处理。

十、我的 AI 代码埋坑检查卡

在合并 AI 生成的代码前,我会快速确认:

text 复制代码
[ ] 业务规则不是 AI 自行猜出来的
[ ] 范围、状态和边界条件已经明确
[ ] 异常不会被宽泛捕获后静默吞掉
[ ] 失败时的数据状态可以解释和恢复
[ ] 鉴权覆盖了读取、修改、删除、批量和导出入口
[ ] 外部输入经过了正确校验、编码或参数化处理
[ ] 并发、重复提交和消息重复消费已经考虑
[ ] 事务、缓存、消息和外部调用的边界已经确认
[ ] 日志没有泄露密码、令牌、验证码和完整隐私数据
[ ] 测试覆盖了正常、边界、异常、安全和并发场景
[ ] 代码符合当前项目已有约定
[ ] AI 的结论已经回到源码、测试或运行结果中验证

如果这张卡还有多项无法回答,说明代码还不适合直接合并。

十一、总结

AI 生成的代码最容易埋坑的地方,通常不是语法,而是那些没有被明确写进需求的部分:

  1. 业务规则和隐含假设。
  2. 边界条件和状态流转。
  3. 异常、回滚、重试和补偿。
  4. 权限、越权和敏感信息。
  5. 输入安全和外部依赖。
  6. 并发、幂等和数据一致性。
  7. 测试是否覆盖真正的风险。

因此,拿到 AI 代码后,不要只问:

text 复制代码
这段代码能运行吗?

还应该继续问:

text 复制代码
它在什么情况下会出错?
出错后系统会处于什么状态?
它是否符合真实业务和项目约定?
我怎样用测试证明它没有遗漏关键风险?

请记住:

AI 可以快速生成代码,但只有经过风险审查的代码,才有资格进入工程系统。

下一篇文章,我们把今天的风险清单进一步固化成一套可直接复用的资产:

我的代码审查 Prompt:从"能跑"到"可维护"。

如果这篇文章对你有帮助,欢迎点赞、收藏、关注专栏。

也欢迎在评论区留言:你审查 AI 代码时,最容易忽略业务逻辑、并发问题,还是安全风险?


✍坚持原创,求关注,点赞,收藏

相关推荐
MayBaymax2 小时前
Spring AI Alibaba Graph 实战:客服工单智能处理
java·ai·ai编程
程序员Better2 小时前
我终于遇到一台懂 AI 编程的专业编程显示器!
人工智能·openai·编译器
猿人谷2 小时前
Jev:当 AI 不再生成 Token,而是直接做决策
后端·langchain·aigc
zhangfeng11332 小时前
ATK(华为算子测试平台)详细介绍 CANN(Compute Architecture for Neural Networks,神经网络计算架构
人工智能·华为·ai编程·npu·cann
杨杨杨大侠2 小时前
Jev 不是 Agent:TypeSafe System One 如何成为离 LLM 最近的决策层
aigc·openai·ai编程
plainGeekDev2 小时前
棘轮原理与实战:让 Harness 越用越可靠
aigc·ai编程·claude
外收内放3 小时前
Python与AI应用(项目开发实战:AI智能伴侣第三版)
python·学习·ai编程
zhangfeng11333 小时前
《从“人工适配“到“智能生成“:KernelSwift 跨国产芯片算子迁移全栈方案解读》 —— 强调范式跃迁和跨硬件属性,适合偏架构分析的写法
人工智能·算法·华为·ai编程·npu
OpsEye4 小时前
为什么你的 Agent 莫名烧钱?聊聊循环调用的兜底方案
javascript·ai编程