如果你想知道 AI 生成的代码好不好,你面临一个根本性困境:人类专家太贵,测试用例太慢,而 benchmark 的分数往往测的是另一个问题。

LLM-as-Judge 的思路是:用 AI 来评价 AI。但这条路有一个致命弱点——评价者自己的偏见,会系统性地扭曲评价结果。

本篇深入解析 LLM-as-Judge 在代码评测领域的应用:它为什么被广泛采用,它的三种主要偏差,以及如何在实战中正确使用它。


目录


一、为什么需要 LLM-as-Judge

1.1 传统评测的三重困境

在 AI 编程工具的评测中,传统做法依赖两种机制:

基于测试用例的评测(Test-based Evaluation)

这类评测的核心是:为每个测试问题准备一个或多个标准答案(ground truth),然后将模型生成的代码与标准答案进行比对。SWE-bench 就是这个思路的典型代表。

这个方法的问题在上一期博客中已有详细讨论:

基于人类评估的评测(Human Evaluation)

顾名思义:请人类专家来判断 AI 生成的代码质量。这是 gold standard——最准确,但代价最高、速度最慢,无法规模化。

基于规则的自然语言评测(NLP-based Evaluation)

用 BLEU、ROUGE 等文本相似度指标来比较模型输出与参考答案。这类指标源自机器翻译领域,对代码评测尤其不适用——两段实现相同逻辑的代码,token 序列可能完全不同,但质量完全一样。

1.2 LLM-as-Judge 的出现

LLM-as-Judge 的出现,是这三重困境共同推动的结果:测试用例覆盖不了复杂场景,人类评估成本太高,规则指标又不适用于代码。

核心思想是:既然 LLM 能够理解代码的语义和逻辑,就让它来扮演”裁判”的角色,直接判断给定的代码是否正确、是否高效、是否遵循最佳实践。

传统评测链条:
  模型生成代码 → 与 ground truth 比对 → 输出分数
  局限:必须先有 ground truth

LLM-as-Judge 链条:
  模型生成代码 → LLM 裁判理解代码 → LLM 裁判直接评判 → 输出分数
  优势:不需要 ground truth,LLM 的理解能力替代了标准答案

这个思路在 2023 年左右开始流行,主要应用于自然语言生成任务的评测。到 2024 年,SWE-bench 团队正式将其引入代码评测领域,创建了 SWE-bench Verified,开启了 LLM-as-Judge 在代码评测中的工业级应用。


二、两种评测范式的根本差异

在深入 LLM-as-Judge 之前,需要理解它与 test-based evaluation 的本质区别——这决定了两种方法各自擅长什么、不擅长什么。

2.1 Test-based Evaluation:比较输出

Test-based evaluation 比较的是输出。你给模型一个问题,模型生成一段代码,然后你运行这段代码,看测试用例是否通过。

这个范式的核心假设是:代码的正确性可以通过行为来验证——如果代码通过了所有测试用例,它就是正确的。

这个假设在很多场景下成立,但存在两个根本性问题:

第一:测试用例覆盖率有限

PlayEval 的实验直观地展示了这个问题:对于 GUI 应用,代码可以”编译通过 + 运行不崩溃 + 测试用例全过”,但实际上违反了用户交互的核心逻辑(”小鸟穿过管道”)。测试用例测的是行为的一个子集,不是全部行为。

第二:ground truth 的构建本身需要成本

SWE-bench 的数据来自真实 GitHub Issue-PR 对。创建每一个测试实例,需要人工找到真实存在的 bug、验证修复 patch 确实有效、构建完整的测试环境。这个成本决定了测试实例的数量是有限的——SWE-bench Full 有约 12,000 个实例,但经过质量筛选的 Verified 版本只有 1,000 个。

2.2 LLM-as-Judge:理解语义

LLM-as-Judge 的核心假设是:LLM 能够理解代码的语义,从而判断给定实现是否解决了指定问题

这不再是”比对输出”,而是”理解任务 + 理解实现 + 理解两者关系”。

这个范式解耦了两个关键能力:

当两者由同一个模型承担时,我们无法区分”模型做对了是因为理解了任务”还是”因为它背住了答案”。但 LLM-as-Judge 可以在一定程度上缓解第二个问题——裁判模型看到的是 Issue + PR 的组合,而不是单个问题的标准答案。

2.3 两种范式的互补关系

Task: 用 LLM 写一个快排算法
  ↓
Test-based: 运行代码 → 检查排序结果是否正确 ✓
LLM-as-Judge: 判断代码逻辑 → 验证分治策略是否正确实现 → 识别边界条件处理

