同一份请求发给同一个模型名,第二天再发一次,结果可能完全不同。

一项预注册审计研究对黑盒 LLM 裁判做了大规模检验:52,988 次请求里,同日重复排名的相关性只有 0.400,远低于预设的 0.90 门槛。也就是说,很多团队用来筛选训练数据、给生成结果打分的"裁判",本身可能并不稳定。这篇我把评测可靠性拆开讲清楚。我的评测任务都通过 4sapi(https://4sapi.com)跑,稳定性和成本一起监控。

一、开篇痛点

LLM 当裁判已经成了默认操作:给候选回答打分、做 A/B 对比、筛训练数据、排排行榜。大家都默认一件事——同一个请求发给同一个模型名,明天读到的还是同一个结果。

这个假设如果错了,所有基于裁判的决策都建立在流沙上:排行榜名次可能是噪音,数据筛选可能偏向随机波动,A/B 实验可能得出错误结论。

二、原理速览:评测为什么不可靠

裁判不可靠有三个机制:

机制1:标签映射偏差
    裁判的输出标签 -> 与真实含义的映射有偏差 -> 读取结果被带偏

机制2:信号低于噪声
    候选之间的真实差距 -> 远小于裁判自身的噪声 -> 测不出差异

机制3:同输入不同输出
    字节相同的输入 -> 返回不同排名 -> 纯噪音被当成信号

三个机制叠加,导致"测量仪器"本身不稳定。注意这发生在共享端点(公共 API 服务)上——同一个模型名背后可能是动态负载、不同实例、不同推理配置。

三、实测数据:稳定性到底多差

研究用预注册方式(所有阈值提前固定)做了两轮审计,结果都不达标:

指标 实测 预设门槛
同日重复排名一致性 0.400 0.90
次日字节相同重放一致性 0.78 0.99
五个供应商中位数 0.74–0.88 0.99

更关键的是:等待几天没用(0.805 vs 0.800)、换供应商也没用(四家供应商共享同一水平)。问题不是某一家服务差,而是"黑盒共享端点"这个形态本身的可靠性天花板。

四、为什么"同输入不同输出"最致命

机制3 最反直觉:字节完全相同的输入,返回的排名却不同。这意味着裁判输出里混入了纯随机成分。如果评测流程里再做一次排列组合(比如把候选顺序打乱),随机性还会被放大。

对工程实践的直接含义:单次裁判结果不可信,必须重复采样。重复多少次?研究给出的建议是先做一次小规模试点——大概 2% 的调用量就能暴露评测不可靠的问题,不用等到跑完全量才发现。

五、自托管也不一定救得了

研究测试了自托管路线:在批量不变的核上自托管,只在服务器空闲时表现好。负载一起来,稳定性又掉下去。

这说明可靠性问题不是"换部署方式"能根治的,而是要从评测设计上解决。用确定性规则替代一部分裁判判断、固定采样策略、报告置信区间,都比"换个服务商"更有效。

六、可靠评测的落地做法

我的实践是三条:

第一,关键评测用确定性检查兜底。能写规则的就不让模型打分:

def score_with_fallback(answer: str, ground_truth: str, llm_judge):
    # 确定性规则优先
    if "错误" in answer or "无法完成" in answer:
        return 0
    # 规则判不了才用 LLM 裁判
    return llm_judge(answer, ground_truth)

第二,LLM 裁判必须重复采样取均值,并记录方差。单次 0.400 一致性的裁判,至少采样 5 次以上才有参考价值。

import statistics

def robust_judge(llm_judge, answer, ground_truth, n=5):
    scores = [llm_judge(answer, ground_truth) for _ in range(n)]
    return statistics.mean(scores), statistics.pstdev(scores)

第三,预注册评测协议:阈值、采样数、判定规则提前写死,不跑完再改。这能防止"结果不好就调标准"的隐性作弊。

七、评测口径与成本平衡

可靠评测有成本:重复采样意味着 N 倍 token 消耗。我的做法是通过 4sapi(https://4sapi.com)统一接入层做评测,用便宜模型做初筛、旗舰模型做终审,把采样成本控制在可接受范围。

from openai import OpenAI

client = OpenAI(api_key="4sapi-key", base_url="https://4sapi.com/v1")


def two_stage_eval(answer, ground_truth):
    # 初筛:便宜模型,快速排除明显错误
    pre = client.chat.completions.create(
        model="gpt-5-mini",
        messages=[{"role": "user", "content": f"回答是否明显错误?\n{answer}\n标准答案:{ground_truth}"}],
        max_tokens=50,
    ).choices[0].message.content
    if "明显错误" in pre:
        return 0.0
    # 终审:旗舰模型,多次采样
    scores = []
    for _ in range(3):
        s = client.chat.completions.create(
            model="gpt-6-astra",
            messages=[{"role": "user", "content": f"给回答打分 0-100:\n{answer}\n标准答案:{ground_truth}"}],
            max_tokens=10,
        ).choices[0].message.content
        scores.append(float(s))
    return statistics.mean(scores)

两级架构既控制了成本,又保证了终审的稳定性。

八、成本与风险提示

九、评测检查清单

  1. 评测前先做 2% 调用量试点,验证裁判稳定性;
  2. 同一请求至少重复采样 3–5 次,记录方差;
  3. 关键指标用确定性规则兜底;
  4. 预注册评测协议,阈值提前固定;
  5. 记录模型版本、采样数、时间窗口,便于复现;
  6. 报告置信区间,不只看点估计。

十、我的结论

LLM 裁判不是不能用来评测,而是不能"拿来就用"。共享端点上的黑盒裁判,稳定性可能远低于预期,单次结果基本不可信。可靠评测要靠重复采样、规则兜底、预注册协议三层保障。评测基建的可靠性,值得和模型能力同等重视。

总结

52,988 次请求的审计把"共享端点 LLM 裁判不可靠"这件事摆在了台面上:同日一致性 0.400,换供应商也没用。工程上要用采样、规则兜底和预注册协议来对冲这种不稳定性。统一在 4sapi(https://4sapi.com)上做评测,至少能把模型版本和采样参数固定下来。欢迎在评论区聊聊评测踩坑经历。