10月27日至28日,Artificial Analysis 发布了 Intelligence Index v5。按官方说明,该指数 60% 的权重改为基于私有测试集或未公开答案的评测。其中 FrontierCode 2.0 这类私有基准的任务不对外公开,任何一项阻断性检查未通过的尝试记 0 分,以避免数据污染。
几乎同一时间,Ai2 发布了一项关于 LLM 评审稳定性的研究。研究者测试了六个大模型对科研想法新颖性的判断,发现判断结果随评测设置变化而不稳定,在一组成对比较实验中,仅改动提示词中的几个词,准确率就变化了超过 50 个百分点。据 Ai2 研究,在同一批样本对上,把提示词从“评审认为其中一个想法新颖,请指出哪一个”改为“哪一个想法新颖”,GPT-5.4 的准确率从 93.5% 降到 40.9%。
需要先说明这项研究的适用范围。它并未证明所有 LLM 新颖性判断都不可靠,只表明在某一特定设置下取得的好成绩,本身不能作为跨设置可靠性的证据。其任务是科研想法的新颖性判断,结论不能直接外推到其他评审任务。但“评审结果对提示词敏感”这一风险,在任何依赖 LLM 打分的系统里都需要单独检验。
两件事指向同一个问题:评测数字的可信度,取决于测试集是否被污染、评审过程是否稳定。本文不比较各厂商模型的优劣,只讨论自建评测体系时可以落地的做法。
评测集的数据结构与隔离
评测集首先是一份有版本、有来源、有访问边界的数据资产。核心规则只有一条:私有切分的原文,不得进入提示词、少样本示例或微调数据。
python
from dataclasses import dataclass
from typing import Literal
@dataclass(frozen=True)
class EvalItem:
item_id: str
input_text: str
gold: str # 双人标注并经仲裁后的结论
slice_tags: tuple[str, ...] # 场景切片,如 ("noise:high", "dialect:southwest")
source: Literal["prod_sample", "synthetic", "adversarial"]
split: Literal["private", "dev"]
version: str # 题库版本,用于追溯与轮换
def load_items(store, split: str):
# 评测服务对外只返回聚合指标;
# private 切分的原文不提供给被测模型的提示词构造、训练与调参流程
assert split in ("private", "dev")
return store.read(split)
调参、改提示词、选模型一律只能使用 dev 切分。private 切分只在发布前的最终评估中使用,且每次访问留痕。
污染检测:扰动一致性
私有集不能保证被测模型从未见过类似内容,所以仍需检测。一种常用思路是对样本做不改变标签的扰动(实体替换、语序调整、同义改写),比较扰动前后的准确率。差距显著为正,说明模型的表现部分依赖对原题面的记忆。
python
def accuracy(model, items):
return sum(model(it.input_text) == it.gold for it in items) / len(items)
def contamination_gap(model, items, perturb, n_variants=3):
"""perturb(item, seed) 返回改写后的 EvalItem,须保持 gold 不变。"""
base = accuracy(model, items)
perturbed = [
accuracy(model, [perturb(it, seed=s) for it in items])
for s in range(n_variants)
]
return base - sum(perturbed) / n_variants
这个指标只能提示风险,不能证明无污染。扰动方式本身也需要人工抽检,确认标签确实没有改变。
评审稳定性:提示变体与位置交换
使用 LLM 作为评审时,至少应检验两类敏感性。
第一类是提示变体。准备若干条语义等价的提示词改写,统计同一样本在不同变体下的结论是否一致。
第二类是位置偏差。成对比较时,交换两个候选的顺序各评一次,结论随顺序改变的样本不应计入有效结论。
python
from collections import Counter
def majority(votes):
return Counter(votes).most_common(1)[0][0]
def pairwise_verdict(judge, prompt, a, b):
"""交换候选顺序各评一次;结论不随顺序保持时返回 None。"""
r1 = judge(prompt, first=a, second=b) # "first" | "second"
r2 = judge(prompt, first=b, second=a)
if (r1 == "first") == (r2 == "second"):
return "a" if r1 == "first" else "b"
return None
def flip_rate(judge, items, prompt_variants, n_repeats=3):
"""同一样本在不同提示变体下得到不同结论的比例。"""
flips = 0
for it in items:
verdicts = [
majority([judge(p, it) for _ in range(n_repeats)])
for p in prompt_variants
]
flips += len(set(verdicts)) > 1
return flips / len(items)
n_repeats 用于压低单次采样的随机性,prompt_variants 用于暴露提示词敏感性,两者不能互相替代。
另外,Ai2 的结果提示了一点:增加检索或推理开销,并不能稳定地改善评审质量。因此评审方案不应默认“投入更多就更可靠”,同样需要用上面的指标实测。
与人工标注的一致性
准确率会受类别分布影响。当某一类占比很高时,评审即使总是输出多数类,准确率也很高。Cohen’s kappa 对这种情况做了校正:
python
def cohen_kappa(y_true, y_pred):
n = len(y_true)
labels = set(y_true) | set(y_pred)
po = sum(t == p for t, p in zip(y_true, y_pred)) / n
pe = sum((y_true.count(l) / n) * (y_pred.count(l) / n) for l in labels)
return 1.0 if pe == 1 else (po - pe) / (1 - pe)
人工标注本身也要先检验:两名标注员之间的 kappa 过低,说明标注规则不清晰,此时评审与“标准答案”的一致性没有意义。
不确定性与区分度
一个版本比另一个版本高 1.5 个百分点,样本量不够时可能只是噪声。对同一批样本做成对比较,用配对 bootstrap 估计差值区间:
python
import random
def paired_bootstrap_diff(a_flags, b_flags, B=2000, seed=0):
"""a_flags/b_flags: 同一批样本上两个版本是否答对(0/1)。返回差值的 95% 区间。"""
rng = random.Random(seed)
n = len(a_flags)
diffs = []
for _ in range(B):
idx = [rng.randrange(n) for _ in range(n)]
diffs.append(sum(a_flags[i] - b_flags[i] for i in idx) / n)
diffs.sort()
return diffs[int(B * 0.025)], diffs[int(B * 0.975) - 1]
评测集还会随模型进步而“用尽”区分度。Artificial Analysis 在 CritPt v2 上的做法值得参考:其私有子集由 70 道研究级物理题剔除 30 道构成,被剔除的是七个前沿模型在五次尝试中全部答对的题目。自建评测集可以采用同样的思路:
python
def refresh_private_set(items, reference_models, run, attempts=5):
"""剔除参考模型全部稳定答对的题,保留仍有区分度的题。"""
kept = []
for it in items:
saturated = all(
all(run(m, it) for _ in range(attempts))
for m in reference_models
)
if not saturated:
kept.append(it)
return kept
这种筛选会使保留下来的题目对参考模型偏难,需要在评测报告中注明所用的参考模型与筛选日期。
发布门槛
把上述指标汇总为发布前的检查项。下面的阈值仅为示意,应按具体场景用历史数据校准,不应直接套用。
python
def release_gate(r):
checks = {
"judge_kappa": r.kappa >= 0.70,
"prompt_flip_rate": r.flip_rate <= 0.10,
"contamination_gap": r.contamination_gap <= 0.03,
"vs_baseline": r.diff_ci_low > 0,
"slice_floor": all(s.acc >= s.floor for s in r.slices),
}
return all(checks.values()), checks
返回每项检查结果而不仅是总判断,可以让未通过时的原因直接可见。
私有测试集的代价
私有化并非没有代价。评测数据大部分保密之后,外部无法再独立复核结果。内部评测同样存在这个问题:结论难以被其他团队复现,也容易随评测人员离开而失去上下文。可以采取的缓解措施包括:公开评测方法与评分脚本、保留脱敏的样例题、记录每个版本的题目数量与切分规则,以及引入未参与建库的人员做定期审计。
语音转写场景的注意点
以“语音转写文本再交由 LLM 做语义判定”的链路为例,评测集有几点需要注意:
输入保留转写误差。 线上输入是带识别错误的文本,用人工校对后的干净文本评测,会系统性高估线上表现。
按声学条件切片。 噪声水平、口音与方言、语速分别统计,总体准确率会掩盖个别切片的明显下降。
标注针对原始音频。 标准答案应由标注员听音频后给出,而不是只看转写,否则转写错误会被一并写进“标准答案”。
评审与转写分开评估。 先分别度量转写错误率和判定一致性,再看端到端结果,才能定位问题出在哪一层。
上线前自检清单
- 私有切分是否与调参、提示词、微调数据完全隔离,访问是否留痕?
- 是否做过扰动一致性检验,并人工抽检过扰动后的标签?
- 评审是否经过提示变体与位置交换检验,翻转率是否记录在报告中?
- 评审与人工标注的 kappa,以及标注员之间的 kappa 是否都已计算?
- 版本对比是否给出置信区间,而不只是均值差?
- 是否定期剔除已无区分度的题目,并记录筛选所用的参考模型?