T
traeai
登录
返回首页
Towards Data Science

LLM评估基于直觉——我构建了决定什么能发布的缺失层

8.5Score
LLM评估基于直觉——我构建了决定什么能发布的缺失层

TL;DR · AI 摘要

LLM评估系统存在重大缺陷,需引入决策层以识别虚假信息。

核心要点

  • 构建了基于可信度和具体性的评分层,可检测幻觉内容。
  • 单个分数无法区分自信但错误的响应与真实响应。
  • 提供完整代码实现,可在生产环境中部署。

结构提纲

按章节快速跳转。

  1. 文章提出了一种新的LLM评估方法,解决了现有系统无法识别幻觉内容的问题。

  2. 当前LLM评估依赖直觉判断,无法有效识别自信但错误的响应。

  3. 构建了一个包含可信度和具体性两个信号的评分层,用于检测幻觉内容。

  4. 提供了完整的Python代码实现,并附有实际测试数据。

  5. 适用于需要自动决策的LLM管道,如RAG系统和多轮对话机器人。

  6. 现有的LLM评估系统存在严重缺陷,需引入决策层以确保输出质量。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • LLM评估系统缺陷
    • 现有问题
      • 依赖直觉判断
      • 无法识别自信但错误的响应
    • 解决方案
      • 可信度与具体性评分
      • 决策层设计
    • 实现细节
      • Python代码实现
      • 实际测试数据

金句 / Highlights

值得收藏与分享的关键句。

  • 现实中的问题不是模型产生幻觉,而是没有东西能捕捉到那些自信但错误的响应,这些响应得分0.525,超过阈值,却悄悄地是错误的。

    第2段

    ⬇︎ 下载 PNG𝕏 分享到 X
  • 高具体性加上低可信度是幻觉的标志。单个分数每次都会错过这一点。

    第2段

    ⬇︎ 下载 PNG𝕏 分享到 X
  • 完整代码:https://github.com/Emmimal/llm-eval-layer

    第2段

    ⬇︎ 下载 PNG𝕏 分享到 X
#LLM#评估系统#AI
打开原文

内容提要

一个纯 Python 的完整实现,附带真实的基准测试数据。

大多数团队通过阅读和猜测来评估 LLM 的回复。一旦规模扩大,这种方法就会失效。

真正的问题不在于模型会产生幻觉,而在于没有任何机制能捕捉那些自信的错误回复——那些得分 0.525、通过阈值却悄无声息出错的回答。

我构建了一个评分层,将忠实度拆分为两个信号:归因性和具体性。高具体性加低归因性正是幻觉的特征。单一评分永远无法捕捉到这一点。

这不是一个评估脚本。这是一个位于模型和用户之间的决策引擎。

我改了提示词中的一行。全盘崩溃。

三个词让我的评估系统崩溃:_“要具体且详细。”_

某个周二下午,我把这三个词加进了系统提示词。常规改动。在调试 RAG 流水线时,这种改动你可能会做十几次。一小时后我运行了下一批测试,第三个问题的回复是这样的:

_“语境工程于 1987 年在 MIT 发明,主要用于 CPU 的硬件缓存优化。它与语言模型无关。”_

我的评分器给了它 0.525 分。高于我 0.5 的通过阈值。绿灯。

我差点就漏掉了它。我当时正像盯着测试结果看了两小时后那样快速浏览输出,检查分数,而不是逐句阅读。我之所以能发现它,唯一的原因是“1987”这个年份看起来不对劲。我读了两遍,然后调出了上下文文档。模型编造了那个句子中的每一个具体细节。

分数上升是因为回复变得更具体了。质量崩溃是因为模型对自己编造的东西更加自信。我的评估层用一个数字来涵盖这两个方向,但它无法区分它们。

那次我是手动发现的。那不是流程。那是运气。而评估系统的全部意义就在于,它不应该依赖于你是否在某个下午碰巧仔细阅读。

但当你试图真正修复它时,事情就变得复杂了。比如,你究竟如何定义“好”?如果你只是让另一个 LLM 来评判第一个,你只是把问题上移了一层。真正的危险不是错误的回复;而是那些听起来像专家却在悄无声息地对你说谎的回复。

