核心摘要

LLM 幻觉检测本质上是证据问题,不是文风判断。 生产系统应把回答拆成原子声明,在已授权且版本固定的证据快照上逐条判定,再决定发布、修订、拒答或升级人工复核。证据不足不等于错误,表达一致、语气自信或格式正确也不等于事实正确。

目录

核心要点

  • 评估原子声明,不要用一个不透明的答案级幻觉分数覆盖所有错误。
  • 为每次判定固定语料库、版本、权限范围、新鲜度规则和引用锚点。
  • 使用四种判定:supportedcontradictedinsufficient_evidencenot_applicable
  • 一致性、模型置信度、低温度和合法 JSON 都只是信号或控制,不是真值保证。
  • 分开评估检索、证据质量、生成忠实度、引用、拒答和任务成功。
  • 事实判定器不得授权支付、删除、发消息等外部副作用。

什么是 LLM 幻觉

LLM 幻觉是生成模型以看似确定的方式陈述错误或虚假内容。NIST AI 600-1 使用 Confabulation 描述这类会误导用户的风险。但工程上还必须声明边界:相对于哪个来源、版本、时间、司法辖区或任务契约,它是错的?

语言流畅度不属于真值测试。犹豫的句子可能正确,带完整引用的漂亮回答也可能错误。生产系统不应把以下情况压成一个标签:

判定 含义 正确动作
支持 supported 声明可由指定证据推出 其他门禁通过后可发布
矛盾 contradicted 证据支持与声明不兼容的结论 修订或阻断
证据不足 insufficient_evidence 当前快照无法证明任何一方 补充检索、拒答或复核
不适用 not_applicable 观点、指令、问候等非事实内容 不进入事实性指标分母

“不受支持”和“被证据反驳”不是一回事。语料库可能覆盖不足,问题可能超出范围,事实也可能在快照后发生变化。把所有未验证声明都判成错误,会同时污染评测数据与产品行为。

相邻故障不等于幻觉

指令偏移、算术错误、不安全建议、偏见和策略拒绝都可能与幻觉同时出现,但需要独立测试。回答可能事实正确却违反策略,也可能完全忠于输入证据,但证据本身已经过期。

应至少区分两个事实性轴:

  • 回答正确性:声明是否符合任务规定的外部真值标准。
  • 回答忠实度:声明是否能由提供给模型的证据推出。

对旧政策的准确总结具有忠实度,却不具备当前正确性。反过来,在封闭证据任务中,一个碰巧正确但不在授权证据内的答案仍违反支持范围。

先定义真值与证据边界

只有任务契约明确了证据范围和有效时间,幻觉测试才可复现。生成回答前应记录:

yaml
task:
  id: refund-policy-qa
  truthMode: closed-evidence
  asOf: 2026-08-10T09:00:00Z
  materialClaims: [eligibility, deadline, fee]

evidenceSnapshot:
  corpusId: support-policy
  revision: sha256:8c1f...
  authorizedTenant: tenant-42
  sourceAuthority: approved-policy
  freshnessRule: effective_at <= asOf < superseded_at
  citationUnit: source-id-and-section

failurePolicy:
  contradicted: block
  insufficientMaterialClaim: abstain
  invalidCitation: block
  reviewerRequiredFor: [legal-exception]

这份契约可以阻止验证器悄悄搜索另一张网页、更新版本文档或其他租户的数据。它也让争议可以定位:生成器、检索器、证据集、判定器和发布策略都有独立身份。

证据必须保留血缘

保存规范来源 ID、来源版本、权威级别、有效区间、访问决策、召回片段和检索轨迹。Embedding、摘要、图谱边和重排分数都是派生辅助信息,不能替代原始来源边界。

来源冲突时,不要平均成一个高置信度答案。系统应执行明确的权威级别与时效策略,必要时向用户披露冲突或升级复核。

建立声明证据决策流水线

