别让评测分数骗了你:从静态刷榜到动态抗污染评测管道实战
当 78% 的 CodeForces 题目存在训练集软污染,当 NIST 闭源评测引发争议,传统静态基准的公信力正在崩塌。本文以 BeyondBench、StressEval、Claw-Eval-Live 为蓝本,给出从污染检测到动态生成评测管道的完整工程方案
引言:你的评测分数,有多少是真的?
2026 年 5 月,两件事几乎同时发生,把大模型评测的公信力问题推到了台前。
第一件事:NIST 发布了针对 DeepSeek V4 的专项评测报告,结论是”与美国顶尖水平存在 8 个月差距”。北航肖利民教授指出,NIST 评测未涵盖 DeepSeek V4 在超长上下文上的核心优势,且其闭源评测体系无法复现、公正性难以核验——谁掌握评测标准,谁就掌握话语权。
第二件事:Soft Contamination 论文(arXiv:2602.12413)对 OLMo-3 训练语料的语义嵌入分析发现,78% 的 CodeForces 题目存在训练集”软重复”,50% 的 ZebraLogic 逻辑谜题被精确覆盖;而 ICLR 2026 接收的 BeyondBench(arXiv:2509.24210)则从工程层面验证了这一问题的严重性——其 44 个算法任务/117 个变体/101 个模型的评估显示,即使最强模型在 Hard Suite 上也仅达 56% 准确率,传统静态基准的可信度已不可靠。这意味着,你在榜单上看到的很多”突破”,可能只是模型在考试前看过答案。
问题很清楚了:静态基准 + 封闭评测 = 不可信的分数。作为工程师,我们需要一套从检测污染到构建动态评测管道的完整方案。本文给出可落地的实战路径。
一、先诊断:你的基准被污染了吗?
在动手建管道之前,先量化你的评测集被污染的程度。
1.1 N-gram 重叠检测
最基础但也最必要的检查——直接统计评测集与训练集的 N-gram 重叠率。
from collections import Counter
from typing import List, Set
def ngram_contamination_score(
eval_texts: List[str],
train_texts: List[str],
n: int = 13
) -> dict:
"""检测评测集与训练集的 N-gram 重叠程度"""
def get_ngrams(text: str, n: int) -> Set[str]:
tokens = text.lower().split()
return {' '.join(tokens[i:i+n]) for i in range(len(tokens)-n+1)}
eval_ngrams = Counter()
for text in eval_texts:
eval_ngrams.update(get_ngrams(text, n))
train_ngrams = set()
for text in train_texts:
train_ngrams.update(get_ngrams(text, n))
contaminated = {ng: cnt for ng, cnt in eval_ngrams.items()
if ng in train_ngrams}
total_eval = sum(eval_ngrams.values())
contaminated_count = sum(contaminated.values())
return {
"n": n,
"total_eval_ngrams": total_eval,
"contaminated_ngrams": contaminated_count,
"contamination_rate": contaminated_count / total_eval
if total_eval > 0 else 0,
"unique_contaminated": len(contaminated),
}
经验阈值(来自 BeyondBench 对 101 个模型的分析):
| 重叠率 | 判定 | 建议 |
|---|---|---|
| < 1% | 基本干净 | 可正常使用 |
| 1%-5% | 轻度污染 | 需做降权处理 |
| 5%-15% | 中度污染 | 必须清洗或降级使用 |
| > 15% | 严重污染 | 放弃该基准作为主要指标 |
1.2 语义嵌入检测:抓”软污染”
N-gram 只能抓精确重复,抓不了”改写后语义相同”的软污染。需要语义嵌入检测。
import numpy as np
from sentence_transformers import SentenceTransformer
def semantic_contamination_scan(
eval_questions: List[str],
train_corpus: List[str],
model_name: str = "BAAI/bge-large-en-v1.5",
similarity_threshold: float = 0.85,
batch_size: int = 256
) -> dict:
"""用语义嵌入检测评测集与训练集的软污染"""
model = SentenceTransformer(model_name)
eval_emb = model.encode(eval_questions, batch_size=batch_size,
normalize_embeddings=True)
train_emb = model.encode(train_corpus, batch_size=batch_size,
normalize_embeddings=True)
# 分批计算相似度,避免 OOM
contaminated_indices = []
max_similarities = []
for i in range(0, len(eval_emb), batch_size):
batch = eval_emb[i:i+batch_size]
sims = batch @ train_emb.T # (batch, train_size)
max_sim = sims.max(axis=1)
max_similarities.extend(max_sim.tolist())
for j, sim in enumerate(max_sim):
if sim >= similarity_threshold:
contaminated_indices.append(i + j)
return {
"total_eval": len(eval_questions),
"contaminated_count": len(contaminated_indices),
"contamination_rate": len(contaminated_indices) / len(eval_questions),
"contaminated_indices": contaminated_indices,
"avg_max_similarity": float(np.mean(max_similarities)),
"threshold": similarity_threshold,
}
实测数据(BeyondBench 论文报告):
- CodeForces 题目:78% 存在语义相似软重复(阈值 0.85)
- ZebraLogic 逻辑谜题:50% 精确重复
- MATH/AIME:约 30% 存在不同程度的语义重叠
1.3 性能异常检测:最不需要训练集的信号
如果拿不到训练集怎么办?可以观察模型在基准上的异常行为模式。
def detect_anomaly_patterns(
model_results: dict, # {model_name: {benchmark: score}}
baseline_models: List[str],
suspect_models: List[str],
) -> dict:
"""检测模型在特定基准上的异常高分"""
anomalies = {}
for bench in list(list(model_results.values())[0].keys()):
baseline_scores = [model_results[m][bench]
for m in baseline_models
if m in model_results]
if not baseline_scores:
continue
mean = np.mean(baseline_scores)
std = np.std(baseline_scores)
for model in suspect_models:
if model not in model_results:
continue
score = model_results[model][bench]
z_score = (score - mean) / std if std > 0 else 0
# z > 2.0 且分数 > 95% 视为可疑
if z_score > 2.0 and score > 95:
anomalies.setdefault(model, []).append({
"benchmark": bench,
"score": score,
"z_score": round(z_score, 2),
"baseline_mean": round(mean, 2),
"flag": "likely_contaminated"
})
return anomalies
二、构建动态评测管道:从 LiveBench 到 BeyondBench
确认污染后,解决方案不是修补,而是从根本上换一套评测方式——动态评测管道。
2.1 架构选型:三种动态评测范式
| 范式 | 代表 | 核心机制 | 适用场景 | 更新频率 |
|---|---|---|---|---|
| 时间窗口刷新 | LiveBench | 每月新题,旧题降权/退役 | 通用能力评测 | 月度 |
| 算法化生成 | BeyondBench | 参数化问题模板+随机实例 | 数学/推理评测 | 每次运行 |
| 需求信号驱动 | Claw-Eval-Live | 从真实 workflow 需求抽取任务 | Agent 评测 | 季度 snapshot |
选择建议:
- 做模型能力评测 → LiveBench 式时间窗口
- 做推理/数学评测 → BeyondBench 式算法化生成
- 做Agent 评测 → Claw-Eval-Live 式需求驱动
2.2 实战:搭建一个 BeyondBench 式算法化生成管道
BeyondBench 的核心思想:用算法生成数学问题,而非人工编写。每次评测运行时重新生成实例,从根本上杜绝污染。
下面是一个简化的实现——以图论问题为例:
import random
import hashlib
from dataclasses import dataclass, field
from typing import List, Tuple, Optional
@dataclass
class GraphProblem:
"""图论推理问题实例"""
problem_id: str
task_type: str # e.g., "shortest_path", "mst", "graph_coloring"
difficulty: str # "easy", "medium", "hard"
description: str # 自然语言问题描述
graph_spec: dict # 图的规格(顶点、边、权重)
correct_answer: str # 标准答案
solution_trace: str # 求解步骤(用于过程评分)
parameters: dict = field(default_factory=dict)
class AlgorithmicBenchGenerator:
"""算法化评测基准生成器"""
def __init__(self, seed: Optional[int] = None):
self.rng = random.Random(seed)
self.task_generators = {
"shortest_path": self._gen_shortest_path,
"mst": self._gen_mst,
"graph_coloring": self._gen_coloring,
}
def generate_suite(
self,
tasks: List[str] = None,
variants_per_task: int = 3,
difficulties: List[str] = None,
) -> List[GraphProblem]:
"""生成一套完整评测"""
tasks = tasks or list(self.task_generators.keys())
difficulties = difficulties or ["easy", "medium", "hard"]
suite = []
for task in tasks:
for diff in difficulties:
for v in range(variants_per_task):
problem = self.task_generators[task](
difficulty=diff, variant=v
)
suite.append(problem)
return suite
def _gen_shortest_path(
self, difficulty: str, variant: int
) -> GraphProblem:
"""生成最短路径问题"""
node_range = {"easy": (4, 6), "medium": (7, 10), "hard": (11, 15)}
lo, hi = node_range[difficulty]
n_nodes = self.rng.randint(lo, hi)
# 随机生成连通图
nodes = [f"V{i}" for i in range(n_nodes)]
edges = []
for i in range(n_nodes):
for j in range(i+1, n_nodes):
if self.rng.random() < 0.4: # 边密度
w = self.rng.randint(1, 20)
edges.append((nodes[i], nodes[j], w))
# 确保连通
# ... (省略连通性检查代码)
source = nodes[0]
target = nodes[-1]
# 用 Dijkstra 求正确答案
answer, trace = self._dijkstra(nodes, edges, source, target)
problem_id = hashlib.md5(
f"sp_{difficulty}_{variant}_{n_nodes}_{len(edges)}".encode()
).hexdigest()[:12]
desc = (
f"给定一个有 {n_nodes} 个顶点、{len(edges)} 条边的加权无向图,"
f"边及权重如下:{[(e[0], e[1], e[2]) for e in edges]}。"
f"求从 {source} 到 {target} 的最短路径长度。"
)
return GraphProblem(
problem_id=problem_id,
task_type="shortest_path",
difficulty=difficulty,
description=desc,
graph_spec={"nodes": nodes, "edges": edges},
correct_answer=str(answer),
solution_trace=trace,
parameters={"variant": variant, "n_nodes": n_nodes},
)
def _dijkstra(self, nodes, edges, source, target):
"""Dijkstra 求解,同时记录 trace"""
import heapq
adj = {n: [] for n in nodes}
for u, v, w in edges:
adj[u].append((v, w))
adj[v].append((u, w))
dist = {n: float('inf') for n in nodes}
dist[source] = 0
prev = {n: None for n in nodes}
pq = [(0, source)]
trace_steps = []
while pq:
d, u = heapq.heappop(pq)
trace_steps.append(f"访问 {u},当前距离 {d}")
if d > dist[u]:
continue
if u == target:
break
for v, w in adj[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
heapq.heappush(pq, (dist[v], v))
trace_steps.append(
f" 更新 {v}: {dist[v]} (经 {u})"
)
# 回溯路径
path = []
cur = target
while cur:
path.append(cur)
cur = prev[cur]
path.reverse()
return dist[target], "\n".join(trace_steps)
def _gen_mst(self, difficulty, variant):
# 类似结构,生成最小生成树问题
pass
def _gen_coloring(self, difficulty, variant):
# 类似结构,生成图着色问题
pass
关键设计原则(来自 BeyondBench 的 44 个任务/117 个变体实践):
- 参数化模板:将问题抽象为参数模板,每次运行随机填充参数
- 可验证性:算法自动生成标准答案和求解轨迹,无需人工标注
- 难度可控:通过参数范围(节点数、边密度等)精确控制难度梯度
- 实例唯一性:用
seed + task + variant组合确保可复现但不可预判
2.3 实战:搭建失败驱动的动态评测(StressEval 式)
StressEval(arXiv:2605.01939, IJCAI 2026)提出了一个更聪明的思路:不从头生成题,而是从模型的失败中合成新题。这对于已上线模型的持续质量保障特别有用。
StressEval 三阶段管道:
模型失败日志 → 难度卡构建 → 实例合成 → 注入评测集
↑ |
└──────── 持续反馈 ←───────────────────┘
@dataclass
class DifficultyCard:
"""半结构化难度卡:记录失败推理步骤和根因"""
task_id: str
failed_step: str # 哪一步失败了
root_cause: str # 根因分类
knowledge_gap: str # 缺失的知识点
reasoning_error: str # 推理错误类型
difficulty_level: str # easy/medium/hard
synthesis_prompt: str # 合成新实例的提示
class StressEvalPipeline:
"""失败驱动的动态评测管道"""
def __init__(self, model_client):
self.model = model_client
self.failure_store: List[DifficultyCard] = []
def analyze_failure(
self, question: str, model_answer: str,
correct_answer: str, reasoning_trace: str
) -> DifficultyCard:
"""分析模型失败,构建难度卡"""
prompt = f"""分析以下模型失败案例,提取失败原因:
问题: {question}
模型回答: {model_answer}
正确答案: {correct_answer}
推理过程: {reasoning_trace}
请输出 JSON:
{{
"failed_step": "失败的具体步骤",
"root_cause": "知识缺失|推理错误|计算失误|理解偏差",
"knowledge_gap": "缺失的知识点",
"reasoning_error": "推理错误的具体类型",
"difficulty_level": "easy|medium|hard",
"synthesis_prompt": "用于合成类似但不同的问题的提示"
}}"""
response = self.model.generate(prompt)
card_dict = json.loads(response)
card = DifficultyCard(task_id=hashlib.md5(
question.encode()).hexdigest()[:8], **card_dict)
self.failure_store.append(card)
return card
def synthesize_from_card(
self, card: DifficultyCard, n_variants: int = 3
) -> List[dict]:
"""基于难度卡合成新的评测实例"""
prompt = f"""基于以下失败模式,生成 {n_variants} 个不同的新问题:
失败根因: {card.root_cause}
知识缺口: {card.knowledge_gap}
推理错误: {card.reasoning_error}
难度级别: {card.difficulty_level}
合成方向: {card.synthesis_prompt}
要求:
1. 新问题必须与原始问题不同(不能只是换数字)
2. 必须能触发相同的失败模式
3. 每个问题附带标准答案和评分标准
4. 输出 JSON 数组"""
response = self.model.generate(prompt)
return json.loads(response)
def run_stress_cycle(self, eval_set, n_rounds=3):
"""运行一轮压力评测周期"""
all_new_problems = []
for round_idx in range(n_rounds):
# 1. 在当前评测集上运行模型
results = self.evaluate(eval_set)
# 2. 分析失败案例
for r in results:
if not r["correct"]:
card = self.analyze_failure(
r["question"], r["model_answer"],
r["correct_answer"], r.get("trace", "")
)
# 3. 合成新问题
new_problems = self.synthesize_from_card(card)
all_new_problems.extend(new_problems)
# 4. 注入评测集
eval_set.extend(new_problems)
return {
"rounds": n_rounds,
"new_problems_generated": len(all_new_problems),
"failure_patterns": len(self.failure_store),
}
StressEval 的核心洞察:不是”出更难的题”,而是”出更容易暴露特定弱点的题”。与传统随机增加难度不同,它精准瞄准模型的已知失败模式。
三、Agent 评测的特殊挑战:过程审计
传统基准只看结果对不对,Agent 评测必须看过程对不对。Claw-Eval-Live 的实验表明:不看过程,Agent 评测会系统性”放水”——漏掉 44% 的安全违规和 13% 的鲁棒性问题。
3.1 三链证据审计框架
@dataclass
class AuditEvidence:
"""Agent 执行的三链审计证据"""
execution_trace: List[dict] # 执行轨迹(工具调用序列)
server_audit_log: List[dict] # 服务端审计日志
environment_snapshot: dict # 执行后环境快照
class AgentAuditor:
"""Agent 执行过程审计器"""
def __init__(self, sandbox_env):
self.sandbox = sandbox_env
def audit_execution(
self, task_def: dict, agent_session
) -> dict:
"""审计一次 Agent 执行"""
# 1. 捕获执行轨迹
trace = agent_session.get_tool_calls()
# 2. 获取服务端审计日志
audit_log = self.sandbox.get_audit_log(
agent_session.session_id
)
# 3. 执行后环境快照
snapshot = self.sandbox.capture_state()
evidence = AuditEvidence(
execution_trace=trace,
server_audit_log=audit_log,
environment_snapshot=snapshot,
)
# 4. 交叉验证
return self._cross_validate(task_def, evidence)
def _cross_validate(
self, task_def: dict, evidence: AuditEvidence
) -> dict:
"""三链交叉验证"""
findings = {
"completeness": self._check_completeness(
task_def, evidence
),
"safety": self._check_safety(evidence),
"robustness": self._check_robustness(evidence),
"action_verification": self._verify_actions(
task_def, evidence
),
}
# 对比:仅看结果 vs 看过程
result_only_pass = findings["completeness"]["final_match"]
process_verified_pass = all(
v["pass"] for v in findings.values()
)
return {
"result_only_pass": result_only_pass,
"process_verified_pass": process_verified_pass,
"gap": not result_only_pass == process_verified_pass,
"findings": findings,
}
def _check_safety(self, evidence):
"""检查安全违规——只有审计日志能看到"""
violations = []
for log_entry in evidence.server_audit_log:
if log_entry.get("unauthorized_access"):
violations.append(log_entry)
if log_entry.get("data_exfiltration_attempt"):
violations.append(log_entry)
return {
"pass": len(violations) == 0,
"violations": violations,
}
def _check_completeness(self, task_def, evidence):
"""检查任务完成度"""
required_actions = task_def.get("required_actions", [])
executed_actions = [
t["tool"] for t in evidence.execution_trace
]
missing = [
a for a in required_actions
if a not in executed_actions
]
return {
"final_match": task_def.get("expected_output")
== evidence.environment_snapshot.get("output"),
"missing_actions": missing,
"action_coverage": 1 - len(missing) / max(len(required_actions), 1),
}
def _check_robustness(self, evidence):
"""检查鲁棒性——错误注入后的恢复能力"""
error_count = sum(
1 for t in evidence.execution_trace
if t.get("status") == "error"
)
recovery_count = sum(
1 for t in evidence.execution_trace
if t.get("recovered_after_error")
)
return {
"pass": error_count == 0
or recovery_count / error_count > 0.8,
"error_count": error_count,
"recovery_rate": recovery_count / max(error_count, 1),
}
def _verify_actions(self, task_def, evidence):
"""验证关键行动是否真的发生了"""
required_state_changes = task_def.get(
"required_state_changes", []
)
actual_state = evidence.environment_snapshot
verified = []
for change in required_state_changes:
path = change["path"]
expected = change["value"]
actual = self._get_nested(actual_state, path)
verified.append({
"path": path,
"match": actual == expected,
"expected": expected,
"actual": actual,
})
return {
"pass": all(v["match"] for v in verified),
"verified": verified,
}
@staticmethod
def _get_nested(d, path):
keys = path.split(".")
for k in keys:
if isinstance(d, dict):
d = d.get(k)
else:
return None
return d
Claw-Eval-Live 的关键数据:
- 不看过程 → 漏掉 44% 安全违规 + 13% 鲁棒性问题
- HR/People 类任务:所有模型通过率 < 22.2%,多模型直接 0%
- Terminal/Development:强模型已达 100%,已接近天花板
- 真正的瓶颈不是技术操作,是跨系统业务编排
四、评测管道运维:持续质量保障体系
4.1 评测管道的 CI/CD
将评测管道集成到模型迭代流程中,而不是一次性跑完就扔。
# .github/workflows/eval-pipeline.yml
name: Dynamic Eval Pipeline
on:
schedule:
- cron: '0 2 * * 1' # 每周一凌晨运行
workflow_dispatch: # 手动触发
jobs:
contamination-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 检测训练集污染
run: |
python scripts/contamination_check.py \
--eval-set data/eval_current.jsonl \
--train-corpus data/train_corpus.jsonl \
--ngram-n 13 \
--semantic-threshold 0.85 \
--output reports/contamination_report.json
- name: 上传污染报告
uses: actions/upload-artifact@v4
with:
name: contamination-report
path: reports/contamination_report.json
dynamic-bench-generation:
needs: contamination-check
runs-on: ubuntu-latest
steps:
- name: 生成新评测实例
run: |
python scripts/generate_bench.py \
--seed ${{ github.run_number }} \
--tasks "shortest_path,mst,graph_coloring" \
--variants 5 \
--difficulties "easy,medium,hard" \
--output data/eval_dynamic.jsonl
model-evaluation:
needs: dynamic-bench-generation
runs-on: ubuntu-latest
steps:
- name: 运行模型评测
run: |
python scripts/run_eval.py \
--eval-set data/eval_dynamic.jsonl \
--model-endpoint ${{ secrets.MODEL_ENDPOINT }} \
--output reports/eval_results.json
- name: 生成评测摘要
run: |
python scripts/eval_summary.py \
--results reports/eval_results.json \
--contamination reports/contamination_report.json \
--output reports/weekly_eval_summary.md
4.2 评测分数衰退预警
class EvalDecayMonitor:
"""监控评测分数随时间的衰退趋势"""
def __init__(self, history_file: str):
self.history = self._load_history(history_file)
def check_decay(
self,
current_scores: dict,
window: int = 4, # 对比最近4次
threshold: float = 0.05 # 5% 衰退触发告警
) -> List[dict]:
"""检查各基准分数是否出现显著衰退"""
alerts = []
for bench, score in current_scores.items():
past = [h[bench] for h in self.history[-window:]
if bench in h]
if len(past) < 2:
continue
avg_past = sum(past) / len(past)
decay = (avg_past - score) / avg_past
if decay > threshold:
alerts.append({
"benchmark": bench,
"current": score,
"past_average": round(avg_past, 2),
"decay_pct": round(decay * 100, 2),
"severity": "high" if decay > 0.1 else "medium",
})
return alerts
4.3 评测管道健康度检查清单
| 检查项 | 频率 | 不通过时动作 |
|---|---|---|
| N-gram 污染率 < 5% | 每周 | 清洗评测集或切换动态基准 |
| 语义重叠率 < 15% | 每月 | 调整 similarity_threshold 或换题 |
| 基准区分度(最强-最弱差 > 20pp) | 每次评测 | 增加难度梯度或补充任务类型 |
| 题目时效性(> 90天题目 < 30%) | 季度 | 注入新题,退役旧题 |
| 过程审计覆盖率 > 80% | 每次评测 | 补充审计钩子 |
| 分数衰退 < 5%/月 | 月度 | 排查模型变更或评测集退化 |
五、踩坑经验总结
5.1 语义嵌入检测的坑
- 阈值选择:0.85 是通用推荐值,但数学公式/代码的相似度天然偏高,建议降至 0.80;文学/创意写作可升至 0.90
- 批次 OOM:对 100 万级训练语料做全量相似度计算,16GB GPU 最多处理 batch_size=256,再大直接 OOM。解决:先用 FAISS 做近似最近邻,再做精确验证
- 跨语言软污染:中文训练集可能包含英文基准题的翻译版本,嵌入模型需要支持跨语言(推荐 bge-m3)
5.2 动态生成管道的坑
- 实例质量不稳定:LLM 辅助生成的问题可能存在逻辑错误。必须加一道算法验证——用确定性算法验证生成实例的答案正确性
- 可复现性 vs 抗污染的矛盾:seed 固定则可复现但可被逆向,seed 随机则不可复现。解法:公开评测时用固定 seed,但每月更换 seed 并退役旧实例
- 难度标注偏差:自动标注的难度经常不准确。建议用 2-3 个不同能力水平的模型试跑校准
5.3 Agent 评测的坑
- 沙箱逃逸:Agent 可能通过环境变量、网络请求绕过审计。必须在沙箱层面(Docker network=None + seccomp)做隔离
- 审计日志遗漏:只记录工具调用不够,必须同时记录服务端行为(数据库查询、API 调用)。Claw-Eval 的 44% 安全违规漏检就是因为只有调用记录没有服务端日志
- 评分主观性:对于”报告质量”等开放性指标,LLM Judge 和人工评分的一致性约 75%。建议:关键评测项用规则评分,开放性项用 LLM Judge + 人工抽检
结论
大模型评测正在经历从”静态刷榜”到”动态抗污染”的范式转变。本文给出的工程路径可以概括为三步:
- 先诊断:用 N-gram + 语义嵌入检测污染程度,用性能异常检测定位可疑基准
- 换管道:根据场景选择时间窗口(LiveBench)、算法化生成(BeyondBench)或需求信号驱动(Claw-Eval-Live)
- 加审计:对 Agent 评测,必须引入执行轨迹 + 服务端日志 + 环境快照的三链证据审计
这不是锦上添花的优化——当 NIST 用闭源评测给 DeepSeek V4 定性”8 个月差距”,当 78% 的 CodeForces 题目存在训练集软污染,评测的可信度已经成为产业话语权的基础设施。构建可信的评测管道,不是可选项,是必选项。