大多数教程告诉你就调用模型然后看看输出是否“看起来正确”。但看看这些数字。当你的回复总体得分 0.525,技术上可接受,但其基础得分是 0.428,具体性得分是 0.701 时,会发生什么?这种组合意味着自信但无根据。这不是一个临界回复。这是一个穿着商务装的幻觉。

这些不是罕见的边缘情况。这是生产环境 LLM 系统中的默认情况,而你无法通过感觉检查来捕捉它。

答案在于一个大多数团队完全跳过的缺失层。在 LLM 输出和用户交付之间,存在一个刻意的步骤:决定回复是应该被提供、重试还是重新生成。我构建了那层。这就是那个系统,附带真实的数字和可运行的代码。

完整代码:https://github.com/Emmimal/llm-eval-layer

适用对象

这种架构在以下情况中很有用:当你构建 RAG 系统时 [1],错误答案很容易混入;或者构建处理多轮对话且需要随时间检查回复的聊天机器人。它同样适用于任何需要自动决定下一步操作的 LLM 流水线,比如是向用户显示回复、重试还是生成新回复。

对于没有生产流量的单轮演示可以跳过。如果每个回复无论如何都会经过人工审核,那么这种开销就不值得。同样,如果你的领域只有一个正确答案且精确匹配就足够,那也不需要。

为什么 LLM 评估是失效的

大多数评估系统以三种方式失效,而且通常在有人注意到之前就发生了。

“看起来正确”并不总是正确。 一个回复可能听起来流利、结构良好、显得自信,但仍然完全错误。流利度不能保证真实性。当你快速审查输出时,你的大脑通常评估的是写作质量,而不是准确性。你必须积极对抗这种本能,而大多数人没有。

真正重要的幻觉不是你能轻易发现的那些。 没有人会发布一个说埃菲尔铁塔在柏林的模型。那种问题第一天就会被发现。危险的是那些自信的、领域特定的主张,对于非该领域专家的人来说听起来是对的 [10]。它们通过审查而不被注意,进入生产环境,并最终呈现在用户面前。

更深层次的问题是,分数不是决策。 你设定了 0.5 的阈值。一个回复得 0.51 分,通过。另一个得 0.95 分,也通过。你同等对待它们。但其中一个很可能需要人工审核。它们给你一个数字,而你真正需要的是:发布这个、标记这个或拒绝这个。

分数上升了。质量崩溃了。一个数字无法同时承载两个方向。

传统的指标如 BLEU 和 ROUGE 在这里效果不佳 [2, 3]。它们检查有多少词与参考答案匹配,这在机器翻译中是有道理的,因为通常只有一个正确的输出。但 LLM 的回复没有单一的正确版本。表达同一件事有很多种方式。所以将 BLEU 用于对话是具有误导性的。这就像只通过检查有多少词与标准答案匹配来给论文评分,而不是判断观点是否真正正确且解释得当。

如今大家都在转向使用 LLM 即评判员的方法 [4]。这种方法利用 GPT-4 这样的模型来评估另一个 GPT-4 模型的输出。它确实比 BLEU 有所改进,但也带来了问题:成本高昂、每次结果可能略有不同,并且让你依赖于另一个无法完全控制的模型。在生产系统中对每个响应进行评分时,这种方法也无法扩展。

像 RAGAS [6] 这样的框架推动了这一进程,但它们仍然依赖 LLM 评判员进行评分,并且在多次运行中无法保证结果的一致性。实际上,你需要的是一个能在本地运行、没有单次调用成本、且每次都能产生一致结果的评分层。

真实评估系统的需求

在编写任何代码之前,我设定了五个硬性约束。它必须在毫秒内完成,因为拖慢用户响应速度的评估层是无法部署的。标准流程中不能有 API 调用。LLM 评判员是备用方案而非默认选项,因为按评估调用付费无法扩展。并且相同的输入每次必须得到相同的评分,否则回归测试就完全失去了意义。

