用 AI 做代码审查:提示词怎么写,它能查出什么、查不出什么

让 AI 看代码这事,效果差别极大。甩一句"帮我看看这段代码"过去,它通常会夸你一通再提两条不痛不痒的建议。换成具体的提示词,能查出来的东西多得多。

一、提示词怎么写

把四个要素给全:代码 + 上下文 + 关注点 + 输出格式

一个我常用的模板:

下面是 [语言/框架] 的代码,用途是 [一句话说明干什么],
运行环境 [版本/依赖],会被 [调用方/并发量/输入来源] 调用。

请从以下几个角度审查:
1. 空指针和未判空的访问
2. 边界条件(空数组、0、负数、超长输入、null)
3. 异常被吞掉或者资源没关闭
4. 命名和可读性
5. 重复代码

对每个问题,按下面格式输出,不要修改代码之外的东西:
- 位置:函数名 + 行号
- 问题:一句话
- 影响:什么情况下会触发
- 建议:怎么改

按严重程度排序,只报告你有把握的问题,不确定的单独列在"存疑"里。

几个让效果变好的细节:

  1. 限定关注点。一次只让它查 3 到 5 类问题,查得比你列二十条要深。
  2. 要求给位置和触发条件。不带位置的建议没法验证,等于没说。
  3. 明确要求它区分"确定"和"存疑"。这条很关键,能过滤掉大量幻觉。
  4. 给配套信息。把相关的接口定义、数据结构、测试用例一并贴进去,它才有判断依据。
  5. 小批量提交。一次喂 200 到 500 行效果最好,整个文件几千行丢过去,它会漏。

二、它能稳定查出的问题

这些是我实测命中率比较高的:

  1. 空指针和未判空。链式调用、可选字段、map 取值,基本都能点出来。
  2. 边界条件。空数组、只有一个元素、0 和负数、超长字符串、临界值。它列得比人全。
  3. 异常被吞掉catch 里什么都不做、只打日志不处理、吞掉原始堆栈。
  4. 资源没关闭。文件句柄、数据库连接、流没关,或者没用 try-with-resources。
  5. 命名和可读性。变量名单字母、函数名和干的事不符、布尔命名不带 is/has。
  6. 重复代码。几处几乎一样的逻辑,它会直接指出来并建议抽函数。
  7. 硬编码。魔法数字、写死的路径、明文密钥和 token。这一条值得单独跑一次。
  8. 明显的 N+1 查询。循环里查数据库,一眼就能看出来。
  9. 线程不安全的容器。在并发场景用了普通 HashMap、ArrayList。
  10. 拼写错误导致的 bug。变量名打错、赋值写成了比较,人眼很容易漏,它反而能抓住。

三、它查不出来的东西

这部分更值得记,因为它会给你虚假的安全感。

  1. 业务逻辑错误。扣款算错了、状态流转缺了一步,它不知道你的业务应该是什么样。
  2. 架构和分层问题。职责划分、模块边界、依赖方向,需要看整个项目才判断得了。
  3. 需求理解偏差。代码写得完美,但做的不是产品要的东西。
  4. 并发时序问题。真正的竞态、死锁、可见性问题,需要运行时分析。
  5. 性能问题的真实归因。它能看出"这里可能慢",但定位不到真正的瓶颈。
  6. 数据一致性。跨表、跨服务的一致性问题,看不到全局就判断不了。
  7. 安全漏洞的业务语境。越权访问这类问题,它不知道"什么数据该对谁可见"。
  8. 历史包袱相关的坑。某段看起来多余的代码是为了绕开一个三年前的问题,它会建议你删掉。

四、怎么嵌进日常流程

我现在的用法:

  1. 提交前自查:写完一个函数,先让它审一遍,重点看边界和空指针。这一步能挡掉大部分低级问题。
  2. PR 前第二遍:把 diff 喂给它,让它从 reviewer 视角提问题,同时自己再读一遍。
  3. 接手陌生代码时:让它解释一段代码的意图和副作用,比自己硬啃快。
  4. 专项扫描:定期只查一类问题,比如"把所有硬编码和密钥找出来",命中率比混合审查高。

五、最后一条提醒

AI 审过的代码,人还是要看一遍。它给的建议,每一条你都得能判断对不对,判断不了就先别改。

把 AI 当成第一道筛子,不是最后一道。它能帮你省掉读代码的体力活,省不掉"这段代码对不对"这个判断,那部分是你的活。

返回AI编程