Task: 评估代码是否遵循安全最佳实践
  ↓
Test-based: 难以覆盖(安全漏洞不一定有测试用例)
LLM-as-Judge: 可以直接分析代码的安全属性 ✓

两种范式不是替代关系,而是互补关系。Test-based 擅长验证行为,LLM-as-Judge 擅长理解语义。


三、LLM-as-Judge 的三种实现架构

根据裁判模型与被测代码的关系,LLM-as-Judge 有三种主要实现架构:

3.1 Pairwise Comparison(成对比较)

同时给裁判模型两个候选答案(A 和 B),要求它判断哪个更好。

Prompt:
  问题:[用户需求描述]
  答案A:[候选代码A]
  答案B:[候选代码B]
  
  请判断哪个答案更好地解决了问题,并说明理由。

优点

缺点

应用场景:模型选择(”我应该用 Claude 还是 GPT 来完成这个任务?”)、Prompt 优化对比(”A/B 测试两种不同的 system prompt”)

3.2 Reference-based Scoring(参考评分)

给裁判模型一段代码和一个参考解决方案,要求裁判判断代码相对于参考方案的优劣。

Prompt:
  问题:[需求描述]
  参考解决方案:[专家代码]
  待评测代码:[候选代码]
  
  请评估候选代码与参考方案的差距,给出 0-10 的评分并说明理由。

优点

缺点

应用场景:AI 编程比赛的自动化评分、代码优化任务的评估

3.3 Reference-free Evaluation(无参考评测)

裁判模型仅凭问题描述和候选代码,判断代码质量,不依赖任何参考解决方案。

Prompt:
  问题:[需求描述]
  待评测代码:[候选代码]
  
  请评估这段代码是否正确解决了问题,给出通过/不通过/部分通过的评价。

优点

缺点

应用场景:SWE-bench Verified 的核心评测逻辑、企业内部无标准答案的代码审查

SWE-bench Verified 采用的是 Reference-free Evaluation 的变体:裁判模型会先阅读 Issue(理解任务),然后阅读候选 PR(理解实现),最后判断”这个 PR 是否解决了这个 Issue”。没有标准答案,只有裁判的独立判断。


四、核心偏差:为什么裁判也会犯错

LLM-as-Judge 的最大陷阱,是把裁判模型当作一个客观的评测工具。但裁判模型也是一个 LLM,它有自己的认知偏见,这些偏见会系统性地影响评价结果。

4.1 长度偏差(Length Bias)

长度偏差:裁判模型倾向于认为更长的回答质量更高。

这是一个被广泛证实的现象。在 LLM-as-Judge 的研究中(论文:「The Cost of Clarity」),研究人员发现,当两个答案质量相同时,裁判模型会选择更长的那一个。

在代码评测中,这个偏差会直接影响结果:

例子:
  问题:"写一个函数检查字符串是否是回文"

  答案A(短,正确但简洁):
    def is_palindrome(s):
        return s == s[::-1]

  答案B(长,包含详细注释和边界处理):
    def is_palindrome(s: str) -> bool:
        """
        检查字符串是否为回文。
        忽略大小写和非字母数字字符。
        """
        # 预处理:转小写并移除非字母数字字符
        cleaned = ''.join(c.lower() for c in s if c.isalnum())
        # 核心比较
        return cleaned == cleaned[::-1]

  裁判的典型倾向:选择 B(因为更长、更详细)
  但在功能上两者都是正确的

在代码评测中的后果:能够生成更长、更详细注释和文档的模型,会系统性获得更高的评分,即使它们的功能正确性与短代码完全相同。

缓解方法

4.2 位置偏差(Position Bias)

位置偏差:裁判模型倾向于选择位于特定位置的答案(在 pairwise 比较中通常是第一个或第二个)。

这个偏差的来源尚不完全清楚,但一个主要假设是:注意力分布不均匀。模型可能对输入的开头和结尾部分给予更多关注,而忽略中间部分。

在代码评测中的表现:

Pairwise 比较设置:
  候选A:[先出现的代码]
  候选B:[后出现的代码]
  
  结果:A 和 B 质量相同时,裁判可能系统性地偏好某个位置
  
实验数据(示意):
  A 在前时:裁判选择 A 的概率 = 55%
  B 在前时:裁判选择 B 的概率 = 55%
  → 存在 ~5% 的位置偏差(看似小,但足以影响排名)

这个偏差在激烈的竞争中至关重要:如果两个模型真实得分差距只有 1-2%,而裁判有 5% 的位置偏差,结果可能是完全颠倒的。

缓解方法

4.3 自我偏好偏差(Self-Preference Bias)

