代码写完之后,真正花时间的往往不是写,而是看。尤其是接手别人的项目,或者隔了几个月回头改自己写的东西,光是把上下文重建起来就要费不少功夫。AI 在这一步确实能帮上忙,但前提是你别只说「帮我看看有没有问题」——那样它只会回你一堆不痛不痒的客套建议。
先分清两件事:审查和重构
代码审查是找问题:边界条件漏了、异常没处理、命名误导人、存在安全隐患。重构是改结构:把重复逻辑抽出来、把过长的函数拆开、把耦合的部分解耦。这两件事的提示词写法完全不同——审查要它「别改代码,只列问题」,重构要它「保持外部行为不变,只调整内部实现」。
把两件事塞进一句话里问,AI 通常会把两边都做一半:问题没找全,改出来的代码你也不敢直接用。比较实用的做法是分两轮——第一轮只让它读代码、列问题清单,你挑出真正要改的几条;第二轮再针对挑出来的问题让它改。这样每一次改动你都有明确预期,出问题也能定位到是哪一步引入的。
如果你的 AI 每次都先说「这段代码整体不错,不过可以考虑……」,再给三条无关痛痒的建议,那多半不是模型不行,而是你没给它一个可执行的检查标准。
审查提示词:给它一份清单,而不是一个请求
空泛的提问只会换来空泛的回答。有效的做法是在提示词里交代清楚三件事:这段代码的运行场景(谁调用、输入从哪来、出错会怎样)、你关心的维度(正确性、可读性、性能、安全)、输出格式(按严重程度排序,每条给出代码位置和具体建议)。
还有一点:要求它说出「为什么」。如果它指出某一行有问题,就让它说明在什么输入下会出问题。说不出来的建议,多半是根据代码风格猜的,可以直接忽略。这个习惯能帮你过滤掉大部分无效输出。
把清单固定下来
反复用下来你会发现,值得关心的就那几类。把它们固定成一份清单,每次审查都带上,效果比每次临时描述稳定得多。
边界条件:空输入、超长输入、并发调用、重复提交。这几类是线上问题的高发区,也是人工审查最容易漏的地方,可以专门让它从这几个角度各过一遍。
错误处理:异常是不是被静默吞掉了、失败之后有没有重试或兜底、日志里能不能定位到具体是哪一次请求出的问题。
可读性:命名和实际行为是否一致、一个函数是不是做了不止一件事、注释是在解释「为什么」还是只是复述「做了什么」。
安全:用户输入有没有直接拼进查询或命令、密钥有没有硬编码在代码里、外部传入的数据有没有做校验。
重构:先定边界,再让它动手
重构最大的风险是「顺手改坏了」。所以第一步不是让它改,而是让它先描述这段代码现在到底做了什么——包括副作用、依赖了哪些外部资源、被谁调用。如果它描述出来的和你理解的不一致,说明要么代码本身太绕,要么它没读全,这时候先别往下走。
确认之后,给它一条硬约束:外部行为不变。函数签名、返回值、抛出的异常都保持原样,只允许调整内部实现。有了这条约束,你可以拿原来的测试直接验证改完是否等价;如果本来就没有测试,那就先补几个最典型的输入输出用例,再让它动手。
改动范围也要收紧。一次只让它动一个函数或者一个模块,别把整个项目丢过去。范围越大,它越容易顺手改到不相关的地方,你 review 的成本反而更高。
常见问题
代码一次贴多长合适?
以一个函数或一个类为单位、几百行以内比较稳妥。太长的话它容易只注意开头和结尾,中间的逻辑一带而过。如果一个文件确实很大,就按功能拆成几段分开问。
会不会把能跑的代码改成跑不通的?
有这个可能,所以别让它直接覆盖原文件。让它把改动后的完整版本贴出来,你人工对比一遍再合并。凡是改动超出了你要求的范围,都要单独追问一句为什么。
能替代人工 review 吗?
不能。它擅长机械性的检查——空值、异常、命名、重复代码;不擅长业务语义,比如某个字段在这个场景下是不是应该允许为空。把机械的部分交给它,把业务判断留给人,两边都不浪费。