把 LLM Judge 当成最终判定结论是很多团队在做 Eval 时

小美爱学习 初级 2小时前 799 浏览 14 点赞 约 1 分钟

很多公司在推 AI Agent 落地时,习惯用一个更强的大模型(比如 GPT-4o 或 Claude 3.5)来给 Agent 的输出打分。但问题是,如果你发现 Judge 经常报同一个错,却一直把它留在 Judge 环节,你其实是在为已经发现的 Bug 支付重复的“租金”。因为 Judge 慢、贵,而且不确定,每次跑 Eval 结果可能都不一样。

真正高效的实操应该是建立一个“棘轮机制(Ratchet)”,把那些重复出现的 Judge 结论,尽可能地向低层级(更确定、更便宜)的检查机制迁移。

我把证据强度分成了三个层级,这在实际部署工作流时非常关键:

  • Tier 1(不可伪造的证明): 比如 JSON 格式是否正确、文件是否存在、是否编译通过、是否超时。这是绝对的硬指标,速度极快且免费。
  • Tier 2(统计信号): 比如输出与任务规格的 Embedding 相似度、长度分布、Diff 结果是否为空。它依赖于 Agent 无法控制的基准线,具有确定性。
  • Tier 3(Model-as-Judge): 纯粹的模型观点。这只能作为信号,不能作为最终裁决。

当 Judge 反复指出某个问题(例如:摘要中引用了原文不存在的章节)时,不要依赖 Judge 继续判,而要思考:有没有 Tier 1 或 Tier 2 的方法能抓到它?

在这个例子里,可以通过简单的字符串匹配(检查引用标题是否在原文中出现)将其升级为 Tier 1 检查。

type Finding = {
 claim: string; // Judge 反复抱怨的问题
 sourceText: string; // Agent 没写过的内容(原文)
 citedSections: string[];
};

// 升级到 Tier 1:将主观观点转化为不可伪造的事实检查
function citationsExist(f: Finding): { pass: boolean; missing: string[] } {
 const missing = f.citedSections.filter(
 (s) => !f.sourceText.includes(s)
 );
 return { pass: missing.length === 0, missing };
}

// 升级到 Tier 2:如果完全匹配太死板,则用 Embedding 相似度对比基准线
function citationGroundedness(
 f: Finding,
 embed: (t: string) => number[],
 cos: (a: number[], b: number[]) => number
): number {
 const src = embed(f.sourceText);
 const scores = f.citedSections.map((s) => cos(embed(s), src));
 return scores.reduce((a, b) => a + b, 0) / (scores.length || 1);
}

在公司内部推行这套逻辑后,你会发现 80% 的生产环境失败(比如 JSON 格式崩了、路径幻觉、响应为空)其实都能通过 Tier 1 和 Tier 2 拦截掉。把确定性的东西交给代码,把模糊的争议留给 Judge,这样 Eval 流程才能跑得快且稳。

工作流AIAI落地agentsevaluation

全部回复 (4)

架构师老刘 中级 9小时前
而且Judge还容易被长答案给骗,字数越多分越高。
0 回复
大Jerry 高级 9小时前
之前就被这坑搞过,最后还是得把判别标准固化成代码才行。
0 回复
极客Ray 高级 9小时前
@大Jerry 代码虽然死板但起码稳,你当时是用正则还是写脚本跑的?
0 回复
副业中创业者 初级 9小时前
后来我把部分判断逻辑写成了正则,速度快多了还稳。
0 回复

发表回复

支持 Markdown 格式