自我偏好偏差:裁判模型倾向于认为与自己同源的模型生成的答案更好。

这在代码评测中是最危险的偏差,因为它引入了系统性的不公平:如果用 GPT-5 做裁判,Claude 生成的代码可能系统性得分更低(反之亦然)。

这个偏差与模型的对齐方式(RLHF/PPO)相关——模型的偏好受到训练数据的影响,而这些偏好会延伸到它的评判行为中。

在代码评测中的具体表现

实验设置:
  裁判模型:GPT-5
  被测模型:Claude 4.6 vs GPT-5(同类)
  候选代码质量:Claude 实际更高(由人类专家判定)

  结果:GPT-5 裁判可能系统性给 GPT-5 的代码更高分
  这不是"裁判失职",而是模型自身的偏好被引入评测

SWE-bench Verified 意识到了这个问题,采用的做法是:使用与被测模型不同来源的裁判模型进行评测。但这不能完全消除自我偏好——因为相似训练方式(如 RLHF)的模型之间可能存在隐性偏好。

缓解方法

4.4 裁判能力天花板(Judge Capability Ceiling)

最后一个问题不是偏差,但同样关键:裁判的质量受限于裁判模型的能力本身

如果裁判模型对某个编程语言、某个框架、某种范式不够了解,它的评判就会出现错误——不是因为偏见,而是因为不理解。

例子:
 裁判模型:Claude 3(对 Rust 的所有权系统理解有限)
 被测代码:一段使用复杂生命周期标注的 Rust 代码
 裁判判断:"这段代码看起来有问题"(但实际上代码是正确的)
 原因:裁判对 Rust 生命周期的理解不够深入

这引出了一个关键的设计决策:裁判模型应该比被测模型更强,还是可以不同但互补?

直觉上我们倾向于”裁判应该更强”,但实际上,当裁判模型与被测模型使用相同的训练数据时,”更强”往往意味着”更大”——而更大的模型可能恰好是你们正在评测的那个。这种循环依赖(用要评测的模型来做裁判)是需要避免的。


五、SWE-bench Verified:LLM-as-Judge 的工业级实践

SWE-bench Verified 是 LLM-as-Judge 在代码评测领域最知名的工业应用。理解它的设计选择,对于如何在实战中使用 LLM-as-Judge 有直接指导意义。

5.1 为什么需要 SWE-bench Verified

SWE-bench Full 存在一个根本性问题:评测的可靠性存疑

SWE-bench Full 的评测完全依赖测试用例的执行结果。但这些测试用例是 GitHub 仓库原有的——它们的设计目的是验证代码变更,而不是验证 AI 的代码生成能力。

这导致两类问题:

测试泄露(Test Leaking):某些测试用例可能在模型的训练数据中出现过,模型”背住了测试用例”而非真正理解了代码修复逻辑。这不是理论担忧——Swarm Tax 论文通过 paraphrase 测试证实了这个现象:改写问题措辞后,某些模型的分数下降超过 30 个百分点。

Harness 不稳定:Claude 降级门事件揭示,SWE-bench Full 的评测结果受到 CLI 层配置的显著影响。模型本身的分数可能被工具链的问题掩盖。

5.2 SWE-bench Verified 的设计

SWE-bench Verified 的核心改进是:对于每个测试实例,先用人类专家审核确认这个实例是有效的(有明确的 ground truth,测试用例确实覆盖了修复内容),然后使用一个独立裁判模型来评判模型生成的 PR 是否解决了 Issue。

具体流程:

Step 1:人类专家审核
  - 确认 Issue 有明确的预期行为
  - 确认测试用例确实覆盖了这个行为
  - 排除歧义性 Issue

Step 2:模型生成 PR
  - 被测模型读取 Issue,生成代码修改

Step 3:LLM-as-Judge 裁判评判
  - 裁判模型阅读 Issue + 候选 PR
  - 判断 PR 是否解决了 Issue
  - 给出"通过/不通过/不确定"的判决

Step 4:结果聚合
  - 与原始测试用例执行结果交叉验证
  - 标记"裁判通过但测试失败"的异常案例(可能是测试用例的问题)

5.3 SWE-bench Verified 的局限性

SWE-bench Verified 并不是完美的答案,它有自己的局限:

人类审核的成本:SWE-bench Verified 只有约 1,000 个实例,而 Full 有约 12,000 个。审核的代价决定了数量上限。

裁判模型的偏差仍然存在:SWE-bench Verified 使用 Claude 作为裁判(具体版本官方未完全公开),但我们无法确认裁判偏差被完全消除。官方报告中标注了裁判评测的一致性(与测试用例执行结果的一致性约 87%),但仍有 13% 的不一致。

