应用工程

RAG 引用真实性自动校验

RAG 系统给答案附上链接,并不代表引用是真的。常见问题不是链接打不开,而是链接能打开、文档也相关,却没有直接支持答案中的具体主张。用户看到脚注容易降低警惕,这类“看起来有据可查”的错误比没有引用的幻觉更难发现。

引用真实性校验要回答三个不同问题:来源是否真实存在,引用片段是否来自该版本文档,片段是否足以支持答案主张。把三者压成一个相似度分数,会让系统无法解释究竟在哪里失真。更稳妥的做法是结构化生成、确定性核对和语义判断分层执行。

一、先定义什么叫一条有效引用

一条可接受的引用至少包含 source_id、文档版本、片段位置和被支持的 claim。只保存网页 URL 不够,因为网页会更新;只保存 chunk_id 也不够,因为重新切块后同一编号可能指向不同文本。

可以把有效性拆成四级:来源有效,表示文档在允许的数据集中;定位有效,表示引用片段能在指定版本中复原;内容相关,表示片段谈到同一主题;证据充分,表示片段能够推出答案中的主张。前三层通过,最后一层失败,仍然属于伪引用。

例如答案说“退款必须在 7 天内申请”,证据只写“符合条件的客户可以申请退款”。两段语义相关,却没有支持“7 天”这个期限。向量相似度通常会给高分,因此不能承担最终裁决。

二、让生成模型输出 claim 与 citation 的映射

不要先生成自然语言答案,再从检索结果里猜脚注。生成阶段就要求模型把可验证主张拆开,并显式引用一个或多个证据块。最终展示层再把结构化结果渲染成自然文本。

{
  "claims": [
    {
      "claim_id": "c1",
      "text": "退款申请需要在购买后 7 天内提交。",
      "citations": [
        {"source_id": "policy", "version": "2026-08-01", "chunk_id": "p12"}
      ]
    }
  ]
}

一个句子如果包含多个独立事实,应拆成多个 claim。比如“方案 A 每月收费 20 美元并支持 10 名成员”包含价格和人数上限,可能来自不同段落。拆分以后,校验器能指出哪个事实没有证据,而不是整句给出模糊的失败。

三、第一层用确定性规则检查来源与定位

确定性检查不需要模型。校验 source_id 是否属于本次检索集合,版本哈希是否一致,chunk_id 是否存在,引用文本是否能在规范化后的原文中找到。还要禁止模型引用没有送入上下文的来源,否则它可能凭训练记忆生成一个真实 URL,却不是本次答案的证据。

文档入库时建议保存 document_id + version_hash + start_offset + end_offset。网页类来源额外保存抓取时间和 canonical URL;数据库记录保存主键与更新时间。这样即使索引重建,也能回到当时生成答案所见的原文。

确定性层失败应直接判定引用无效,不必继续调用语义模型。它还可以拦截越界 offset、空片段、重复脚注和指向导航栏文本的引用,节省后续评测成本。

四、第二层判断证据是否真正支持主张

语义校验更接近自然语言推断:给定 claim 和 evidence,输出 supported、contradicted 或 insufficient。提示词必须强调“相关不等于支持”,并要求对数字、时间、范围、否定词和比较关系逐项核对。

def verify_claim(claim, evidence, judge):
    prompt = {
        "claim": claim,
        "evidence": evidence,
        "labels": ["supported", "contradicted", "insufficient"],
        "rule": "只能依据 evidence;相关但缺少关键限定时选 insufficient"
    }
    return judge.generate_json(prompt)

单个大模型评分不能当绝对真值。高风险场景可以组合规则:数字必须在证据中精确出现;带“全部、永远、唯一”等强限定的主张需要同等级措辞;判断模型负责同义改写与跨句蕴含。规则和模型结论冲突时,默认进入人工复核或删除该主张。

五、处理一条主张需要多段证据的情况

有些结论无法由单个 chunk 支持。例如一段说明基础配额,另一段说明企业版例外。校验时既要检查每段证据,也要检查证据组合是否完整。简单地取最高分片段,会丢掉例外条件。

建议限制每条 claim 最多引用三到五段,并要求生成器说明每段证据的角色:直接支持、限定条件、计算输入。计算类答案还要保存中间式子。例如“年度成本为 240 美元”若由“月费 20 美元”推导,应记录 20 × 12,校验器同时核对数字来源与运算。

如果证据之间矛盾,应根据版本、权限范围和生效时间选择,而不是让模型投票。无法确定时,答案要明确显示冲突,不应偷偷选一段更像结论的文本。

六、离线评测要覆盖伪引用,而不只是正确引用

测试集除了正常样本,还要人为构造困难负例:主题相关但不支持、数字相近但不同、旧版本政策、否定关系翻转、适用范围缺失、多个证据才能推出。只有“随机换一篇无关文档”的负例太容易,无法代表线上错误。

主要指标包括 citation precision,即展示的引用中有多少真正支持主张;citation recall,即应当引用的主张有多少得到证据;claim coverage,即答案中可验证事实的覆盖率;以及错误接受率,即校验器把伪引用放行的比例。高风险知识库应优先降低错误接受率。

评测集的建立可参考 LLM 评测 Golden Set 构建方法,检索与生成指标的整体关系见 RAG 系统评测框架搭建实战。

七、线上链路应支持降级与追踪

同步校验会增加延迟,可以按风险分级。客服政策、合规、合同等答案在返回前完成全量校验;普通知识问答先做确定性检查和轻量语义检查;长报告可以先生成草稿,再异步标注低可信引用供用户复核。

校验失败后的处理顺序是:重新检索更精确证据;缩小或改写 claim;仍无证据则删除该事实并回答“当前资料不足”。不要只把脚注移除却保留原结论,那只是隐藏错误。

线上日志至少记录 query、检索文档版本、claim、citation、校验标签、置信理由和最终动作。涉及敏感数据时记录哈希或脱敏摘要,并设置保存期限。文档更新后,可按 version_hash 找到受影响答案并重新校验,这也能解决索引与内容版本不一致的问题,详见 RAG 文档版本与索引一致性。

八、落地顺序:先可追溯,再追求智能

第一阶段先改数据结构,让每个脚注能回到确定版本和原文位置;第二阶段加入 claim 拆分与规则检查;第三阶段再接语义 judge 和困难负例评测;最后根据线上误报、漏报调整阈值与降级策略。

团队最容易走反的是一开始训练复杂判别器,却没有稳定的文档 ID 和版本。此时判别结果即使正确,也无法复现或修复。可追溯性是校验系统的地基,模型只是其上的一个判断组件。

九、相关阅读