把 LLM 评审员"代码化":PAJAMA 用 80 个 Python 函数替代一整支裁判团

论文:Codifying the Judge: Scalable Evaluation via Program Distillation(arXiv: 2607.22561) 作者:Tzu-Heng Huang、Shengqi Qiu、Frederic Sala 机构:University of Wisconsin-Madison 链接:https://arxiv.org/abs/2607.22561 | 代码:github.com/SprocketLab/PAJAMA


你有没有过这种经历——线上跑的 reward model 越调越大、API 账单越涨越猛,团队里开始有人嘀咕"我们到底在评什么"?

LLM-as-a-judge 这几年几乎是评测管线的事实标准:成对偏好标注、奖励模型蒸馏、RLHF 反馈,统统靠把候选丢给一个 GPT/Gemini/Claude 让它打分。但代价是 每次评估都要重新跑一遍百亿参数的推理,并且你永远不知道它那句"我喜欢 response A"是基于什么理由、是格式偏好、是位置偏好、还是纯幻觉。

这篇来自 UW-Madison 的工作给出了一个挺反直觉的解法:让 LLM 一次性"吐出"一段 Python 函数,函数签名固定为 judge(query, response) → float,后续所有评分都靠本地执行程序。整个系统叫 PAJAMA,5 个偏好数据集上 78.11% 的平均准确率能追平 OLMo-2-13B-Instruct(79.70%),而吞吐量是后者的 47 倍。最让我意外的是奖励模型蒸馏那一组实验——用 PAJAMA 的程序判分当监督去微调 Qwen2.5-3B,RewardBench 上反而比用 GPT-4 标签训练的版本高出 1.67 个点,API 成本却只有 1/50。

一、LLM 评审员的"四宗罪"

作者把 LLM-as-a-judge 的痛点拆得很细,我把它压缩成一张表:

痛点 实际工程代价
推理成本 GPT-5 评估百万样本 ≈ 一笔不小的话费;开源部署不烧 API 但烧 GPU
逻辑不透明 输出理由看着像那么回事,但内部决策链没法审计——到底是真的"在评质量"还是被 markdown 格式分了心?
系统性偏差 位置、冗长、引用、性别、富内容——LLM 的偏好像个黑盒抽奖
重复推理税 评分标准微调一次,整个数据集要重跑一遍

第一和第三点在工业界是显性成本——账单上看得见、回归测试里能复现。但第二和第四点更隐蔽,也更致命:你没办法把一个"判断"diff 给同事 review。改一个 rubric 就意味着重跑推理,迭代速度被卡死。

PAJAMA 的核心想法是:把"判断逻辑"和"判断执行"彻底解耦。LLM 只在合成时调用一次(一次性 \(\mathcal{O}(1)\) 投资),之后所有评估都是本地 Python 函数调用,\(\mathcal{O}(n)\) 的 API 费用直接消失。

二、思路:把评审员"蒸馏"成程序委员会

2.1 一个合成示例

作者用 Claude Opus 4.6 一次性合成了 ~80 个候选程序,每个程序负责从某个角度评估候选响应。Figure 1 完整展示了"逻辑连贯性"这个评估准则下,LLM 给出的 judging_function 长什么样:

Figure 1: 程序化评审的合成示例——左侧是合成 prompt,右侧是 LLM 生成的 Python judging_function,结合语义漂移(TF 向量余弦相似度)、主题一致性(段落间词汇重叠)、篇章标记等特征,加权打分后做归一化

图 1:程序化评审合成示例。LLM 接收合成 prompt(左上)后输出 Python judging_function,实现"逻辑连贯性"评估准则,组合 TF 向量余弦相似度的语义漂移、话语段落的主题一致性、加权打分等可解释特征,对矛盾和截断施加显式惩罚。

最有意思的设计是特征层面的可解释性——coherence_score = 0.53·sim_mid + 0.25·(1/(1+10σ²)) 这种公式,每一项都对应自然语言里说得清楚的语义概念。你想让模型更关注"主题一致性",改一行权重就行;想加个新维度,再让 LLM 合成一个程序。这是 LLM 评审员永远给不了你的可调试性

2.2 单一程序不够,所以搞了个委员会

作者也承认,单个程序扛不住所有类型的输入。直接让 LLM 自由合成会产生一堆逻辑重复的程序(都基于"长度"打分)。解决方案是预先策划 10 个不同维度的评估准则(如连贯性、清晰度、结构、相关性、可读性、完整性、变化度、长度充分性、话语标记、矛盾检测),每个准则独立合成 8 个候选程序。文本相似性检查会过滤掉逻辑重复的,最终留下大约 80 个差异化程序。

然后按验证集准确率做 top-k 选择:选 8~21 个程序组成最终委员会(不同数据集保留数量不同),丢弃低于随机概率(<50%)的程序。这一步至关重要——它是后续弱监督聚合的输入。

2.3 校准:让"异质打分"在同一坐标系说话

每个程序输出量纲都不同——有的输出 0~1 的概率,有的输出原始 token 数。作者用了两步校准

  1. Min-max 归一化\([0, 1]\)
  2. 离散化为投票 + 弃权区间:计算两个候选的质量差异 \(d_{ij} = \hat{s}^{(1)} - \hat{s}^{(2)} \in [-1, 1]\),若 \(|d_{ij}| < \tau_j\) 则程序弃权。\(\tau_j\) 在验证集上 grid search 最大化准确率确定

弃权机制是个挺巧的设计——程序信号太弱时,沉默比乱说话更可靠

2.4 弱监督聚合:让 Snorkel 派上用场

top-k 程序的投票构成偏好矩阵 \(L \in \{-1, 0, +1\}^{N \times k}\)。这一步直接套用 Snorkel 框架的标签模型:从程序间的一致/分歧模式估计每个程序的准确率,学出聚合权重,推理时输出联合判定。

说实话看到这里我愣了一下——Snorkel 是 2016 年的弱监督方法,作者把它嫁接到 LLM 评审的程序化版本上,逻辑上确实自洽:每个程序就是一个"标注函数(labeling function)",量纲乱、覆盖率不满、互相有冲突,完美匹配 Snorkel 的预设。

2.5 置信度路由:不确定的样本才升级到 LLM

程序委员会对每个样本会输出两个内部信号: - 投票方差:程序间分歧越大,越不确定 - 聚合器后验:后验概率越接近 50%,越不确定

这两个信号零额外监督——纯靠程序之间的共识度判断。低于阈值的样本路由到 LLM 评审,其余由程序决定。阈值连续扫描,可以描绘出"准确率 vs 吞吐量"的完整曲线。

Figure 2 把这套流程画得很清楚:

Figure 2: PAJAMA 完整工作流——用户 query + 两个候选响应输入,由 LLM 一次性合成的程序委员会评分,弱监督模型聚合输出联合判定 Y;低置信度样本路由回 LLM 评审

图 2:PAJAMA 工作流。给定查询 \(q\) 和两个候选响应 \(r^{(1)}, r^{(2)}\),由 LLM 从 6 个策划准则(Relavance、Readability、Completeness、Coherence、Clarity、Structure)合成的程序化评审池产生初始评估,弱监督聚合为联合决策,不确定案例路由至 LLM 评审。

三、实验:追平 13B 评审员,快 47 倍

3.1 程序评审的"性价比曲线"

5 个偏好数据集、4 个模型家族(专有:GPT-4.1、GPT-5 Thinking;开源:OLMo-2、Gemma-3、Qwen2.5),LLM 评审用 vLLM 64 并发,程序评审用 24 CPU 线程并行。

Figure 3 的 6 个子图把"准确率-吞吐量"曲线画在了一张图上——

Figure 3: 5 个偏好数据集 + Average 的准确率-吞吐量散点图。PAJAMA(红点)以 ~439 samples/sec 的吞吐量与中型 LLM 评审竞争,曲线上的点是不同尺寸的 LLM judge

图 3:五个偏好数据集上准确率 vs 吞吐量。每个子图标题报告选择后保留的程序数量(8~21 个)。红色实心圆为 PAJAMA,灰色虚线为专有 LLM(GPT-4.1、GPT-5 Thinking),彩色折线为各模型家族不同尺寸的 LLM 评审。

评估器 平均准确率 平均吞吐量 (samples/sec)
GPT-4.1 87.68% 1.83
GPT-5 Thinking 85.72% 0.10
OLMo-2-13B 79.70% 9.30
Qwen2.5-14B 87.77% 8.83
PAJAMA 78.11% 439.41

几个关键数字: - PAJAMA 平均 78.11% vs OLMo-2-13B 79.70%:准确率差距 1.59 个点 - 速度快 47.25×:程序评审在 24 核 CPU 上跑出了 439 samples/sec - 比最快的 LLM 评审(OLMo-2-13B)还快 47×:vLLM 也才 9.3 samples/sec - 程序覆盖率 >95%:所有数据集上程序能给出非弃权判定的样本比例都极高(最高 99.20%)

我的第一反应是:1.59 个点的差距在很多场景下完全可以接受——花 1/47 的成本换 1.6 个点的差距,对中小团队来说是白送

3.2 混合评估推进 Pareto 前沿

PAJAMA 不止能当纯程序评审员,更关键的是它能作为路由信号给一个更大的 LLM 兜底。

Figure 4-7 展示了 OLMo-2、Qwen2.5、Gemma-3 三个模型家族内不同尺寸 LLM 作为兜底对象时的路由曲线:

Figure 4: OLMo-2 家族内路由结果——红色 Confidence 曲线在 1B/7B/13B 三个尺寸上都主导了无模型路由基线

图 4:OLMo-2 家族内的路由。Confidence(红)= 程序后验概率路由;Vote Variance(蓝)= 投票方差路由;Query/Response Length = 启发式路由;Random = 随机路由;黑色虚线圆 = 端点(纯程序或纯 LLM)。

配置 准确率提升 吞吐量提升
OLMo-2-1B + PAJAMA +23.5% 5.1×
OLMo-2-7B + PAJAMA +5.0% 2.9×
OLMo-2-13B + PAJAMA +1.3% 2.3×
Qwen2.5-0.5B + PAJAMA +29.2% 3.6×
Qwen2.5-1.5B + PAJAMA +19.2% 4.0×
Qwen2.5-3B + PAJAMA +2.6% 2.2×
Gemma-3-270M + PAJAMA +26.7% 2.9×
Gemma-3-1B + PAJAMA +23.5% 3.3×

Figure 5: Qwen2.5 家族内路由结果——5 个尺寸的 LLM 评审作为兜底对象,Confidence 路由在中小模型上收益最大

图 5:Qwen2.5 家族内的路由曲线。Qwen2.5-0.5B/1.5B/3B/7B/14B 五个尺寸作为兜底 LLM。

Figure 6: Gemma-3 家族内路由结果——4 个尺寸的路由曲线

图 6:Gemma-3 家族内的路由曲线。Gemma-3-270M/1B/4B/12B 四个尺寸作为兜底 LLM。

一个挺反直觉的发现:收益最大的不是最大的 LLM,而是中小尺寸的 LLM。OLMo-2-1B + PAJAMA 提升 23.5 个点、准确率从 53% 抬到 77%,吞吐量还翻了 5 倍。这逻辑上很合理——1B 模型本身评分质量差,程序委员会比它强太多,路由决策几乎总是对的;13B 模型本身已经很强,路由的边际收益就小。

最后 Figure 7 把所有模型、所有数据集的 Pareto 前沿汇总:

Figure 7: PAJAMA 在 OLMo-2/Gemma-3/Qwen2.5 三个模型家族上推进 Pareto 前沿——红色 PAJAMA frontier 始终包住灰色 LLM-only frontier

图 7:混合评估推进 Pareto 前沿。三列分别为 Oracle Router(理论上界)、Vote Variance、Aggregator Posterior 路由信号。红色实线 = PAJAMA frontier,灰色实线 = LLM-only frontier,彩色虚线 = 各模型尺寸单独 frontier。

Oracle Router(只升级程序会判错的对)是上界,PAJAMA 的两种信号都接近这个上界——这意味着程序委员会的"不确定"信号是相当可靠的,比随机路由、query length 启发式、response length 启发式都更接近最优。

3.3 奖励模型蒸馏:50× 便宜,效果反而更好

这是整篇论文让我最意外的一组实验。

设置:从 Prometheus 和 JudgeLM 各采样 20,000 偏好对,用 PAJAMA 的程序评审重新标注,作为 Qwen2.5-3B-Instruct 在 Bradley-Terry 目标下的微调监督。评估分两层: - 域内准确率:在 Prometheus/JudgeLM 测试集上 - 域外泛化:RewardBench(Chat、Chat Hard、Reasoning 三个子集)

标注源 API 调用量 估算成本 Prometheus 域内 JudgeLM 域内 RewardBench 均值
GPT-4 20,000 samples $363.97 97.23% 90.24% 54.98%
PAJAMA 80 programs $7.2150× 便宜 92.20% 82.79% 56.65%

注意最后两列——RewardBench 上 PAJAMA 标签训练的模型反而高出 1.67 个点。JudgeLM 训练版本甚至高出 4.49 个点(61.77% vs 57.28%)。

我的第一反应是怀疑:是不是程序标签噪声更大,反而成了某种正则化?作者没明说,但 RewardBench 的子集结果给了一些线索:

类别 PAJAMA 标签 (Prometheus 训练) GPT-4 标签
Chat 79.33 68.44
Chat Hard 30.04 38.82
Reasoning 60.58 55.70

PAJAMA 在 Chat 和 Reasoning 上赢,在 Chat Hard 上输。Chat Hard 是 RewardBench 里专门构造的"看似对但实则错"的样本,GPT-4 标签在这种 adversarial 数据上更有优势;而程序标签因为只评估显式特征(语义漂移、主题一致性等),可能对"看起来对但其实有逻辑陷阱"的样本不够敏感。这是个诚实的 trade-off——你拿 1.5 个点的 Chat Hard 换 10 个点的 Chat,外加 50× 的成本优势,工程上多数场景是划算的。

3.4 偏差可校准:把"评审员的偏见"当成 bug 修

最后一组实验测的是 LLM 评审员的"老大难"——偏差。作者构造了 5 种扰动: - 位置偏差:交换两个候选的顺序 - 富内容偏差:给响应加 markdown、emoji 等 - 引用偏差:引用但不提供证据 - 性别偏差:替换指代性别的人称 - 冗长偏差:把响应拉长

两个指标:Flip Rate(扰动后判定改变的占比,越低越好)、Bias Win Rate(偏差响应最终胜出的占比,越低越好)。

方法 平均 Flip Rate 平均 BWR
OLMo-2-1B 57.72% 27.85%
OLMo-2-7B 27.62% 13.62%
OLMo-2-13B 54.97%
Qwen2.5-14B 24.64%
PAJAMA(未校准) 39.78% 12.09%
PAJAMA(Claude Code 校准后) 35.58% 7.60%

未校准的 PAJAMA Flip Rate 已经低于多数 LLM——位置偏差 0%(因为程序对顺序不敏感),冗长偏差因为显式惩罚短/长响应也表现不错。

更牛的是校准机制:用 Claude Code 编码代理对程序源代码做迭代编辑,专门针对偏差类型做修补。比如富内容类,把"奖励 markdown 列表"那段逻辑直接删掉,Flip Rate 单项改善 9.39 个点。

作者原话:偏差不再是评估器的"固定属性",而是可修补的 bug

这个观点我太同意了——LLM 评审员的偏差你想修补都没法动手,程序化评审员的偏差你能直接改源代码。从工程角度,可调试性本身就是一种巨大的优势

3.5 验证集到底要多大?

附录 D.1 测了一个我很好奇的点:验证集从 100% 缩到 5%,程序选择和聚合器的性能会塌吗?

验证集比例 JudgeLM Acc. Prometheus Acc. PandaLM Acc.
100% 0.807 0.880 0.698
60% 0.809 0.880 0.694
20% 0.807 0.882 0.692
5% 0.805 0.882 0.692

几十个样本就够——准确率变化不到 0.5 个点。这意味着 PAJAMA 不会反过来被"标注验证集"卡脖子,标注成本主要还是来自程序合成的 \(\mathcal{O}(1)\) 一次性投资。

四、我的判断:漂亮,但有适用边界

4.1 亮点

程序蒸馏这套范式真的挺漂亮。它把 LLM 评审的"成本-准确率-可解释性"三角问题里,可解释性这一角直接砍到了零边际成本。我尤其喜欢它对"偏差可修补"的论证——LLM-as-a-judge 的偏差你只能等下一代模型去修,程序化评审的偏差你今天就能在 IDE 里改

奖励模型蒸馏那个 +1.67 个点的结果非常 surprising。直觉上程序标签噪声更大,应该作为弱监督训练会输给 GPT-4 标签,但实验结果反过来了。我没看到作者详细解释,可能的解释是: - 程序标签在不同 rubric 间一致性更高(都是同一组合成参数),GPT-4 标签随 prompt 变异性大 - 程序标签的"显式特征"组合反而提供了某种隐式正则化 - 域内评测时 GPT-4 标签占优(97.23% vs 92.20%),但 RewardBench 评测时"看穿陷阱"的能力更依赖真实偏好,程序标签可能更鲁棒

4.2 局限

作者自己列了三点,我也补充一些

  1. 依赖底层 LLM 能力。如果 LLM 不理解任务(生成无效程序),整个系统塌掉。对复杂数学/编码任务,程序的特征工程可能泛化不了——这些场景仍需 LLM 兜底。
  2. 适用范围有限。需要"可直接被 Python 函数评估"的候选——主观性、创造性的任务,程序化评审员会显著失真。
  3. 路由信号对 Chat Hard 类 adversarial 样本不够敏感(3.3 节已讨论)。

还有一个工程上的隐性风险:80 个程序在不同数据集上的泛化能力有差异。你给一个新领域,可能要重新合成一批程序——一次性投资变成了"每次迁移都要重新投资"。不过作者说 80 个程序在 5 个数据集上零样本迁移都 work,这点需要更多领域验证。

4.3 与同期工作的位置

说实话,把 LLM-as-a-judge 的判断逻辑"固化"成可解释组件这个方向,过去几年有不少尝试: - Prometheus 系列:开源 LLM 评审员,本质还是在训一个 LLM judge,成本/不透明性没解决 - JudgeLM:同上 - 路由/级联评估:FrugalGPT、EcoAssistant 等,更多是 model-level 的 cascade,不涉及"判断逻辑的代码化" - Snorkel 风格弱监督:作者直接借了 Snorkel 框架,但嫁接到 LLM 评审场景上是新的

PAJAMA 的位置可以这样描述:它不是新方法,而是把现有组件(弱监督 + 程序合成 + 置信度路由)拼成了一套专门解决"LLM 评审的成本-不透明性"问题的范式。这种"工程整合 + 准点踩对"的工作,工业上其实价值很高——它让你明天就能在自己的评测 pipeline 里替换掉一部分 LLM 调用。

五、给你的工程启发

如果你的团队在用 LLM-as-a-judge 做大规模评估,PAJAMA 给了三个立刻可用的实践建议:

  1. 先做"程序 + LLM 兜底"混合评估。不要全切,把 PAJAMA 跑在 80% 明显可自动化评估的样本上,剩下的 20% 仍走 LLM。成本直降 5×,准确率影响很小。
  2. 把你的 rubric 显式化。你团队的评分标准如果写得出来,就让 LLM 合成对应的程序——这本身就是一次 rubric 审查。
  3. 把偏差当 bug 管。LLM 评审员的偏差你只能"换模型碰运气",程序化评审员的偏差你能在 PR 里改——把这个工作流嵌进你的 CI/CD。

如果你也在调 reward model、对 API 账单敏感、或者在 debug LLM 评审员的奇怪判定,这套程序化评审的思路值得认真试一下。代码已开源,80 个程序就是 80 个可以审计、可以修改、可以重用的评估函数——比起黑盒 GPT-5,这至少是工程友好的。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新 AI 前沿,关注我。