无法评测行为正确性:这是最重要的一点——SWE-bench Verified 仍然基于”PR 是否修复了 Issue”的判断,本质上还是代码修复的评测,无法评估 AI 生成代码的行为正确性上限(PlayEval 的发现)。


六、Cursor Canvas 的 Eval 分析:LLM-as-Judge 的产品化案例

Cursor Canvas 的官方博客提到了他们如何使用 LLM-as-Judge 来做 Eval 分析——这是 LLM-as-Judge 在产品层面的实际应用案例。

6.1 Canvas 的 Eval 分析功能

Canvas 的 Eval 分析功能是这样的:

输入:
  1. 一组测试用例(Eval Harness)
  2. 模型在这些测试用例上的表现记录

输出:
  - 失败模式的自动聚类(哪些测试是同一类错误导致的失败)
  - Eval Harness 本身 bug 的发现(测试用例写错了,而非被测代码有问题)
  - 模型能力变化的趋势分析

Cursor 官方报告了这两个关键发现:

发现一:发现了 Eval Harness 本身的 bug

在他们的测试中,LLM 裁判发现了某些测试用例本身的错误——测试用例本身写得不对,导致正确的代码被判定为错误。这与 Claude 降级门的教训一致:benchmark 的分数反映的是”模型 + Harness + 裁判”的组合输出,其中任何一个出错都会影响最终结果。

发现二:大幅降低了人工分析成本

在没有自动化 LLM-as-Judge 分析的情况下,开发者需要手动查看每一个失败案例,理解失败原因,判断是否为同一类错误。这是一个 O(n) 的人工劳动。LLM-as-Judge 将其变为 O(k),其中 k 是聚类后的错误类型数量(通常 k « n)。

6.2 对 AI 编程工具开发者的启示

Canvas 的 Eval 分析功能,揭示了 LLM-as-Judge 在 AI 编程工具开发中的真正价值:

不是用来替代人类评测,而是用来发现 Harness 的问题。

当你用 LLM-as-Judge 来分析测试失败案例时,最大的受益通常不是对模型打分,而是发现:

这比单纯用 LLM-as-Judge 来排名模型要有价值得多。


七、PlayEval 的 PlayCoder:行为验证中的 LLM 裁判

PlayEval 论文中的 PlayCoder 框架提供了一种不同的 LLM-as-Judge 视角:不是让裁判评判代码文本,而是让裁判评判代码的运行时行为

7.1 传统 LLM-as-Judge vs PlayCoder 裁判

传统 LLM-as-Judge 的裁判输入:

Issue + PR 代码文本 → LLM 裁判判断是否解决

PlayCoder 的裁判输入:

GUI 截图序列(程序的实际运行画面)→ LLM 裁判判断行为是否正确

PlayCoder 的 PlayTester Agent 的核心逻辑是:

# PlayTester 的裁判逻辑(简化版)
for step in interaction_sequence:
    screenshot = capture_screen()  # 截图
    expected_behavior = describe_expected_behavior(step)
    
    # LLM 裁判:这段截图里的行为是否正确?
    judgment = llm_judge(
        screenshot=screenshot,
        expected=expected_behavior,
        prompt="这段截图里的应用行为是否正确?"
    )
    
    if not judgment.passed:
        bugs.append({
            'step': step,
            'screenshot': screenshot,
            'reason': judgment.reason
        })

关键创新:用视觉反馈替代文本反馈。传统测试 Agent 需要”哪里出错了”的文本描述才能知道测试失败;PlayTester 直接看截图,发现”小鸟穿过管道了”这类视觉上的异常行为。

7.2 PlayCoder 的三角色协作

PlayCoder 不是一个单一裁判,而是一个多角色协作系统:

这是一个带 LLM 裁判的闭环反馈系统,与传统的 CI/CD pipeline 中的测试-修复循环在逻辑上相同,但测试的执行和判断均由 LLM 完成。

实验结果:PlayCoder + Claude-Sonnet-4 达到 20.3% Play@3,相比基线提升超过 10 个百分点。但即使如此,20.3% 仍然很低——说明 GUI 应用的行为正确性问题,远比”能编译运行”要困难得多。


八、实战指南:如何在你的项目中用好 LLM-as-Judge

8.1 适合使用 LLM-as-Judge 的场景

不是所有评测场景都适合用 LLM-as-Judge。以下是适合的场景特征:

有明确需求但无标准答案

✓ 代码风格审查:"这段代码是否遵循 PEP8?"
✓ 安全漏洞检测:"这段代码是否有 SQL 注入风险?"
✓ 性能分析:"这个实现是否有效率瓶颈?"
✗ 精确的算法实现(需要 ground truth)

