最近打回 AI 写的 PR 越来越勤。说它写得差倒不至于,速度和整洁度它都超过我了。麻烦在另一个地方:拿人写代码的老标准去评机器写的代码,评不出重点。
我把现在的处置标准压成了 3 条规矩,先全部摆出来:
| 规矩 | 触发条件 | 处置 |
|---|---|---|
| 1 | 三态不齐(loading / error / empty) | 直接打回,不商量 |
| 2 | AI 的需求理解没随 PR 提交 | 打回,先补材料 |
| 3 | diff 里混进任务外的「顺手改动」 | 打回,越权行零容忍 |
第 1 条争议最大,因为它明摆着是双标。往下看我的理由。
规矩一:三态不齐,直接打回
AI 生成的前端代码有一种天然的迷惑性:看起来对。UI 能点,数据能显示,演示的时候网络刚好也好。它默认产出 happy path,不是它笨,是你给的上下文里只有 happy path。
一个典型的 AI 产出,数据列表组件:
function OrderList() {
const { data } = useQuery({ queryKey: ['orders'], queryFn: fetchOrders });
return (
<ul>
{data.map((o) => (
<li key={o.id}>¥{o.amount.toFixed(2)}</li>
))}
</ul>
);
}
演示的时候毫无问题。但 React Query 在请求成功之前 data 是 undefined,接口一抖动,这行 data.map 直接白屏;接口报错,用户看到的还是白屏,一条提示都没有。
打回标准很具体:三态补齐才算完成。
function OrderList() {
const { data, isLoading, isError, refetch } = useQuery({
queryKey: ['orders'],
queryFn: fetchOrders,
});
if (isLoading) return <Skeleton rows={3} />;
if (isError) return <ErrorState onRetry={refetch} />;
if (data.length === 0) return <EmptyState />;
return (
<ul>
{data.map((o) => (
<li key={o.id}>¥{o.amount.toFixed(2)}</li>
))}
</ul>
);
}
这条被质疑得最多,理由很整齐:人写的组件三态不齐的时候,你怎么就留个 comment 提醒一下,合了?
对,就是双标。我的理由:打回人的代码,对方一下午白干,还搭一次不愉快的沟通;打回 AI 的代码,它重跑三分钟。这个动作变便宜了,标准还停在原地,那才是浪费。
顺着这个逻辑还有个推论:AI 的 PR 我要求得比人更严,反正它改起来不心疼。
规矩二:理解不随 PR 提交,就是盲盒评审
规矩二管的是另一件事:AI 对需求的理解,代码倒是其次。它以为的「列表要分页」和产品说的「列表要分页」,中间可能隔着一万个默认值。
所以任务描述必须贴进 PR。看不到它以为什么是需求,这 PR 就没法评,你评的是盲盒。
我现在的 PR 描述固定三段:
## 需求原文
(产品的话原样贴,不改写、不翻译成技术语言)
## AI 的计划
(agent 的 plan 输出原样贴,含它打算动的文件清单)
## 我纠正过的理解
(它哪条理解错了、我改成了什么,这段是评审最该看的)
第三段最值钱。Claude Code、Codex 这类 agent 都有计划模式,先让它列方案再动手,那份计划输出就是现成的评审材料,比从 diff 里反推它当时在想什么省事得多。
评审动作也跟着变了。以前逐行看代码猜意图,现在先看「它的理解」和「需求原文」差多少,再决定代码细看到什么程度。理解全对的,代码扫一眼结构就行;理解跑偏的,diff 再漂亮也白搭。
规矩三:任务外的顺手行,零容忍
AI 修一个按钮对齐,能顺手把半个目录按 prettier 重排一遍,删两个它判定没人用的导出,再把某个依赖悄悄升个小版本。
人干这种事叫顺手,机器干这种事叫越权。人会为自己的顺手负责,机器不会:它不记得自己顺手改过什么,等下次出问题排查的时候,这些混在任务 diff 里的无关行全是噪音。
识别方法很机械:diff 的文件清单和任务对不上,就有越权。比如一个「修复按钮文案对齐」的 PR 里出现这个:
--- a/package.json
+++ b/package.json
@@
- "react": "^18.3.1",
+ "react": "^19.0.0"
不用看第二眼,打回。格式化噪音和依赖版本好认,难的是「删了没人用的导出」:前端项目里动态引用、字符串调用、被构建脚本扫的导出太多了,AI 的静态分析看不见这些。
规矩三是三条里最没有讨论空间的。规矩一你还可以吵吵双标合不合理,规矩三连吵的余地都没有。
给 AI 的打回评论,和人写的不是一种东西
打回之后怎么写评论,是我最近才想明白的环节。
给人写评审意见,重点是把 why 讲清楚,因为人需要被说服;给 AI 写,重点是把 what、边界、验收标准给足。它执行 what 的效率极高,领会 why 的能力很差。
问题:OrderList 在加载中和请求失败时白屏
要求:补三态(骨架屏 / 错误态带重试 / 空列表态)
边界:只改 src/components/OrderList.jsx,不要动其他文件
验收:DevTools 里切 offline 刷新页面,不白屏
四个字段里最值钱的是「边界」。不写边界,它修 OrderList 的时候顺手把整个 components 目录「优化」一遍,正好撞回规矩三。
我自己用下来的体感:这种填空式的打回,一次返工就过的比例高了不少,比「这里有点问题你看看」管用。现在打回全是填这个。
打回的能力,是有保质期的
最后说个我的真实感受。
「看起来没问题就合」这件事有隐性成本。三个月后你可能就打不动它了,权限都在,但读不动了:它的产出速度早就超过你逐行确认的速度,等你只能扫一眼 diff 就点合并的时候,标准想立也立不住。
外面也差不多是这个方向。arXiv 今年有论文专门讨论 agent 时代的 code review 怎么重新设计,CodeRabbit 这种 AI 审 AI 的机器人快成开源项目的标配了。连 Anthropic 自己的研究都被拉到 Reddit 上吵了一圈:AI 辅助编码的效率提升没那么大,还可能影响开发者的能力。
评审这条流水线上,人还说了算的地方不多了,打回算一个。
你们团队现在 AI 生成的 PR,过评审用的是和人同一套标准吗?规矩一这种「该不该双标」,我站更严这边。你呢?