跳转到主要内容

将 Eval 作为 Pull Request 评论而非任务:在代码审查中嵌入 LLM 质量门禁

阅读需 1 分钟Tian PanTian Pan

许多自称“有评估(evals)”的团队,其实际情况是:有一个仪表板,某人每周运行一次测试套件,然后将数据粘贴到没人看的 Slack 频道。评审人员批准提示词(prompt)更改时,甚至根本没看过它是否影响了测试套件,而回归问题(regression)两周后才在客户反馈单中显现。评估确实存在,但评估并未进入开发循环。

解决办法在于结构,而非意愿。只有当评估存在于变更发生的地方——即 Pull Request(PR)评论中,紧挨着代码差异(diff),并带有单个 PR 的增量变化和评审员无法忽视的回归提醒时,评估才能真正起到质量把关的作用。在其他任何地方,它们都只是表演性的产物:投入了大量精力构建,却什么也拦截不到。

值得效仿的模式早已存在于你的代码库中。代码覆盖率(Code coverage)在 20 年前也经历过同样的历程:从一个没人点开的 HTML 报告的夜间任务,演变为在 PR 中以置顶评论形式发布的增量报告,并带有逐文件提醒。大多数工程师已经不记得覆盖率不在行内显示的时候了,而这正是重点——一旦反馈与变更相邻,这种实践就无需推销而能自发延续。

什么是实践中所谓的“我们有评估”

走进任何一个开展大语言模型(LLM)工作超过一个季度的团队,询问他们的评估在哪里运行。答案几乎总是一样的:有一个脚本,针对“黄金数据集”运行,结果保存在 Notebook、电子表格中,或者如果团队更成熟的话,保存在一个托管的仪表板上。在发布前、通过定时任务(cron)或是在产品经理(PM)询问“我们的摘要功能改进了吗?”时,手动调用该脚本。

这种设置将评估变成了一项“任务”——一种你需要触发、观察运行并进行解读的事。任务具有惯性。一个需要 10 分钟的任务不会在每次提交时触发;一个生成百行表格的任务不会在每次提交时被阅读;一个存在于代码评审工具之外的任务不会阻碍代码合并。团队制造了一个测量仪器,却把它放在了离实验现场三个房间远的地方。

自然的偏移是显而易见的。评估只会在想起来运行的日子运行。涉及提示词修改的 PR 往往基于工程师“感觉还行”以及评审员在阅读新模板时没发现明显错误而合并。评估在运行时,往往在某个没人注意的片段中倒退了两三个点,而团队并不会将这种回归与导致它的合并关联起来,因为在合并发生的地方,这种关联是不可见的。

这并非评估框架的工具性失败。框架本身没问题——DeepEval、promptfoo、Braintrust、Latitude、Traceloop 以及其他数十种工具都能在黄金数据集上生成称职的指标。失败的原因在于,这些指标产生的地方并非做出合并决策的表面。

代码覆盖率做对了什么

作为指标,代码覆盖率一直都很薄弱。运行到某行代码不等于测试了它;一个返回错误类型的函数如果有 100% 的覆盖率,也依然是 100% 覆盖;追求数字的团队会写出只跑行数而不验证行为的测试。尽管如此,覆盖率作为一种“实践”能够存续,是因为一个具体的原因:报告进入了 PR 评论。

演进过程至关重要。早期的覆盖率工具生成 HTML 报告——这是一个在浏览器中打开的目录,逐行显示颜色标注。它们确实有用,但几乎没人用。下一步是仪表板,托管在团队 Wiki 中某个逐渐失效的链接上。更有用一点,但对合并决策依然没有承重作用。让覆盖率坚持下来的原因是每个 PR 上自动置顶的机器人评论,它包含三项信息:整体覆盖率百分比、与基准分支的增量,以及覆盖率下降的已修改文件列表。

第三项信息才是真正起作用的。知道整体覆盖率从 87.2% 降到 87.1% 是一个可以被合理化忽视的事实。但知道在这个特定的 PR 中,payments/refund.ts 的覆盖率从 94% 降到了 71%,这是评审员一定会质问你的事情。差异(diff)与指标并列,且指标范围限定在变更内,而不是汇总在整个代码库中。

现代覆盖率操作进一步加强了这一点:当你推送新提交时,它们会重新编辑同一条评论,而不是堆叠便签;它们仅显示 PR 中修改的文件以减少噪音;如果变更文件的增量超过阈值,它们会让检查失败。这些单看都不稀奇。但结合在一起,它们让覆盖率成为了代码评审中自然发生的一环,无需任何人特意要求。

有效 PR 评论背后的工程投入

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 11 分钟

Prompt 修改不只是措辞变动:将 Prompt 视为软件的代码审查规范

Prompt 修改看起来像是英语,但行为表现却像代码。通过配对评估与 Prompt 的 PR、行为差异注释以及划分审查角色等规范,在用户发现之前捕捉行为回归。

insider
llm
阅读需 8 分钟

那些悄然成为你唯一评测集阅读者的提示工程师

你的评测集只是一个文件,而使其具备可读性的判断力却存在于某个工程师的脑海中 —— 本文将探讨这种巴士系数如何在他们离职后才显现出来。

insider
evals
阅读需 8 分钟

你在廉价模型上测试,却在昂贵模型上部署

在廉价模型上运行 CI 和评估,而生产环境却使用尖端模型,这在最关键的地方破坏了开发与生产环境的一致性。本文将探讨为什么层级差距会使你的评估门控失效,以及缩小这一差距的预算计算方法。

insider
llm
阅读需 10 分钟

被你的模型视为“约束性判例”的 Few-Shot 示例

Few-shot 示例并非中立的演示 —— 它们是“判例法”。模型会通过表面 Token 绑定到最接近的示例,并继承其约束,从而输出评估套件无法察觉的、充满自信的错误答案。

insider
llm
阅读需 9 分钟

提示词 Diff 隐藏了自身的爆炸半径

一个三个单词的提示词修改和一段三个段落的重写在文本 Diff 中看起来并无二致,但其行为后果却大相径庭。为什么提示词审查需要评估增量,而不是字符计数。

insider
prompt-engineering