mcpField
V
validate-evaluator

validate-evaluator

github.com/ai-evals-course测试与质量1.6k1.1k 次安装5 周前更新
代码仓库

关于 validate-evaluator

validate-evaluator 是校准 LLM judge 与人工判断一致性的 Skill,指导团队划分数据集、迭代评估器并测量 TPR、TNR。它还说明如何校正生产数据的通过率并计算置信区间。

主要功能

  1. 01划分训练、开发与测试集
  2. 02测量 TPR 与 TNR
  3. 03依据分歧迭代 judge 提示词
  4. 04校正通过率并估算置信区间

适用场景

  1. 01验证二分类 LLM judge 的判断表现
  2. 02调整评估提示词并检查开发集结果
  3. 03估算生产轨迹的真实通过率

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ai-evals-course/evals-skills --skill validate-evaluator

安装后在 Claude Code 中输入/validate-evaluator确认已加载。

附带文件agents/openai.yaml

详细介绍

验证评估器

根据人工判断校准 LLM 评审器。

概览

  1. 将人工标注的数据拆分为训练集(10-20%)、开发集(40-45%)和测试集(40-45%)
  2. 在开发集上运行评审器并测量 TPR/TNR
  3. 迭代调整评审器,直到开发集上的 TPR 和 TNR 均 > 90%
  4. 在留出的测试集上运行一次,测得最终 TPR/TNR
  5. 将偏差校正公式应用于生产数据

先决条件

  • 已构建的 LLM 评审提示词(来自 write-judge-prompt)
  • 人工标注的数据:约 100 条跟踪记录,每种失败模式都有二元通过/失败标签
    • 目标是约 50 条通过和 50 条失败(保持平衡,即使实际分布有所偏斜)
    • 标签必须由领域专家提供,不能使用外包标注员
  • 来自已标注数据的候选少样本示例

核心说明

第 1 步:创建数据集拆分

将人工标注的数据拆分为三个互不重叠的集合:

拆分大小用途规则
训练集10-20%(约 10-20 个示例)为评审提示词提供少样本示例仅使用明确的通过和失败案例。直接用于提示词中。
开发集40-45%(约 40-45 个示例)迭代改进评估器不得加入提示词。反复用于评估。
测试集40-45%(约 40-45 个示例)最终的无偏准确率测量开发期间不得查看。仅在最后使用一次。

目标:开发集和测试集合计包含 30-50 个属于每个类别(通过和失败)的示例。即使实际情况中的占比有所偏斜,也要使用平衡的拆分——你需要足够多的失败示例,才能可靠地测量 TNR。

from sklearn.model_selection import train_test_split

# First split: separate test set
train_dev, test = train_test_split(
    labeled_data, test_size=0.4, stratify=labeled_data['label'], random_state=42
)
# Second split: separate training examples from dev set
train, dev = train_test_split(
    train_dev, test_size=0.75, stratify=train_dev['label'], random_state=42
)
# Result: ~15% train, ~45% dev, ~40% test
第 2 步:在开发集上运行评估器

在开发集的每个示例上运行评审器。将预测结果与人工标签进行比较。

第 3 步:测量 TPR 和 TNR

TPR(真正率): 人工判断为通过时,评审器也判断为通过的频率是多少?

TPR = (judge says Pass AND human says Pass) / (human says Pass)

TNR(真负率): 人工判断为失败时,评审器也判断为失败的频率是多少?

TNR = (judge says Fail AND human says Fail) / (human says Fail)
from sklearn.metrics import confusion_matrix

tn, fp, fn, tp = confusion_matrix(human_labels, evaluator_labels,
                                   labels=['Fail', 'Pass']).ravel()
tpr = tp / (tp + fn)
tnr = tn / (tn + fp)

使用 TPR/TNR,而非精确率/召回率或原始准确率。这两个指标可直接对应偏差校正公式。Cohen's Kappa 仅用于衡量两位人工标注员之间的一致性,不用于衡量评审器与真实标签之间的一致性。

第 4 步:检查不一致项

检查所有评审器判断与人工标签不一致的案例:

不一致类型评审器人工判断修正方法
误判为通过通过失败评审器过于宽松。强化失败定义或添加边界案例示例。
误判为失败失败通过评审器过于严格。明确通过定义或调整示例。

对于每个不一致案例,确定是否需要:

  • 明确评审提示词中的措辞
  • 从训练集中替换或添加少样本示例
  • 为边界案例添加明确规则
  • 将评估标准拆分为更具体的子检查项
第 5 步:迭代

优化评审提示词,并在开发集上重新运行。重复此过程,直到 TPR 和 TNR 趋于稳定。

停止标准:

  • 目标: TPR > 90% 且 TNR > 90%
  • 最低可接受标准: TPR > 80% 且 TNR > 80%

如果一致性提升停滞:

问题解决方案
TPR 和 TNR 都较低为评审器使用能力更强的 LLM
一个指标较低,另一个可接受针对较低的指标检查不一致案例
两者都停滞在目标以下将评估标准拆解为更小、更原子化的检查项
对某些输入类型持续判断错误从训练集中添加有针对性的少样本示例
标签本身似乎不一致重新检查人工标签;评分标准可能需要改进
第 6 步:在测试集上进行最终测量

