深度分析 AI bot 充斥代码审查导致 PR 质量不升反降,揭示问题的根本在于组织流程而非工具本身。
今年,我们的团队扩大了,PR 的数量也随之增长,而且增长速度显然比 ticket 的产生速度更快。新人加入,意味着有更多代码在流程中流转,却不意味着大家掌握了更多上下文。许多大型 PR,光是读懂就需要真正动脑思考:它要解决什么问题,为什么采用这种方案,其中真正重要的是什么,哪些只是附带细节。代码越来越多,共享理解却没有增加——我们的麻烦正是从这个缺口开始的。
当代码审查变得越来越难、越来越慢时,人们自然开始借助工具,试图跟上节奏。现在,我们有一个 AI code review bot,会自动审查每个 PR;与此同时,不少人也会在本地运行自己选择的 LLM 和 coding agent,用它们起草审查意见。把这两件事放在一起,结果正如你所料:一个 bot 在 PR 里发表评论,另一个 bot 回复它。有些被报告出来的 bug,本来就是 LLM 凭空编造的,但模型会以无比确信的口吻陈述它们,尽管它根本无从知道这些 bug 并不存在。这正是 AI 编程辅助的一项切实弊端:自信地犯错。
评论开始不像署名同事本人写出来的了。冗长啰嗦。无论当下是否真的需要,所有可能相关的参考资料和引用都会一股脑塞进去。我们的团队习惯用自己的话直截了当地讨论代码,但 PR 里却开始充斥 AI 垃圾内容。
有一种抱怨出现了不止一次:为了获得真正的上下文,大家不得不离开 PR,在讨论串之外找人沟通,或者询问某个模型。因为评论本身要么没有真正提供足够的信息,要么塞了实在太多、太多的废话。Pull request 评论存在的全部意义,就是让你不必为了理解它而去其他地方查找信息。
还有一个问题:内容重复,以及重复阅读的成本。用一整段文字解释一段你一分钟就能直接读懂的代码,并不能替你节省时间。相反,它会额外消耗你的时间,而这还没算上这条评论原本声称能帮你省下的自行分析时间。
团队里有人说得很直接:现在还不确定怎样才算恰当的平衡,但整个范式显然已经发生了变化。这个判断很合理。不太合理的是,认定我们现在的做法就是唯一可行的方式。
人的注意力才是最稀缺、最值得严防死守的资源。把生产成本极低、消费成本却极高的冗长文字强加给彼此,应该被视为一种真正的反模式。
这种状况持续几周后,我们的 CEO 在 Slack 里说了一番话,对我来说真正点中了整个问题的核心。大家对 PR 审查的抱怨确实存在,但那只是症状,而不是病因。他的观点是:真正的瓶颈并不特指 PR 审查,而在于技术娴熟的队友所拥有的注意力是有限的,却很容易被 LLM 生成的内容淹没。人的注意力才是最稀缺、最值得严防死守的资源。把生产成本极低、消费成本却极高的冗长文字强加给彼此,应该被视为一种真正的反模式。他把这个概念称为 Return-on-Attention,即 ROA:你要求别人阅读的每一个字,都必须对得起对方为阅读它所付出的成本。
他用同一周发生的两个例子佐证了这一点。有几份 ADR 包含大量重复内容,一位同事不得不从头到尾全部读完。ROA 糟透了。还有一个 PR,只是在 gitignore 中忽略一个目录——一行代码、十个字符——却附带了一段长达 1,430 个字符的描述。对负责审查它的人来说,ROA 同样糟透了。
这两个例子都与代码质量无关。它们都在追问同一件事:为了给自己省下三十秒的编辑时间,你究竟有权消耗别人多少注意力?
同样的概念也有一个公开流传的版本。noslopgrenade.com 将它称为“slop grenade”:在聊天或邮件中粘贴一大段 AI 生成的回复,而同样的内容如果由人来写,可能一句话就够了。这个说法针对的是聊天,而不是代码审查,但两者的失败模式完全相同。LLM 可以毫不费力地生成远超任务所需的文字,但这些多余内容的成本并不会凭空消失,只会转移到不得不阅读它们的人身上。
我发现自己身上也存在同样的倾向,只不过不是作为审查者,而是作为思考者。有一段时间,我还没真正静下心来思考问题,就先把它交给模型。我能感觉到,自己对工作流程的要求正在变得松散。并不是因为模型给出的答案有错,而是因为我不再先自行理清问题,然后再提出问题。
我也正在和 Claude 的一个具体习惯较劲:它喜欢把设计决策的过程直接叙述到评论和代码里。“我们选择了这个,而不是那个。”即使没有收到相关 prompt,这类话也会自己冒出来,而且从来没有真正帮到过我。这种决策应该写在 PR 描述或 commit message 中,因为那里有上下文、日期和作者。把它放在代码注释里,只会成为噪声。下次有人改变想法后,这条注释就会变成错误信息,而且不会有人记得删除它。我正在专门构建一个 skill,用来阻止 Claude 把这种模式写进代码库。
Bot 审查本身不是问题。错误地使用它才是。
如果它能为审查者提供一个自己原本不会发现的视角,或者找出一个 bug、一个被遗漏的边界情况、一个确实存在于 diff 中的问题,那么它就很有用。这才是真正提供帮助的第二双眼睛。
一旦它消耗的阅读注意力超过了它能节省的注意力,它就不再有用。审查的目的,是交付价值,并在人与人之间传递知识。代码质量之所以重要,是因为它服务于这些目标,而不是反过来。如果一条评论让代码稍微变好了一点,却让审查者疲惫了许多,那么这笔交换并不值得。
我有一条自己遵循的规则:当你发布一条审查评论时,它的署名是你。当然,coding agent 也许算得上共同作者……但后续需要跟进的人并不是它。PR 作者有问题或异议时,要找的人也不是它,而是你。PR 作者无从知道这条评论究竟是怎样写出来的。当然,他们很可能猜得到,尤其是当你满篇都在用长破折号的时候。他们会把它视为你的判断,以你的口吻来理解,并像对待你亲手输入的每一个字那样,要求你为它负责。
所以,在点击提交之前,你应该用这个标准检查它:这些话,你本人会以这样的篇幅、这样的语气说出来吗?如果答案是否定的,解决办法并不是写一个更好的 prompt,而是动手编辑。删掉那些不属于你的内容。