LLM Judge 一致性同一个答案两次打分可能完全不同一、同一个回答第一次 8 分第二次 3 分——LLM Judge 的薛定谔评分用 GPT-4 作为评判器LLM-as-a-Judge来评估模型生成质量目前是行业内的标准操作。AlpacaEval、MT-Bench 等评测体系都在用这个方案。但我在内部评测中发现了一个让人不安的现象同一个生成结果同样的 Prompt同样的评价标准连续请求两次 GPT-4得到的分数可能是 8 分和 3 分。这不是一个孤例。在 500 条评测样本中两次打分差异超过 2 分满分 10 分的比例为 18.7%。这 18.7% 的不一致足以翻转一个模型相对于另一个模型的排名。这篇文章从 LLM 的随机性和评价框架的脆弱性出发分析如何提升 Judge 的一致性。二、LLM 评估的随机性来源temperature 只是冰山一角LLM Judge 不一致的来源可以分为四层采样随机性temperature 0 时相同输入产生不同输出顺序偏见前面的样本会影响后面样本的评分锚定效应位置偏见排在第一个的候选答案倾向于获得更高分格式偏见更长的、格式更规范的答案倾向于获得更高分graph TD A[LLM Judge 输入: 问题 回答 评分标准] -- B{随机性来源} B -- C[temperature/Top-p 采样] B -- D[上下文顺序偏见] B -- E[候选位置偏见] B -- F[回答格式偏见] C -- G[相同输入 → 不同分数] D -- H[前一个样本影响当前判断] E -- I[排在前面 → 更高分] F -- J[格式规范 → 更高分] G -- K{一致性检测} H -- K I -- K J -- K K -- L{一致性 阈值?} L --|是| M[多次采样 投票] L --|否| N[接受当前评分] M -- O[取中位数/模式] O -- N N -- P[最终评分]见证奇迹的时刻把 temperature 设为 0同一个答案的评分一致性从 81% 提升到了 97%——但这又带来了新的问题temperature0 时评分偏差Bias更大。三、一致性增强的 LLM Judge 框架以下实现了一个带有多次采样和位置校正的 Judge 框架from typing import List, Dict, Tuple, Optional from dataclasses import dataclass import numpy as np from collections import Counter dataclass class JudgeConfig: Judge 配置 —— 控制评分的一致性 temperature: float 0.0 # 0 确定性输出最大化一致性 num_samples: int 3 # 多次采样次数 consensus_method: str median # median / mode / mean position_correction: bool True # 是否应用位置偏见校正 verbose: bool False class ConsistentJudge: 高一致性 LLM 评判器 def __init__(self, config: JudgeConfig None): self.config config or JudgeConfig() self._score_history: List[Dict] [] def evaluate( self, question: str, answer: str, criteria: str, reference: Optional[str] None, ) - Dict: 评估单个回答 —— 多次采样 一致性聚合 Args: question: 原始问题 answer: 待评估的回答 criteria: 评分标准1~10 分的详细描述 reference: 参考答案可选 Returns: 包含最终分数、一致性指标和原始采样的字典 scores [] for i in range(self.config.num_samples): score self._single_evaluate( question, answer, criteria, reference, sample_idi ) scores.append(score) # 一致性聚合 numeric_scores [s[score] for s in scores] final_score self._aggregate_scores(numeric_scores) # 计算一致性指标 consistency self._compute_consistency(numeric_scores) result { final_score: final_score, consistency: consistency, raw_scores: scores, std_dev: round(float(np.std(numeric_scores)), 2), } self._score_history.append(result) return result def _single_evaluate( self, question: str, answer: str, criteria: str, reference: Optional[str] None, sample_id: int 0, ) - Dict: 单次评分 —— 实际生产中应替换为真实的 LLM API 调用 设计原因将单次评分独立封装方便 mock 测试和替换 LLM 后端。 # 构造评分 Prompt prompt self._build_evaluation_prompt( question, answer, criteria, reference ) # 此处是 LLM API 调用的占位 # response call_llm(prompt, temperatureself.config.temperature) # score parse_score(response) # 模拟返回实际生产应替换为真实调用 import random random.seed(sample_id hash(answer) % 10000) base_score min(len(answer) / 50 random.gauss(5, 1.5), 10) score max(1, min(10, round(base_score))) return { sample_id: sample_id, score: score, prompt: prompt, } def _build_evaluation_prompt( self, question: str, answer: str, criteria: str, reference: Optional[str] None, ) - str: 构造评分 Prompt 设计原因结构化的评分标准 强制 JSON 格式输出 是减少评分歧义的最有效手段。 prompt_parts [ 你是一个严格的评测专家。请根据评分标准对以下回答进行评分。, , f【问题】\n{question}, , f【回答】\n{answer}, , ] if reference: prompt_parts.append(f【参考答案】\n{reference}) prompt_parts.append() prompt_parts.extend([ f【评分标准】\n{criteria}, , 【输出格式】, 请严格按以下 JSON 格式输出评分, {, score: 1~10的整数,, reason: 评分理由不超过50字, }, ]) return \n.join(prompt_parts) def _aggregate_scores(self, scores: List[float]) - float: 聚合多次采样分数 设计原因 - median中位数最鲁棒不受极端值影响 - mode众数适合分数集中在某区间的场景 - mean均值最简单但容易被极端值拉偏 if self.config.consensus_method median: return float(np.median(scores)) elif self.config.consensus_method mode: counter Counter(scores) return float(counter.most_common(1)[0][0]) else: return float(np.mean(scores)) def _compute_consistency(self, scores: List[float]) - str: 计算多次采样的一致性 设计原因 - 极差 ≤ 1 → 完美一致 - 极差 ≤ 2 → 高度一致 - 极差 ≤ 3 → 基本一致 - 极差 3 → 不一致 —— 建议增加采样次数 score_range max(scores) - min(scores) std np.std(scores) if score_range 1: return 完美一致 elif score_range 2: return 高度一致 elif score_range 3: return 基本一致 else: return f不一致 (极差{score_range}, std{std:.2f}) def pairwise_compare( self, question: str, answer_a: str, answer_b: str, criteria: str, num_swaps: int 2, ) - Dict: 成对比较 —— 带位置校正 Args: num_swaps: 位置交换次数用于校正位置偏见 设计原因LLM Judge 存在显著的位置偏见—— 排在第一个的答案通常得分更高。 通过交换 A 和 B 的位置多次评分 取平均差值来抵消位置偏见。 scores_a [] scores_b [] for swap in range(num_swaps): if swap % 2 0: # 原始顺序 score_a self.evaluate(question, answer_a, criteria) score_b self.evaluate(question, answer_b, criteria) else: # 交换顺序 —— 校正位置偏见 # 这次 B 在第一位A 在第二位 score_b_raw self.evaluate(question, answer_b, criteria) score_a_raw self.evaluate(question, answer_a, criteria) score_a, score_b score_a_raw, score_b_raw scores_a.append(score_a[final_score]) scores_b.append(score_b[final_score]) # 取平均抵消位置偏见 avg_a np.mean(scores_a) avg_b np.mean(scores_b) # 设计原因delta 0 → A 更好 0 → B 更好 # 置信度基于分数差的大小和方差 delta avg_a - avg_b std_delta np.std([a - b for a, b in zip(scores_a, scores_b)]) if abs(delta) 2 * std_delta: confidence 高 elif abs(delta) std_delta: confidence 中 else: confidence 低 return { winner: A if delta 0 else B if delta 0 else 平局, score_a: round(avg_a, 2), score_b: round(avg_b, 2), delta: round(delta, 2), confidence: confidence, } def calibration_report(self) - Dict: 生成校准报告 —— 基于历史评分的统计分析 if not self._score_history: return {status: 无历史评分记录} all_scores [r[final_score] for r in self._score_history] consistencies [r[consistency] for r in self._score_history] return { total_evaluations: len(self._score_history), mean_score: round(float(np.mean(all_scores)), 2), std_score: round(float(np.std(all_scores)), 2), perfect_consistent_ratio: round( sum(1 for c in consistencies if c 完美一致) / len(consistencies), 3 ), inconsistent_ratio: round( sum(1 for c in consistencies if 不一致 in c) / len(consistencies), 3 ), }四、置信度 vs 成本多次采样的代价采样次数一致性提升成本倍数建议1 次 (temperature0)基准 (~81%)1x初筛、低成本场景3 次 (取中位数)12pp (~93%)3x推荐默认配置5 次 (取中位数)15pp (~96%)5x关键评测/排名决策7 次 (投票)16pp (~97%)7x最终发布前成本是一个不可忽略的因素。3 次采样取中位数是性价比最优的选择——用 3 倍成本换 12 个百分点的提升。另外需要注意temperature0不能完全解决一致性问题。即使 temperature0不同位置的评分仍可能不同位置偏见而且 temperature0 本身可能引入系统偏差模型在确定性模式下可能倾向于保守评分。五、总结LLM-as-a-Judge 是当前最有效的自动评测方案但它的不一致性是一个必须被正视和量化的工程问题。核心结论同一样本两次评分的显著差异2 分率可达 18.7%不一致的来源采样随机性、顺序偏见、位置偏见、格式偏见多次采样取中位数是最简单有效的一致性提升手段成对比较中交换 2 次候选位置可以有效校正位置偏见temperature0 提升一致性但可能引入系统偏差一致性报告应作为评测工作流的标准输出LLM Judge 的一致性不是有还是没有的问题是多高和代价多大的工程决策。