另外两个约束关乎可解释性。每个拒绝都必须附带清晰的英文理由,而不仅仅是一个数字,因为“得分:0.43”无法告诉你具体需要修复什么。添加新的评分器时不应涉及修改决策逻辑,否则系统会随时间逐渐腐化。

系统架构

架构分为三层,每层承担特定职责。

图片 1:AI 响应评估流程示意图。顶层工作流包括查询、上下文、LLM 和响应,输入至蓝色评分层,评估归因度和一致性等指标。流程随后分流至黄色决策层(接受/审核/拒绝)和绿色执行层(提供服务/重试/重新生成)

LLM 评估架构:多层流水线示意图,展示如何对生成的 AI 响应进行质量评分,并通过自动化决策层和执行层确保输出内容有据可依。图片由作者提供

评分层负责生成数值,决策层将这些数值转化为带有完整解释的判定结果。后者是大多数系统缺失的部分,却是在生产环境中响应出现问题时最实用的功能——当你不知道故障原因时,它能提供关键线索。

核心评估维度

忠实度:归因性与具体性

这是最重要的评分维度,也是我最初几乎理解错误的部分。

起初我使用单一的“忠实度”评分,混合了语义相似度和上下文与响应间的词汇重叠等指标。这种方法在简单场景中有效,但在关键场景中会失效。

核心问题在于:有些答案听起来自信详尽,却并非基于给定上下文。

因此我将忠实度拆分为两个独立检查。

归因性检查答案是否由上下文支撑。如果响应中的主张无法从输入中找到或推断出,则归因性得分较低 [8]。

code
# 归因性:是否基于事实?

semantic    = semantic_similarity(context, response)
overlap     = token_overlap(context, response)
attribution = 0.60 * semantic + 0.40 * overlap

具体性检查答案的详细程度和具体性。当响应提供清晰细节并避免使用“这在许多场景中都有用”等模糊表述时,具体性得分较高。

code
# 具体性:是否明确具体?

length_score  = min(1.0, len(tokens) / 80)
richness      = len(set(tokens)) / len(tokens)
hedge_penalty = min(0.60, hedge_count * 0.15)
specificity   = (0.40 * length_score + 0.60 * richness) - hedge_penalty

# 复合评分

faithfulness = 0.70 * attribution + 0.30 * specificity

关键洞察:高具体性配合低归因性等于幻觉产生。

图片 2:基于高/低具体性与高/低归因性的 AI 响应评估矩阵图。将输出分类为弱答案、幻觉、有据但单薄、优质答案四个象限

AI 响应质量矩阵:通过事实依据(归因性)与细节精度(具体性)的交叉评估,决定是否接受、拒绝或审核模型输出。图片由作者提供

这种情况非常危险,因为自信详尽的错误答案更难被发现。模糊答案至少展现了不确定性,而自信却无根据的答案则不会。

归因性是主要信号,因为事实依据最重要。具体性作为辅助,主要用于捕捉自信但错误的答案。

以下是一个实际案例。某响应声称上下文工程“于 1987 年在 MIT 发明,主要用于硬件缓存优化”:

code
归因性:0.428(低,与上下文关联弱)
具体性:0.701(高,听起来详细权威)
决策:拒绝
原因:检测到自信型幻觉

若使用单一阈值(如 0.5)的评分系统可能仍会放过此类问题。通过分离归因性和具体性,不仅能显示分数,还能揭示响应失败的深层原因。

答案相关性

该维度衡量响应与原始问题的直接关联程度。

评分器综合三个信号:完整响应与查询的语义相似度、响应中最佳匹配单句的相似度,以及简单的词汇重叠度 [5, 6]。

code
semantic  = semantic_similarity(query, response)
max_sent  = max_sentence_similarity(query, response)
overlap   = token_overlap(query, response)

relevance = 0.45 * semantic + 0.35 * max_sent + 0.20 * overlap

句子级组件奖励聚焦答案的回答。即使回答很长或包含额外信息,只要至少有一个句子直接回答了问题,它仍然可以获得高分。

上下文质量:精确率与召回率

上下文精确率回答一个简单问题:模型是在凭空捏造,还是严格遵循上下文?[7] 如果精确率低,说明回答包含了检索上下文从未支持的主张。模型脱离了既定脚本。

