以下是一个 RAG 系统的输出:它对一个上下文无法回答的问题断言了一条定价声明,而这条声明从未被提供给它。我用两种最流行的 LLM-as-judge 忠实度指标分别对它进行了五次评估,评判模型均为 gpt-4o,温度设置为 0——这是最有利于评判稳定性的设置。

RAGAS 给它的得分是 0.000

DeepEval 给它的得分是 1.000——五次重复评估全部如此,并解释道:“得分为 1.00 的原因是实际输出与检索上下文之间不存在矛盾。” 其中一次评估还补充道:“在保持准确性和一致性方面做得很好!”

这两个指标都叫忠实度。它们内部都一致。只有其中一个能察觉到捏造。

我想解释一下为什么会出现这种情况、我在正确测量后还发现了什么,以及为什么我的结论是两者都要用——同时使用 LLM 评判和确定性检查,而不是你可能预期的“LLM-as-judge 遭贬”。

我为什么需要测量这个

我为医疗保健构建 AI 工具——用于医学作家的声明验证、面向患者的文本简化器(已注册为医疗器械)、临床去标识化。在这个领域,一个答案只有能从其源材料中得到证明才有意义,而真正要命的失效模式往往很隐蔽:简化出院小结中某药物的剂量被静默删除;模型“善意”编造的参考范围;系统在上下文根本没有答案时仍自信地给出回答。

我需要根据这些属性来决定是否发布——当提示词的改动让系统变得不可信时,就让构建失败。而 LLM-as-judge 指标在构建门禁上很不方便:每次运行都要花钱,结果不确定,而且(事实证明)同一指标的两种实现并不测量同一件事。

于是我构建了 OpenGATE,其中每个检查都是输出和人工标注黄金案例的纯函数:必需的事实必须出现(允许接受的改写)、答案中的每一个数字都必须能追溯到上下文、当上下文无法回答时系统必须放弃回答。整个过程不使用任何评分模型。然后,我针对 RAGAS 和 DeepEval 进行了受控对比,以了解每种方法实际能捕捉到什么。

实验

一个包含 27 个输出的冻结语料库:6 个捕获到的系统输出(其中 3 个来自生产环境),加上为每个输出精确注入一种已知缺陷的变体——遗漏事实、捏造数字、未能放弃回答、追加矛盾或原地意义反转。每种情况重复五次。评判模型为 gpt-4o,温度 0。

有三个设计选择对公平性至关重要。缺陷类别按范围分组,从不求和——确定性检查无法察觉意义反转,因此把所有内容都塞进一个准确率数字会扭曲结果(无论哪个方向)。检测率是通过与同一案例未变异的基础输出相比,针对注入缺陷的反应来衡量的,这样就不会把原有的小毛病误算为捕获。输出只有在每一次重复中都被标记为失败才算被检测到——一个间歇性失效的门禁不是真正的门禁。所有输入、脚本和每次重复的得分都已提交至 论文附件

结果是双面的

评判模型胜出的地方——决定性优势。 在意义反转(“随餐服用”变为“空腹服用”,而所有锚点和数字都逐字保留)上,RAGAS 捕获了 4/5,DeepEval 捕获了 5/5。确定性检查捕获了 0/5——而且永远如此。字符串检查没有意义模型。这是评判模型的分类优势,而非边际优势,这也是为什么本文不是一篇“评判模型遭贬”的文章。

评判模型失利的地方。

遗漏。 缺失抗生素剂量并未断言任何不支持的内容——因此忠实度指标天生对此视而不见。评判模型捕获了 0/5 和 1/5 的遗漏事实。确定性锚点检查捕获了 5/5。在那份我删除了 500 mg 剂量的出院小结上,DeepEval 返回了 1.00,并给出理由 “不存在矛盾。” 一个对通过分数的自信解释,却对应着一个缺失抗生素剂量的输出。

成本与速度。 每 1,000 次评估,RAGAS 花费 11.49 美元,DeepEval 花费 8.29 美元,而确定性方法为 0.00 美元。每次重复分别耗时 194 秒和 119 秒,而确定性方法仅需 3.8 毫秒。这个差异决定了你能否在每次提交时——或每次回答时——运行检查。

定位能力。 当确定性检查失败时,它会指明失败原因:缺少事实 “500 mg”。RAGAS 返回一个标量。DeepEval 返回一个理由,有时很好,有时就是上面那句“不存在矛盾”。

我最关心的发现是定义上的。 RAGAS 问的是“每个声明是否都有上下文支持?” DeepEval 的忠实度问的是“是否有任何声明与上下文矛盾?” 一个编造的数字与上下文并不矛盾——上下文对此保持沉默。因此在六个断言了源材料未包含内容的输出上,RAGAS 捕获了 5 个,DeepEval 捕获了 0 个。在明显的矛盾上,它们的结果接近(7/10 vs 9/10)。这种差异是系统性的,而非噪声。

令人不安的含义是:一个团队在没有阅读实现细节的情况下采用“LLM-as-judge 忠实度”,它并没有选择一种严谨程度,而是无意中选择了对哪种失效模式视而不见。对于面向患者的医疗工具,编造剂量是最需要防范的失效,而这正是基于矛盾的评判模型会放行的。

我正在撤回的一个主张

我设计这个实验时,本期望证明评判模型的不稳定性。在强评判模型上,这个发现很弱,我如实报告而非掩盖:在 gpt-4o/温度 0 的设置下,每次输出得分的平均范围为 RAGAS 0.026、DeepEval 0.013。而在 gpt-4o-mini 上,同一语料库的噪声显著增大(11/27 个输出在重复间改变了判定)——因此不稳定性是评判模型的属性,而非评判本身的属性。不在构建门禁上使用评判模型的理由,基于遗漏盲区、定义分歧和成本——这些都不是更好的评判模型所能修复的。

确定性门禁在生产环境中捕获到什么

该框架在四个生产系统中通过 CI 运行。首次运行的结果(此前均未知):一个静默解析失败导致约 50% 的多声明判定默认变为“未支持”;去标识化引擎中的两个姓名捕获缺陷(像 O'Brien 这样的撇号姓氏从捕获模式中漏掉);以及简化器从出院小结中漏掉了抗生素剂量。

我最喜欢的一个失效发生在几个月后。在剂量遗漏问题修复后,同一系统产生了一个捏造的数字:“通常,我们希望血红蛋白水平高于 12 g/dL”——临床上正确,但源信中并不存在。之前的提示词修复说绝不遗漏或更改数字;它禁止丢失数字,但对编造数字保持沉默。一个针对上一个缺陷加固的提示词,并不能针对下一个缺陷——这正是主张每次变更都运行门禁而非仅进行一次审计的全部理由。一个绿色的评分卡是一次测量,而非一种属性。

坦诚的免责声明

这些变异是合成的,源于我观察到的缺陷,而非来自野外采样。语料库只有 27 个输出。仅使用一个评判模型。而且我既编写了缺陷分类法,也编写了其中一个评估臂——这就是为什么按范围分别报告结果,以及为什么在语料库中包含我自己方法得分为零的反转类别。完整论文包含威胁有效性的章节,包括我已预注册但尚未运行的实验(为黄金集独立标注第二位标注者)。

我实际的建议

两者结合使用,各取所长。用 LLM 评判来处理语义——意义反转、矛盾、开放式质量——这是它在分类上更擅长的领域。用确定性检查作为门禁:必需事实存在、数字可追溯、放弃回答得到遵守——可复现、能指明具体失败、免费、速度快到可以用于每次提交和每次回答。

如果你想尝试确定性部分,它采用 MIT 许可,只需一行命令即可运行,无需 API 密钥:

npx @pharmatools/opengate

进入全屏模式 退出全屏模式

Python(pip install opengate-grounding):

from opengate_grounding import check_grounding

result = check_grounding(
    answer,
    context,                        # 检索到的证据
    anchors=["500 mg", "twice daily"],  # 答案必须包含的事实
)
result.grounded   # 确定性——相同证据,每次运行得出相同判定

进入全屏模式 退出全屏模式

还有 pytest 辅助工具、DeepEval 的 GroundingMetric(是的——该集成可以与评判指标很好地并存;这就是重点)、一个在回归时让构建失败的 GitHub Action,以及一个 MCP 服务器,让代理能在回复前自行检查答案。

仓库:github.com/nickjlamb/opengate · 论文:doi.org/10.5281/zenodo.21365095

我是一名医学作家,后来转向为医疗保健构建 AI 工具。本文中的所有内容均可从已提交的附件中复现——如果你发现有站不住脚的地方,请开 issue;这就是门禁存在的意义。