在留出的测试集上运行评审器恰好一次。记录最终 TPR 和 TNR。

看到测试集结果后,不要再迭代。如有需要,请使用新的开发数据返回第 4 步。

步骤 7(可选):估算真实成功率(Rogan-Gladen 校正)

未标注生产数据上的原始评审分数存在偏差。如果需要准确的总体通过率,请根据已知的评审错误进行校正:

theta_hat = (p_obs + TNR - 1) / (TPR + TNR - 1)

其中:

  • p_obs = 评审判定为通过的未标注轨迹占比
  • TPR、TNR = 根据测试集测得
  • theta_hat = 校正后的真实成功率估计值

将结果限制在 [0, 1] 范围内。当 TPR + TNR - 1 接近 0 时,此方法无效(评审的表现不比随机猜测好)。

示例:

  • 评审的 TPR = 0.92,TNR = 0.88
  • 500 条生产轨迹:400 条判定为通过 -> p_obs = 0.80
  • theta_hat = (0.80 + 0.88 - 1) / (0.92 + 0.88 - 1) = 0.68 / 0.80 = 0.85
  • 真实成功率约为 85%,而不是原始的 80%
步骤 8:置信区间

计算 Bootstrap 置信区间。仅有点估计还不够。

import numpy as np

def bootstrap_ci(human_labels, eval_labels, p_obs, n_bootstrap=2000):
    """Bootstrap 95% CI for corrected success rate."""
    n = len(human_labels)
    estimates = []
    for _ in range(n_bootstrap):
        idx = np.random.choice(n, size=n, replace=True)
        h = np.array(human_labels)[idx]
        e = np.array(eval_labels)[idx]

        tp = ((h == 'Pass') & (e == 'Pass')).sum()
        fn = ((h == 'Pass') & (e == 'Fail')).sum()
        tn = ((h == 'Fail') & (e == 'Fail')).sum()
        fp = ((h == 'Fail') & (e == 'Pass')).sum()

        tpr_b = tp / (tp + fn) if (tp + fn) > 0 else 0
        tnr_b = tn / (tn + fp) if (tn + fp) > 0 else 0
        denom = tpr_b + tnr_b - 1

        if abs(denom) < 1e-6:
            continue
        theta = (p_obs + tnr_b - 1) / denom
        estimates.append(np.clip(theta, 0, 1))

    return np.percentile(estimates, 2.5), np.percentile(estimates, 97.5)

lower, upper = bootstrap_ci(test_human, test_eval, p_obs=0.80)
print(f"95% CI: [{lower:.2f}, {upper:.2f}]")

或者使用 judgy(pip install judgy):

from judgy import estimate_success_rate

# judgy expects 0/1 integer labels (1 = Pass, 0 = Fail)
test_labels = [1 if l == 'Pass' else 0 for l in test_human_labels]
test_preds = [1 if l == 'Pass' else 0 for l in test_eval_labels]
unlabeled_preds = [1 if l == 'Pass' else 0 for l in prod_eval_labels]

theta_hat, lower, upper = estimate_success_rate(
    test_labels, test_preds, unlabeled_preds
)
print(f"Corrected rate: {theta_hat:.2f}")
print(f"95% CI: [{lower:.2f}, {upper:.2f}]")

实用指南

  • 对 LLM 评审固定使用确切的模型版本(采用类似 <model>-<YYYY-MM-DD> 的带日期快照 ID,而不是浮动别名)。提供商可能会在不另行通知的情况下更新模型,从而导致无声漂移。
  • 更改评审提示词、更换模型,或生产环境中的置信区间意外扩大时,请重新验证。
  • 使用约 100 个已标注样例(50 个通过,50 个失败)。少于 60 个时,置信区间会变宽。
  • 由一位可信领域专家进行标注是最高效的方式。 如果不可行,可让两位标注人员独立标注 20 到 50 条轨迹,并在继续之前解决分歧。
  • 提高 TPR 比提高 TNR 更能缩小置信区间。 校正时会除以 (TPR + TNR - 1),因此较低的 TPR 会缩小分母,并放大估计误差,导致置信区间变宽。

反模式

  • 假设评审无需验证就“能正常工作”。 评审可能会持续漏掉失败案例,或将通过的轨迹标记为失败。
  • 使用原始准确率或一致率。 应使用 TPR 和 TNR。存在类别不平衡时,原始准确率会产生误导。
  • 将开发集/测试集样例用作少样本示例。 这属于数据泄漏。
  • 将开发集表现作为最终准确率报告。 开发集数据偏乐观。测试集才能提供无偏估计。
  • 使用未经偏差校正的原始评审分数。 如果要报告总体通过率,请应用 Rogan-Gladen 公式(步骤 7)。
  • 只报告点估计,不提供置信区间。 对于较小的测试集,校正后的 85% 可能实际上是 78% 到 92%。请报告范围,让利益相关者了解这个数字的可信程度。

评论

支持 Markdown