上下文召回率则从相反角度考量。它检查检索到的内容有多少实际出现在回答中。低召回率意味着检索获取的文档大部分被模型忽略了。你获取了大量噪声信息。

code
prec = precision(context, response)   # 上下文 -> 回答覆盖度
rec  = recall(response, context)      # 回答 -> 上下文锚定度
f1   = 2 * prec * rec / (prec + rec)

context_quality = 0.50 * f1 + 0.50 * semantic_similarity(context, response)

上下文质量具有因果主动性,而非被动监测。当质量低于阈值时,系统不仅会标记问题,还会改变后续操作。

code
if context_quality < 0.40 and final_score < 0.65:
    action = "retrieve_more_documents"
    reason = "Root cause is retrieval, not the model"

由检索质量差导致的糟糕回答需要更好的文档支持,而非优化提示词。大多数评估系统无法区分这一点,最终会让你花一小时调试错误的方向。

分歧信号

在调试一个棘手边界案例后,我开始密切关注方差问题。日志显示可信度得分为0.68,相关性为0.32,上下文质量为0.71

如果仅对这些数字进行加权平均,最终得分看起来完全可接受。它能通过流程管道。但原始数据却对同一回答呈现出三种截然不同的叙事:一个指标说它准确,另一个说它不相关,第三个说上下文质量尚可。

求平均值完全掩盖了这种冲突。实际需要追踪的是分歧信号。

通过计算所有维度得分的标准差即可立即发现:

code
def _disagreement(scores: list[float]) -> float:
    n = len(scores)
    if n < 2:
        return 0.0           
    mean = sum(scores) / n
    return round(math.sqrt(sum((s - mean) ** 2 for s in scores) / n), 4)

当标准差超过0.12时,系统会直接将回答路由至人工审核队列,完全忽略最终平均值。

如果评分器指向完全不同的方向,说明系统存在根本性不确定。这种摩擦是自动化达到极限的最佳指示,需要人工介入。

不过这个分歧指标不仅触发审核,还会直接馈入置信度计算,这就引出了下一步。

评分引擎:混合架构设计

完整管道运行包含三个步骤。

步骤1:启发式评分

所有四个评估维度均在本地计算。系统完全避免外部API调用。通过将sentence-transformers直接加载到CPU,本阶段耗时约3毫秒。

步骤2:置信度门控

当得分介于0.45-0.65区间时,系统会启动特殊机制。此时不再单独信任启发式评分,而是升级至LLM法官评估。在此区间外,本地评分足够可靠,无需调用API。

步骤3:决策层

图3:AI回答评估管道的纵向流程图。展示了从数据输入到最终拒绝决策的完整流程,基于可信度、相关性、上下文和特异性指标。

AI评估管道:逐步逻辑流展示如何通过指标阈值识别幻觉并触发自动拒绝和重新生成。作者供图

原始浮点数不会直接输出到日志。管道返回的是完整架构:接受审核拒绝,附带故障类型、原因和具体后续操作。LLM法官默认不运行,仅在启发式评分真正无法决策时触发。

决策层:从评分到行动

大多数评估工具试图回答一个基本问题:“这个回答是否合格?”

本系统彻底改变了问题范式:“我们应该如何处理这个回答?”

底层决策逻辑是三维策略,直接基于锚定度、特异性和一致性指标运行。它不依赖单一平均值,而是通过显式编程规则隔离故障:

code
# 确认幻觉:归因度极低且回答模糊
if attribution < 0.35 and specificity <= 0.50:
    return REVIEW, "vague response, retry with specific prompt"

# 确认幻觉:归因度低但回答显得自信
if attribution < 0.35 and specificity > 0.50:
    return REJECT, "confident hallucination"

# 自信幻觉:听起来权威但缺乏依据
if attribution < 0.45 and specificity > 0.60:
    return REJECT, "confident hallucination detected"

# 检索质量差:检索过程本身是根本原因
if context_quality < 0.40:
    return REVIEW, "retrieve_more_documents"

# 严格防护:归因度和上下文质量均薄弱
# 两个弱信号叠加比单个强故障更严重
if attribution < 0.55 and context_quality < 0.50:
    return REJECT, "hallucination guardrail triggered"

# 弱锚定
if attribution < 0.55:
    return REVIEW, "weak grounding, retry with specific prompt"
markdown
# 偏离主题:回答完全未回应查询
if relevance_score < 0.30:
    return REVIEW, "偏离主题,请用更清晰的查询重试"

# 高度分歧
if disagreement > 0.12:
    return REVIEW, "评分不确定,建议人工审核"

# 质量临界
if final_score < 0.65:
    return REVIEW, "临界质量,可选人工审核"

# 所有关卡均成功通过
return ACCEPT, "serve_response"

你不能用同样的方式处理所有糟糕的输出。模糊的回答(低归因度、低具体性)只需重写,因此会进入 REVIEW 状态并附带提示重试。而自信的幻觉(低归因度、高具体性)则很危险,会立即被标记为 REJECT 并强制重新生成。不同的失败需要不同的后续处理。

输出示例展示

以下是运行 main.py 处理四个案例的实际输出。

示例 1:基础扎实的回答

code
最终评分       : 0.680
归因度         : 0.684   (基础扎实度)
具体性         : 0.713   (具体程度)
相关性         : 0.657
上下文质量     : 0.688
分歧度         : 0.016   (评分者标准差)
无幻觉
决策          : ACCEPT  (置信度: 41%)
原因          : 所有质量关卡均已通过
后续操作      : serve_response
延迟          : 322ms

示例 2:自信的幻觉

code
最终评分       : 0.525
归因度         : 0.428   (基础扎实度)
具体性         : 0.701   (具体程度)
相关性         : 0.613
上下文质量     : 0.424
分歧度         : 0.077   (评分者标准差)
疑似基础薄弱
失败类型      : 幻觉
决策          : REJECT  (置信度: 22%)
原因          : 检测到自信幻觉,归因度=0.428
                    (基础薄弱) 但具体性=0.701 (高置信度)。
                    回答听起来权威但未基于上下文。
后续操作      : regenerate_with_grounding_prompt
原因说明      : 自信但无依据的回答比模糊回答更危险
低置信度句子:
  这与语言模型毫无关系。

这个案例完美展示了为什么仅依赖原始评分会失败。如果只看最终评分 0.525,它安全地超过了标准的 0.5 通过阈值。基础指标流水线会让其通过。但决策层捕获并标记了它:归因度评分 0.428 加上具体性评分 0.701 正是自信幻觉的特征。

示例 3:模糊回答

code
最终评分       : 0.295
归因度         : 0.248   (基础扎实度)
具体性         : 0.332   (具体程度)
决策          : REVIEW  (置信度: 32%)
原因          : 不确定/模糊回答,基础薄弱,具体性低。
                    非确认的幻觉。
后续操作      : retry_with_specific_prompt

不要将模棱两可的回答误认为幻觉。低归因度加上低具体性表明模型只是在回避问题。如果强制重新生成,只会得到更多空洞内容。实际解决方案是使用更具限制性的提示模板触发重试。

示例 4:偏离主题的回答

code
最终评分       : 0.080
归因度         : 0.017   (基础扎实度)
具体性         : 0.630   (具体程度)
决策          : REJECT  (置信度: 42%)
原因          : 自信幻觉,归因度=0.017,
                    具体性=0.630。回答听起来权威但属虚构。
低置信度句子:
  法国大革命是一段重大政治和社会变革的时期...
  玛丽·安托瓦内特当时是法国王后。

归因度 0.017 加上具体性 0.630 意味着模型在回答一个关于上下文工程的提问时返回了关于法国大革命的论述。系统立即捕获了这一点,但并非盲目拒绝。它精确定位并暴露了触发低置信度标志的具体句子。

决策分布

code
ACCEPT      1/4  (25%)
REVIEW      1/4  (25%)
REJECT      2/4  (50%)

如果在生产环境中持续追踪这一指标分布,你可以立即发现模型权重是否退化、检索流水线是否丢失相关文档,或提示模板是否失效。这才是真正的系统可观测性,而非仅仅将无用的字符串转储到日志聚合器中。

真实基准测试数据

在完整的 5 案例 RAG 评估集上运行:

ID标签归因度相关性上下文最终评分幻觉决策 q_001 良好回答 0.686 0.680 0.725 0.694 无 ACCEPT q_002 幻觉回答 0.445 0.621 0.459 0.547 疑似 REJECT q_003 良好回答 0.528 0.456 0.535 0.534 疑似 REVIEW q_004 偏离上下文回答 0.043 0.682 0.091 0.337 确认 REJECT q_005 良好回答 0.625 0.341 0.628 0.536 无 REVIEW

决策,而非分数,才是真相之源。这些结果仅为示意——五个案例并非统计显著样本,在信任任何阈值前,应在自己的标注数据上运行此测试。

准确度基准

让我们看看实际的准确度基准。良好输出的平均分为 0.588,而糟糕输出则骤降至 0.442。这 0.146 的分数差距足够大,让我们可以设定严格可靠的边界。此外,在运行期间完美标记了 2/2 的幻觉案例。你可以在不牺牲运行时预算的情况下获得完整的检测覆盖。

延迟基准(10 次运行,预热模型)

操作延迟备注 归因评分器~1.2ms 嵌入加重叠计算 相关性评分器~1.1ms 句子级评分 上下文评分器~0.8ms 精确率加召回率 决策层~0.1ms 策略规则加置信度 完整流水线.evaluate()~291ms 平均值 无 LLM 调用 含 LLM 评判器~340ms 仅处理边缘案例,0.45 至 0.65 区间

code

首次运行时由于需要加载 `sentence-transformers` 模型,会产生约 800-1000ms 的瓶颈。初始加载完成后,处理速度将大幅提升,平均每次调用耗时约 `291ms`。如果在应用容器启动时预加载模型权重,就可以在生产环境中运行整个评估层,同时将响应延迟增加控制在 `300ms` 以内。

## 回归测试系统

大多数团队会跳过这个环节——这是个错误。如果生成评估分数后不采取行动,那将毫无意义。当你调整提示模板导致准确率下降时,需要立即收到警报;当你更换检索策略导致原本通过的三个边界用例完全失效时,必须在推送至主干前发现问题。回归测试套件通过存储历史基线并在 CI 构建过程中对比当前分数来解决这个问题。

suite = RegressionSuite("data/baselines.json")

系统验证完成后记录基线

suite.record_baseline("q_001", query, context, response, result)

修改提示或模型后:

report = suite.run_regression(pipeline, test_cases)

将失败视为 CI 失败

if report.failed > 0: raise SystemExit("检测到质量回归,已阻断部署")

code

当提示词修改引发性能回归时,终端会输出如下信息:

回归报告 -- CI/CD 质量门禁 检测到 3 个回归问题 -- 部署已阻断

总用例数 : 3 通过数 : 0 失败数 : 3 平均差值 : -0.4586 阈值 : +/- 0.05

回归项 -- 分数超出阈值下降: [q_001] 0.694 -> 0.137 (差值 -0.556) [q_002] 0.547 -> 0.137 (差值 -0.410) [q_003] 0.534 -> 0.124 (差值 -0.410)

code

简单的提示词修改使得可靠响应从 `0.694` 跌至 `0.137`。回归流水线会捕获这个问题,在用户受到影响前终止部署。

这将标准 CI/CD 实践引入了生成式 AI 领域。不再需要人工抽查。如果质量跌破阈值,构建就会失败。它将提示工程视为与代码覆盖率或单元测试同等重要的环节[11]。

## 从指标到决策再到行动

这个系统实现了完整的转型:

旧思维: 分数 = 0.68

发布吗?应该没问题

新系统: 信号 -> 推理 -> 决策 -> 行动

code

我们将每个输出都纳入可预测的架构中。你会获得明确决策(通过/审核/拒绝)、记录原因、故障类型、路由操作和置信度百分比。这种结构化负载是系统在出现故障时真正可调试的唯一原因。

每个结果的 to_dict() 方法可生成适用于日志记录、仪表板和 API 的 JSON 序列化数据:

result.to_dict()

{

"decision": "拒绝",

"confidence_pct": 22,

"failure_type": "幻觉",

"hallucination_status": "疑似",

"next_action": "使用基础提示重新生成",

"action_why": "自信但无依据的回答比模糊回答更危险",

"scores": {

"final": 0.525,

"attribution": 0.428,

"specificity": 0.701,

"relevance": 0.613,

"context_quality": 0.424,

"disagreement": 0.077

},

"explanations": {

"reason": "检测到自信幻觉...",

"low_confidence_sentences": ["这与语言模型毫无关系"]

},

"meta": {

"passed": false,

"used_llm_judge": false,

"latency_ms": 301.0

}

}

code

将其接入任何日志系统,就能为系统生成的每个响应建立完整的质量审计追踪。

## 坦诚的设计决策

`0.146` 的分数分离度对于本地启发式系统完全正常。优质和劣质响应总会在中间区域相互交融。决策层通过观察归因性和特异性如何相互作用来解决这个问题,而不是单纯依赖单一的平均数值。试图通过调整权重来强制扩大分离度,只会扭曲基准测试结果,而不会改变代码在生产环境中的实际运行效果。

`0.70/0.30` 和 `0.60/0.40` 的权重配置并非基于某种通用理论。我通过反复测试直到这些数值适配我的知识库数据。如果你在法律合同、医学期刊或原始源代码上运行相同设置,这些比例将会失效。这就是为什么我将它们隔离在 `configs` 目录中。你可以根据特定数据调整调优参数,而无需修改核心流水线代码。

`0.35` 的幻觉阈值仅在归因性完全触底时触发。如果你的应用领域依赖重度释义而不要求精确词汇匹配,这个严格阈值可能产生误报。使用 sentence-transformers[9] 处理语义理解远优于基础的 TF-IDF 匹配。如果禁用该功能并降级到本地回退模式,流水线会自动转为更保守的状态以保护数据。[5]

`0.45` 到 `0.65` 的 LLM 评判区间与默认阈值直接关联。如果你调整 `REJECT_THRESHOLD` 或 `REVIEW_THRESHOLD`,需要重新映射评判窗口以保持匹配。该架构遵循严格模式:仅当本地启发式方法遇到不确定性瓶颈时才启动昂贵的 LLM 评判器,绝不将其作为默认守门员。

低置信度分数——比如边界输出显示的 `22%` 或 `42%`——并非系统缺陷。这些响应确实存在波动性。在不可靠输入上运行过度自信的评估流水线是巨大的生产隐患;你需要的是一个能准确量化自身不确定性的系统。

另外,无需担心 `sentence-transformers` 启动时出现的 `embeddings.position_ids` 警告。这纯粹是表面提示,对运行时性能零影响。

## 未解决的问题

最棘手的情况是隐性幻觉。如果回答复用了你的上下文词汇,却悄无声息地改变了含义,底层代码就会被欺骗,因为原始词语仍然匹配。启发式方法对这种语义漂移是盲区。这正是设置LLM评判备选方案的根本原因。

跨文档一致性同样不在考量范围内。评分器会孤立地根据各自上下文评估每个回答。如果两个相关回答相互矛盾,这里的机制无法捕捉到。而且校准过程确实具有领域特异性——请将 configs/thresholds.yaml 视为起点,在你自己标注的案例上运行,并在信任本文列出的任何数值前进行调优。医疗问答系统需要的幻觉阈值必须比我使用的严格得多。

## 实际构建的成果

完成所有这些构建后,你得到的并非一个评估脚本。

系统接收三个输入:查询、上下文和回答。输出则是包含决策依据、日志原因、错误类型、后续操作、置信度分数及底层数据细目的严格数据包。

每个触及系统的回答都会经历评分、分类和路由。优质回答直通用户,模糊回答会通过更严格的提示词重试,幻觉回答在任何人看到前就被拦截。当你修改提示词后,若曾经得分0.69的三个案例突然变成0.13,回归测试套件会在你推送主分支前捕获异常——而非等待用户上报后。