需要规模化但允许一定误差

✓ 每日 CI/CD 中的代码质量门禁(允许 5-10% 的误判率)
✓ 模型迭代的 A/B 测试
✓ Prompt 优化的快速反馈
✗ 正式发布的合规性审查(需要人工介入)

8.2 Prompt 设计:裁判系统化的关键

裁判的 Prompt 设计是 LLM-as-Judge 系统的核心。一个设计良好的裁判 Prompt 应包含:

Prompt 骨架(参考):

## 任务
你是一个代码质量评审专家。请判断下面的代码实现是否满足需求。

## 评分标准(显式化,避免隐式标准)
1. 功能正确性(0-10):代码是否正确实现了需求描述的功能?
2. 边界处理(0-10):是否正确处理了边界条件和异常情况?
3. 代码可读性(0-10):代码是否清晰易懂?
[注意:不要给长度过高的权重]

## 待评测内容
【需求描述】
{requirement}

【待评测代码】
{code}

## 输出格式
评分:[功能正确性]/[边界处理]/[代码可读性]
结论:通过 / 部分通过 / 不通过
理由:[具体的优缺点分析,不超过200字]

关键设计原则

  1. 显式化评分维度:不要让裁判自己决定什么重要,显式列出你要评估的维度
  2. 限制长度偏好:明确”不要因为代码更长就给更高分”
  3. 要求理由:强制裁判输出理由,而不是只输出分数——理由的质量比分数本身更能揭示裁判的判断是否合理

8.3 多裁判集成策略

单一裁判模型容易引入系统性偏差。更好的做法是多裁判集成:

策略一:模型多样性集成

用 3 个不同来源的裁判模型,对每个候选答案评分
取三个分数的中位数(或去掉最高最低后取平均)

作用:降低单一模型的偏差影响
注意:选用的裁判模型应与被测模型无关联

策略二:Cross-evaluation(交叉评价)

让被测模型也参与评价过程:
1. 裁判 A 评价 B 的代码
2. 裁判 B 评价 A 的代码
3. 如果两者评价不一致,触发人工复核

作用:发现相互偏见的情况
注意:仅适用于模型选择场景,不适合对单一模型的绝对评测

策略三:迭代式裁判(Recursive Judge)

第一轮:裁判模型给出初步评价
第二轮:另一个裁判模型审查第一轮的评价是否合理
第三轮:综合两轮结果给出最终评价

作用:降低裁判自身的认知偏差
成本:约 3 倍的计算成本

8.4 裁判质量监控

LLM-as-Judge 的一个根本挑战是:你如何知道裁判的判断是正确的?

这是一个元问题——如果有一个完美的裁判来判断裁判的判断是否正确,那这个”完美的裁判”才是你真正需要的裁判。

实用解法:黄金测试集校准

1. 从你的评测场景中,人工选取 20-50 个有明确答案的案例
2. 用这些案例测试你的裁判模型,得到裁判的表现数据
3. 记录:裁判的准确率、误判类型、偏差方向

定期重复这个过程,可以追踪裁判质量的变化趋势。

预警信号

信号 含义 应对
裁判持续选择某个固定位置 位置偏差严重 随机交换顺序 + 多次评测
裁判评分普遍偏高或偏低 校准偏移 调整评分阈值
裁判理由与评分不一致 Prompt 指令未被遵循 优化 Prompt
裁判对新类型任务评分异常 超出裁判能力范围 更换更强的裁判或分割任务

九、总结:LLM-as-Judge 的正确位置

LLM-as-Judge 不是银弹,但它是一个非常有价值的工具——前提是你知道它的适用边界。

LLM-as-Judge 适合的场景

LLM-as-Judge 不适合的场景

最关键的心智模型

不要用 LLM-as-Judge 来排名模型,用它来发现你的评测体系的问题。

当你把 LLM-as-Judge 当作一个排名工具时,它的偏差会系统性地扭曲你的决策。

当你把它当作一个发现工具时,它的偏差反而会暴露出来——因为”裁判为什么会这样判断”的问题,比”裁判给出了多少分”的问题更容易被检验和修正。

这与 Claude 降级门的教训、SWE-bench Verified 的设计哲学、以及 Cursor Canvas 的 Eval 分析功能,一脉相承:

测量体系的可靠性,比测量结果的精确度更重要。


参考资料


本篇与「AI 编程工具 Benchmark 盲区」(2026-04-27)构成评估体系专题,后者聚焦于”测不准的问题”,本篇聚焦于”裁判如何工作及如何正确使用”。