11—你的 Judge 准吗:LLM-as-Judge 偏差校准实践

一个让人不安的数字

在 SkillSentry 的实际测评中,我们发现一个现象:

同一批用例,脚本验证(exact_match)通过率 72%,LLM Judge(semantic)通过率 89%。

差了 17 个百分点。

脚本验证是确定性的:参数值是不是 "10"、接口有没有被调用、返回值里有没有某个字段------非黑即白,没有灰色地带。

而 LLM Judge 在评审时,经常这样写 evidence:「从整体输出来看,Skill 基本遵循了规则的精神」------这不是评审,这是放水。

这就是 LLM-as-Judge 的高估偏差(Overestimation Bias),行业内已被多篇论文确认,是所有使用 LLM 评审的系统必须面对的问题。


LLM-as-Judge 的三类系统性偏差

偏差1:高估偏差(Overestimation Bias)

表现:Judge 对"差不多对了"的输出倾向于判 pass。

原因

  • LLM 被训练为"有帮助的",它不擅长严厉否定
  • 当输出看起来像正确答案时,Judge 倾向于找理由让它通过
  • 对于模糊规则(如「输出应该友好」),几乎什么回答都能找到"友好的成分"

量化数据(SkillSentry 实测):

erlang 复制代码
exact_match 断言:72% 通过
semantic 断言(同一规则的宽松表述):89% 通过
差值:17%(这 17% 就是 Judge 放水的部分)

偏差2:位置偏差(Position Bias)

表现:在 A/B 对比评估中,Judge 倾向于给先出现的选项更高分。

原因:LLM 的注意力机制对序列位置有偏好(尤其在长上下文中)。

影响场景 :SkillSentry 的 sentry-comparator(盲测对比)需要防范此偏差。

已有对策:comparator 随机化 A/B 顺序(with_skill 和 without_skill 随机分配为 A 或 B)。

偏差3:冗长偏差(Verbosity Bias)

表现:输出更长的回答往往获得更高评分,即使长度不代表质量。

原因:更长的输出"看起来更努力"、"信息更丰富",Judge 把详细性误认为正确性。

影响场景:text_generation 类 Skill 的评审(回答是否全面、是否遵循格式要求)。


为什么不能"全部用人工评审"

既然 LLM Judge 有偏差,为什么不全部换成人工?

维度 人工评审 LLM Judge
准确性 高(有领域知识时) 中等(有系统偏差)
成本 高($1-5/条) 低($0.001-0.01/条)
速度 慢(分钟级) 快(秒级)
一致性 低(不同人标准不同) 高(同一prompt结果稳定)
可扩展

正确答案是分层组合:确定性规则用脚本、模糊规则用 LLM Judge、高风险场景用人工复核。


SkillSentry 已有的偏差控制手段

在讨论"还需要补什么"之前,先看 SkillSentry 现有的防线:

手段1:断言精度分级(precision)

每条断言标注 exact_match / semantic / existence

json 复制代码
{"id": "E1", "text": "docStatus 参数为 10", "precision": "exact_match"},
{"id": "E2", "text": "回复友好且包含单号", "precision": "semantic"},
{"id": "E3", "text": "调用了 saveExpenseDoc", "precision": "existence"}
  • exact_match:脚本验证,LLM 不参与,零偏差
  • semantic:LLM Judge 评审,承认存在偏差
  • existence:最弱断言,只看有没有

通过率分别报告authoritative_pass_rate 只基于 exact_match,这是发布决策的核心数字。

手段2:脚本预验证(verify_assertions.py)

对所有 exact_match 断言,先用脚本跑一遍:

bash 复制代码
python3 scripts/verify_assertions.py \
  --transcript eval-1/with_skill/outputs/transcript.md \
  --assertions eval-1/assertions.json \
  --output eval-1/grading_script.json

脚本结论是最终结论,LLM 不允许翻转。 这条纪律写在 sentry-grader SKILL.md 中:

「脚本结论即最终结论,不允许 AI 重判(避免 15-20% 高估偏差)」

手段3:盲测消除确认偏差

sentry-comparator 在对比 with_skill vs without_skill 时采用盲测:Judge 不知道哪份输出来自有 Skill 的版本。这消除了"已知谁是被测对象"带来的确认偏差。


还缺什么:系统性校准闭环

上面三个手段都是设计时 的防线。但缺一个运行时的校准机制:

「我怎么知道我的 Judge 现在还准?它上个月准不代表这个月还准。」

校准闭环的设计

erlang 复制代码
┌───────────────┐
│ 每次测评执行   │
│ (产出 grading) │
└───────┬───────┘
        │
        ▼