可靠的最小评估单位是原子事实声明。FActScore 展示了长回答拆成原子事实的价值:同一段文字里可能同时存在受支持和不受支持的内容。

flowchart LR A["任务契约"] --> B["模型回答"] B --> C["原子声明提取"] C --> D["授权证据检索"] D --> E["声明与证据判定"] E --> F["确定性策略"] F --> G["发布"] F --> H["修订"] F --> I["拒答"] F --> J["合格人员复核"]

1. 提取原子声明

拆开复合句,让每条声明只接收一个判定。“退货期限是 30 天且免退货运费”至少包含两条声明。保留声明在原回答中的字符偏移,便于修订与审计。

声明提取器本身也会漏掉重要事实,或把带限定词的表达改成绝对结论。应在人标回答上检查提取召回率,重点覆盖数字、否定、时间限定和引用。

2. 按权限检索证据

先执行租户和文档授权,再进行排名。检索结果应携带稳定来源锚点和版本,而不是匿名文本片段。高相似度只表示向量空间接近,不代表来源权威,更不代表证据可以推出声明。

3. 给出有界判定

NLI 模型或 LLM Judge 可以提出判定,但必须输出类型化字段与证据 ID。使用人工标签校准它,检查位置与冗长偏差,并保留 insufficient_evidence 路径。绝不能用 if "支持" in response 之类的自由文本子串解析。

json
{
  "claimId": "claim-3",
  "claim": "退款期限是 30 天。",
  "material": true,
  "evidenceIds": ["returns-policy-v7#window"],
  "evidenceRevision": "returns-policy-v7",
  "verdict": "contradicted",
  "reasonCode": "VALUE_MISMATCH",
  "judgeVersion": "claim-judge-4",
  "reviewRequired": true
}

4. 按业务损失聚合

不要给“无法验证”统一设置半个错误的权重。被证据反驳的药物剂量应直接阻断发布,不受支持的可选轶事则可以删除。最终动作应由声明重要性和任务损失函数决定。

实现确定性发布策略

下面的无第三方依赖 Python fixture 验证类型化声明结果,并在不信任模型解释或自报置信度的情况下做发布决策:

python
from dataclasses import dataclass
from enum import Enum
from typing import Iterable


class Verdict(str, Enum):
    SUPPORTED = "supported"
    CONTRADICTED = "contradicted"
    INSUFFICIENT = "insufficient_evidence"
    NOT_APPLICABLE = "not_applicable"


@dataclass(frozen=True)
class ClaimResult:
    claim_id: str
    verdict: Verdict
    material: bool
    evidence_ids: tuple[str, ...] = ()
    citations_valid: bool = True


def release_decision(results: Iterable[ClaimResult]) -> str:
    claims = list(results)
    if not claims:
        return "review"

    if any(not claim.citations_valid for claim in claims):
        return "block"

    factual = [
        claim for claim in claims
        if claim.verdict is not Verdict.NOT_APPLICABLE
    ]
    if not factual:
        return "release"

    if any(
        claim.material and claim.verdict is Verdict.CONTRADICTED
        for claim in factual
    ):
        return "block"

    if any(
        claim.material and claim.verdict is Verdict.INSUFFICIENT
        for claim in factual
    ):
        return "abstain"

    if any(claim.verdict is Verdict.CONTRADICTED for claim in factual):
        return "revise"

    if any(claim.verdict is Verdict.INSUFFICIENT for claim in factual):
        return "revise"

    if any(
        claim.verdict is Verdict.SUPPORTED and not claim.evidence_ids
        for claim in factual
    ):
        return "review"

    return "release"


fixture = [
    ClaimResult(
        claim_id="refund-window",
        verdict=Verdict.SUPPORTED,
        material=True,
        evidence_ids=("returns-policy-v7#window",),
    ),
    ClaimResult(
        claim_id="return-fee",
        verdict=Verdict.INSUFFICIENT,
        material=True,
    ),
]