这是当前海量LlamaIndex演示、LangChain示例和基础RAG教程中缺失的关键层。人人都展示如何连接向量数据库,却无人教你如何安全验证模型输出。

RAG确保获取正确文档,提示工程确保传达正确指令,而这一层确保对输出内容做出正确决策。

> 完整源代码、基准测试数据及本地实现脚本可在此获取:**[https://github.com/Emmimal/llm-eval-layer](https://github.com/Emmimal/llm-eval-layer)** 

## 参考文献

[1] Lewis, P.等人 (2020). 《面向知识密集型NLP任务的检索增强生成》. 神经信息处理系统进展, 33, 9459-9474. [https://arxiv.org/abs/2005.11401](https://arxiv.org/abs/2005.11401)

[2] Papineni, K.等人 (2002). 《BLEU:机器翻译自动评估方法》. 第40届计算语言学协会年会论文集, 311-318. [https://aclanthology.org/P02-1040/](https://aclanthology.org/P02-1040/)

[3] Lin, C.-Y. (2004). 《ROUGE:摘要自动评估工具包》. 文本摘要衍生研究, 74-81. [https://aclanthology.org/W04-1013/](https://aclanthology.org/W04-1013/)

[4] Zheng, L.等人 (2023). 《用MT-Bench和Chatbot竞技场评判LLM即裁判》. arXiv预印本 arXiv:2306.05685. [https://arxiv.org/abs/2306.05685](https://arxiv.org/abs/2306.05685)

[5] Reimers, N.与Gurevych, I. (2019). 《Sentence-BERT:使用连体BERT网络的句子嵌入》. 2019年自然语言处理经验方法会议论文集, 3982-3992. [https://arxiv.org/abs/1908.10084](https://arxiv.org/abs/1908.10084)

[6] Es, S.等人 (2023). 《RAGAS:检索增强生成的自动化评估》. arXiv预印本 arXiv:2309.15217. [https://arxiv.org/abs/2309.15217](https://arxiv.org/abs/2309.15217)

[7] Manning, C. D., Raghavan, P., 与Schutze, H. (2008). 《信息检索导论》. 剑桥大学出版社. [https://nlp.stanford.edu/IR-book/](https://nlp.stanford.edu/IR-book/)

[8] Devlin, J.等人 (2019). 《BERT:用于语言理解的深度双向Transformer预训练》. NAACL-HLT 2019会议论文集, 4171–4186. [https://arxiv.org/abs/1810.04805](https://arxiv.org/abs/1810.04805)

[9] Wang, W.等人 (2020). 《MiniLM:面向任务无关的预训练Transformer压缩的深度自注意力蒸馏》. 神经信息处理系统进展, 33, 5776–5788. [https://arxiv.org/abs/2002.10957](https://arxiv.org/abs/2002.10957)

[10] Tonmoy, S. M.等人 (2024). 《大语言模型幻觉缓解技术全面综述》. arXiv预印本 arXiv:2401.01313. [https://arxiv.org/abs/2401.01313](https://arxiv.org/abs/2401.01313)

[11] Breck, E.等人 (2017). 《机器学习测试评分:ML生产就绪度与技术债务削减量规》. IEEE大数据2017会议, 1123–1132. [https://doi.org/10.1109/BigData.2017.8258038](https://doi.org/10.1109/BigData.2017.8258038)

## 声明

本文所有代码均由本人原创编写,基于Python 3.12.6开发测试。基准数据来自本地机器(Windows 11,仅使用CPU)实际运行结果,可通过克隆代码库运行main.py、experiments/rag_eval_demo.py和experiments/benchmarks.py复现。sentence-transformers库作为可选依赖项用于归因和相关性评分中的语义嵌入。未安装时系统将回退至TF-IDF向量并发出警告,所有功能保持正常运行。评分公式、决策逻辑、幻觉检测规则及回归系统均为独立实现,未衍生自任何引用代码库。本人与文中提及的任何工具、库或公司无经济利益关系。

AI 可能会生成不准确的信息,请核实重要内容