┌───────────────────────┐
│ 定期抽检(每月/每季)   │
│ 从 semantic 断言中       │
│ 随机抽 20-30 条          │
└───────┬───────────────┘
        │
        ▼
┌───────────────────────┐
│ 人工标注               │
│ 同一条断言,人给 pass/fail │
└───────┬───────────────┘
        │
        ▼
┌───────────────────────┐
│ 计算一致性              │
│ Cohen's Kappa 或         │
│ 简单 Agreement Rate     │
└───────┬───────────────┘
        │
        ▼
┌───────────────────────┐
│ 决策                    │
│ ≥ 80%:Judge 可信       │
│ 60-80%:修改 Judge prompt│
│ < 60%:停用,换人工      │
└───────────────────────┘

具体操作方法

Step 1:构建校准数据集

从历史测评中挑选 semantic 断言的评审结果,人工复判:

markdown 复制代码
| eval_id | 断言 | Judge判定 | 人工判定 | 一致? |
|---------|------|----------|---------|--------|
| eval-3  | 回复包含审批状态说明 | pass | pass | ✅ |
| eval-7  | 格式符合报销模板 | pass | fail | ❌ Judge放水 |
| eval-12 | 引导用户选择正确类型 | fail | pass | ❌ Judge误杀 |

Step 2:计算偏差指标

python 复制代码
# 简单一致率
agreement_rate = consistent_count / total_count

# 偏差方向
overestimation_rate = judge_pass_but_human_fail / total_count  # Judge放水率
underestimation_rate = judge_fail_but_human_pass / total_count  # Judge误杀率

# 净偏差
net_bias = overestimation_rate - underestimation_rate
# 正值 = 系统性高估,负值 = 系统性低估

Step 3:修正策略

情况 修正动作
净偏差 > 15%(严重高估) Judge prompt 增加严格性指令 + 增加"必须引用原文"要求
净偏差 5-15%(轻度高估) 在报告中标注"语义通过率可能高估 X%,以精确通过率为准"
净偏差 < 5% 当前 Judge 可信,无需修正
误杀率 > 10% Judge prompt 增加"合理变体应视为通过"的示例

Step 4:记录和趋势追踪

json 复制代码
// calibration_history.json
[
  {
    "date": "2026-03-15",
    "sample_size": 25,
    "agreement_rate": 0.76,
    "overestimation_rate": 0.20,
    "underestimation_rate": 0.04,
    "action": "增加 Judge prompt 严格性",
    "judge_model": "current-judge-model"
  },
  {
    "date": "2026-05-18",
    "sample_size": 30,
    "agreement_rate": 0.87,
    "overestimation_rate": 0.10,
    "underestimation_rate": 0.03,
    "action": "无需修正",
    "judge_model": "current-judge-model"
  }
]

LLM-as-Judge 的适用边界

不是所有场景都适合用 LLM 做 Judge。明确边界:

适合用 LLM Judge 的场景

场景 为什么适合
回复友好度/语气评估 主观性强,脚本无法判定
格式合规性(宽松) "大致符合模板"需要语义理解
相关性评估 回答是否与问题相关
安全性初筛 是否包含有害内容
执行轨迹合理性 步骤是否合理、是否有冗余

不适合用 LLM Judge 的场景

场景 为什么不适合 替代方案
参数值验证 有确定答案 脚本 exact_match
事实准确性 LLM 自己也可能幻觉 脚本验证 + 数据库对比
工具是否被调用 日志中有或没有 脚本检查 transcript
数值计算正确性 LLM 数学能力有限 脚本验证
安全漏洞的技术判定 需要安全领域专业知识 人工 + 专业工具

信任度分级

复制代码
可信度:脚本验证 > LLM Judge(严格prompt) > LLM Judge(宽松prompt) > 自评审

这只是评审可信度的排序,不代表当前实现里存在加权评分机制。SkillSentry 的 authoritative_pass_rate 只基于 exact_match / 脚本验证断言计算;LLM Judge 的结论作为补充诊断信息展示,不参与 authoritative_pass_rate 的加权。


Judge Prompt 工程最佳实践

一个好的 Judge prompt 应该包含以下要素:

必须有的四要素

markdown 复制代码
## 你的角色
你是一个严格的 AI Skill 评审员。你的任务是判断 Skill 执行结果是否满足断言。

## 评审规则
1. 只看证据,不推测:如果 transcript 中没有明确记录,判定为 fail
2. 不宽容"差不多":参数值必须精确匹配,"类似"不算通过
3. evidence 必须引用原文:你的判定依据必须来自 transcript/response 的直接引用
4. 沉默不是通过:如果某个步骤应该执行但 transcript 中没有记录,判定为 fail

## 输出格式
对每条断言,输出:
- pass/fail
- evidence:直接引用 transcript/response 中的文本(用引号括起来)
- reasoning:为什么这条证据支持/不支持断言(一句话)

## 断言列表
[具体断言...]

## 被评审内容
[transcript + response...]

常见的 Judge Prompt 反模式

反模式 问题 修正
「请评估输出质量」 太宽泛,Judge 自由发挥 给具体断言列表
「总体来看是否合格」 鼓励笼统判断 要求逐条评审
不要求引用证据 Judge 可能凭印象判断 强制引用原文
只给 pass/fail 不要 evidence 无法事后验证Judge判断 必须附带证据

校准频率建议

场景 校准频率 抽样量
Judge 模型更换 立即全量校准 50+ 条
新 Skill 首次测评 测评完成后校准 20-30 条
常规运行 每月一次 20-30 条
在线监控 Judge 每两周一次 15-20 条
发现异常高通过率 立即 对应 Skill 全量

落地行动清单

最小可行校准(今天就能做)

  • 从最近一次 SkillSentry 测评中,取所有 semantic 断言的 Judge 判定结果
  • 人工复判 20 条(花 15 分钟)
  • 计算 agreement_rate 和 overestimation_rate
  • 如果高估 > 15%:修改 sentry-grader 的评审 prompt

持续校准机制

  • 建立 calibration_history.json,每次校准后追加记录
  • 在 SkillSentry grader-report 中增加「校准状态」字段
  • 设置月度提醒:校准 Judge

总结

要点 结论
LLM-as-Judge 有偏差吗 有,系统性高估 15-20%
能完全消除吗 不能,但可以控制到可接受范围
核心防线是什么 脚本断言优先 + 分层信任 + 定期校准
什么场景不能用 事实验证、参数值、数值计算
多久校准一次 常规每月,模型更换后立即

一句话记住:把能用脚本验证的全部交给脚本,剩下的用 LLM Judge 但承认它有偏差,并定期用人工数据校准偏差大小。


实战补充:5 个 Judge 校准 Case

Judge 校准的目标不是证明 AI Judge 永远正确,而是知道它在哪些维度可靠、哪些维度需要人工复核。

Case 维度 Judge 判定 人工判断 偏差
1 L1 description 缺不触发场景,3/5 同意,确实缺不触发条件 0
2 L3 复杂度 统计所有箭头,复杂度 22,3/5 箭头多为流程格式,修正后为 20,4/5 1
3 L2 HiL 有复述但无确认等待,3/5 同意,复述不是确认 0
4 Trigger TP=5/5,TN=5/5 同意,正负样本判断一致 0
5 L4 冗余 session.json 引用 7 次,4/5 频次准确,但是否冗余需看语义 0

这 5 个 case 说明:

text 复制代码
1. Judge 在结构完整性、HiL 语义、触发判断上比较可靠。
2. Judge 在复杂度和冗余这类"统计 + 语义判断"场景中容易出现偏差。
3. 低 confidence 或语义依赖强的判断,应标记 human_review_required。

Judge prompt 可以补充一条规则:

text 复制代码
统计条件分支时,区分格式符号和逻辑符号。
流程描述中的箭头不算条件分支。
只有表达"如果...则..."语义的才算。

这类校准应成为常规动作:模型升级后、Judge prompt 改动后、评分规则变化后,都应该抽样复核。

相关推荐
刘棕霆1 天前
10—把 SkillSentry 接入 CI:每次改动都有质量门禁
测试
编程探索者小陈2 天前
接口自动化测试(一)
python·测试
1candobetter2 天前
单接口性能测试实践总结:压测方案设计、成功判定与 JVM 监控分析
java·jvm·压力测试·测试
学代码的真由酱3 天前
Java多用户一对一网页聊天室-测试报告
java·开发语言·功能测试·测试
小当家1055 天前
如何评估你的 Skill 质量——从触发准确率到输出质量的系统方法
测试
编程探索者小陈7 天前
【测试】之测试分类篇
测试
kida_yuan8 天前
【以太来袭】7. Besu 性能基线(Caliper)
区块链·测试
qq_白羊座11 天前
测试资产复用维护方法
测试·测试资产
HuskyYellow13 天前
第 1 篇:没有专职测试的小团队,为什么需要 ai-phone?
人工智能·开源·测试