assert release_decision(fixture) == "abstain"
print(release_decision(fixture))
# 输出:abstain

这个策略刻意保守,但不是通用模板。创意写作产品可以把大部分内容标为 not_applicable;医疗或法律流程则需要更严格的证据、更窄的自动化范围和合格人员复核。策略应有版本,并像应用代码一样接受测试。

为什么 RAG 仍会产生幻觉

检索增强生成可以提供最新、私有且可引用的证据,但检索本身不是事实证明。原始 RAG 论文 在其知识密集型测试任务中报告了改进,不能据此推导任意生产 RAG 都会消除幻觉。

应把 RAG 看成一组可能失败的阶段:

阶段 失败模式 诊断指标
语料库 来源错误、过时、重复或未授权 权威度、时效、重复率、越权率
解析与切分 证据被拆断或引用边界丢失 证据片段覆盖、血缘完整性
检索 所需证据未进入候选集 固定 Token 预算下的 Evidence Recall@k
排名 正确证据被埋没 nDCG、倒数排名、Top-k 覆盖
上下文组装 删除冲突或关键限定词 冲突检测、唯一证据覆盖
生成 模型忽略、歪曲或过度外推证据 回答忠实度、不受支持声明率
引用 引用存在但不支持相邻声明 引用精确率与覆盖率
决策 关键证据缺失仍发布 拒答召回、关键声明逃逸率

实现细节可继续阅读生产级 RAG 评估RAG 幻觉缓解策略

常见控制能证明什么

常见“防幻觉”手段通常只控制一个失败模式,却经常被包装成事实保证。

控制 真正用途 不能证明
降低温度 提高复现性,减少采样变化 事实正确
结构化输出或 JSON Schema 语法、必填字段和类型正确 字段值真实
要求引用的提示词 建立输出契约 引用存在且支持声明
自一致性 在部分任务上发现不稳定回答 真值;多次采样可能共享一个错误
多模型一致 模型失败足够独立时提供分流信号 校准置信度;模型可能共享数据和错误
Token 概率 当前模型下的词元似然 现实世界声明为真的概率
更大或更新的模型 在指定基准上可能表现更好 所有领域和切片的幻觉都更少
人工审核 提供上下文判断与责任主体 在缺少专业能力、证据和工时控制时零错误

SelfCheckGPT 证明多次采样的不一致性可以帮助黑盒检测,但它只能作为信号:一致回答也可能重复同一误解。TruthfulQA 同样显示模型可能复现流行谬误,而且在该论文的测试设置中,扩大模型并未自动提升 truthfulness。

因此,低温度是复现控制。需要稳定输出以便调试或评测时可以使用,但事实性必须独立验证。

如何评估检测与拒答

生产评估必须分开测试检测器、回答和决策策略。允许拒答时,只看准确率会奖励猜测。OpenAI 对语言模型为何产生幻觉的分析指出:若评测只奖励答对,模型猜测可能比承认不确定更有利。

构建版本化评测集

评测集应覆盖:

  • 可回答与刻意不可回答问题;
  • 当前、过时、冲突和缺失证据;
  • 数字、日期、否定、引用与多声明回答;
  • 高影响与低影响声明;
  • 语言、地区、租户、设备和用户权限切片;
  • 检索失败、Prompt Injection、超时和依赖部分失败。

对原子声明标注证据 ID 与裁决说明。记录标注者分歧,不要用多数标签隐藏真正的模糊样本。

指标必须带分母

指标 回答的问题
声明提取召回率 重要事实声明是否都被找到
矛盾精确率与召回率 是否发现被证据反驳的声明且不过度误报
证据不足精确率与召回率 是否识别缺失证明而不把它判成错误
引用精确率 每个引用是否支持相邻声明
引用覆盖率 重要事实声明是否有证据
回答忠实度 回答是否保持在输入证据内
回答正确性 是否符合任务的外部真值标准
拒答精确率 系统拒答时是否确有必要
拒答召回率 需要拒答的样本是否被拒答
选择性风险 系统选择发布的回答中错误率多高
覆盖率 请求中有多少得到回答
任务成功率 用户是否安全完成目标任务

选择性风险必须和覆盖率一起报告。一个系统可以通过拒绝所有请求得到接近零的发布错误率,但产品没有可用性。应绘制风险-覆盖曲线,并根据业务损失选择阈值,而不是复制一个通用分数。

如果使用 LLM-as-Judge 标注声明,应与合格人员标签对比,按切片检查混淆矩阵;模型、Prompt、证据格式或领域变化后必须重新校准。

将事实性与工具授权分离

回答验证器绝不能兼任授权系统。即使一句话有完整证据,也不能证明请求者有权读取记录、发起退款、删除文件或发送消息。

状态改变型工具应执行:

  1. 由确定性策略授权主体、租户、资源和精确动作。
  2. 使用当前系统状态校验类型化参数。
  3. 高影响操作要求审批。
  4. 使用幂等键和持久化操作 ID。
  5. 记录 succeededfailedoutcome_unknown,不能根据模型文本推断成功。
  6. 将事实、策略、安全和执行结果门禁相互独立。

这项分离既能限制错误回答的损害,也能抵御 Prompt Injection。检索文档是证据候选,不是指令,更不是权限。

生产检查清单

  • 声明任务真值模式:开放世界、封闭证据、时间快照或领域权威。
  • 固定模型、Prompt、检索器、语料库、证据快照、Judge 与发布策略版本。
  • 提取原子声明,并审计声明提取召回率。
  • 严格区分 contradictedinsufficient_evidence
  • 保留规范来源锚点、版本、权威级别、权限范围与检索轨迹。
  • 验证引用是否支持相邻声明;引用存在本身不够。
  • 建立明确的修订、拒答与合格人员复核路径。
  • 按风险切片使用人工标签校准自动 Judge。
  • 用关键切片回归阻断发布,不能只看平均分。
  • 同时度量选择性风险、覆盖率、任务成功、延迟和成本。
  • 将工具授权和外部副作用放在事实 Judge 之外。
  • 记录满足隐私要求的证据与决策元数据,用于事故分析。

常见问题

LLM 为什么会产生幻觉

自回归模型优化的是可能的文本续写,不是对当前真值数据库执行事务。训练数据可能稀疏、冲突、过时,也可能包含流行谬误。Prompt 和评测还可能奖励回答而不是拒答。这些机制解释了风险来源,但不能推导一个适用于所有任务的幻觉率。

模型置信度能检测幻觉吗

不能单独使用。Token 概率描述模型内部的词元似然;模型口头声称“90% 确定”也不是校准概率,除非它已在同一任务的标注结果上验证。置信度只能在完成任务级校准并监控漂移后用于分流。

不受支持的声明一定是假的吗

不一定。insufficient_evidence 表示指定快照无法证明它。声明可能在语料库外为真、刚刚发生变化、存在歧义,或与授权来源无关。应补充检索、拒答或复核,不能把缺少证明静默改成矛盾。

两个模型给出相同答案就可信吗

一致性只能作为有边界的信号。模型可能共享训练数据、检索来源、Prompt 和系统性误解,因此错误高度相关。重要声明仍需独立证据验证,并用真实任务检查一致性信号是否校准。

生产环境最好的幻觉指标是什么

不存在单一最佳分数。应联合使用声明级矛盾与证据不足指标、引用精确率与覆盖率、正确性、忠实度、拒答精确率与召回率、选择性风险、覆盖率和端到端任务成功率,并按风险切片报告。

总结与相关资源

可靠的 LLM 应用不会判断一段回答“看起来像不像幻觉”。它会声明真值边界、保存证据快照、逐条评估原子声明,再执行确定性的决策策略。RAG、提示词、温度、一致性检查和自动 Judge 都可以支持这套系统,但没有一个是真值预言机。

相关资源: