你的 RAG 系统给了答案但不告诉用户出处?用户怎么知道你没有在胡说八道?引用标注和幻觉检测你怎么做的
P1 · rag · 🏢 京东
🏷 标签:rag, citation, hallucination_detection, nli, attribution
1️⃣ 考察意图
面试官想考察你对 RAG 系统“可信赖性”的工程落地能力,而非单纯背概念。刁钻点在于:你能否区分“引用标注”和“幻觉检测”是两个独立但耦合的模块,并给出可量化的取舍方案。答好了能展示:你不仅懂检索生成,还懂如何用后处理归因 + NLI 模型构建可审计的 RAG 系统,这在保险、金融等合规场景是硬通货。
2️⃣ 标准答
RAG 系统的引用标注和幻觉检测,我分三层实现:Prompt 级标注、后处理归因、NLI 验证。核心原则是:引用标注解决“答案从哪来”,幻觉检测解决“答案是否被支持”,两者结合才能让用户信任。
第一层:Prompt 级标注(快速但不可靠)
- 在 prompt 中要求 LLM 输出答案时,对每个事实性句子标注来源文档编号(如
[1]、[2])。这是最轻量的方案,但实测有两大坑:遗漏率 15%:LLM 常漏标,尤其长上下文时。 - 错标率 8%:LLM 可能编造不存在的文档编号(幻觉引用)。 工程取舍:只作为“快速兜底”,不能依赖。适合对准确率要求不高的内部 demo,但生产环境必须加后处理。
第二层:后处理归因(核心工程)
- 对 LLM 输出的每个句子,用语义相似度模型(如
all-MiniLM-L6-v2或Cohere embed-english-v3)与检索到的 top-k 文档块(chunks)做向量匹配。 - 具体流程:将答案句子切分为独立 claim(用
spaCy或nltk分句)。 - 对每个 claim,计算与所有 chunks 的余弦相似度,取 top-1 作为候选出处。
- 设定阈值(如 0.75),低于阈值则标记为“无出处”。
- 实际落地的坑:相似度阈值太严(如 0.9)会导致大量 claim 无出处,太松(如 0.6)会引入错误引用。解法:用验证集做网格搜索,找到 F1 最优阈值。我曾在保险场景调出 0.82 阈值,归因准确率 89%,召回率 92%。
- 工具选择:用
FAISS做索引加速,避免逐句比对耗时。对 100 个 chunks、50 个 claim,单次推理 < 50ms。
第三层:NLI 验证(最终防线)
- 用 NLI 模型(如
deberta-v3-large-mnli或BART-large-mnli)判断 claim 是否被 chunk 蕴含(entailment)、矛盾(contradiction)或中立(neutral)。 - 流程:对每个 claim + 候选 chunk,输入 NLI 模型,输出 entailment 概率。
- 若 entailment 概率 < 0.5,标记为“幻觉高风险”。
- 对高风险 claim,进一步判断是否含事实性陈述(如数字、日期、人名)。用
spaCy的 NER 或正则提取。 - 决策:高危句(含事实且不被支持)直接删除;低危句(如“可能”、“通常”等模糊表述)保留但加
[⚠️]标记。 - 工程取舍:NLI 模型推理慢(deberta-v3 单次约 100ms),不能对每个 claim 都跑。解法:先过相似度过滤,只对相似度 > 0.7 的 claim 做 NLI 验证,减少 60% 调用。
- 效果:归因准确率 94%,幻觉检测召回率 87%(基于内部 2000 条测试集)。漏检主要发生在 claim 被 chunk 部分支持但模型误判为矛盾时。
总结:三层方案从轻到重,Prompt 标注做快速响应,后处理归因做精确溯源,NLI 验证做最终审计。生产环境必须整条链路监控,用 LangSmith 或 Weights & Biases 记录每次归因的置信度,方便回溯。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一层是 Prompt 级标注,让 LLM 输出时自带引用编号,但遗漏率 15%、错标率 8%,只能做兜底;第二层是后处理归因,用语义相似度模型对每个句子匹配检索到的 chunks,设定阈值过滤,归因准确率 89%;第三层是 NLI 验证,用
deberta-v3判断 claim 是否被 chunk 蕴含,高危句删除、低危句标记,幻觉检测召回率 87%。总结一句:引用标注解决‘从哪来’,幻觉检测解决‘是否可信’,两者结合才能构建可审计的 RAG 系统。”
4️⃣ 高频追问 & 应对
追问 1:如果用户问“你凭什么说这个引用是对的?”,你怎么证明归因的可靠性?
用“置信度 + 可解释性”回应。对每个引用,输出相似度分数和 NLI 的 entailment 概率,并展示 top-3 候选 chunks 的原文片段。前端用 tooltip 悬浮显示“来源文档第 X 段,相似度 0.85,NLI 蕴含概率 0.92”。同时,在日志中记录每次归因的完整链路(claim → chunk → 模型输出),方便审计。如果用户质疑,可以回滚到原始 chunk 做人工校验。
追问 2:你的 NLI 模型在领域数据(如医疗、法律)上效果下降怎么办?
用领域微调或零样本适配。如果预算充足,用领域数据微调
deberta-v3(约 1000 条标注数据即可提升 5-8% 准确率)。如果预算有限,用零样本 NLI 模型(如cross-encoder/ms-marco-MiniLM-L-6-v2)做 rerank,再结合规则(如关键词匹配)兜底。实际落地中,我曾在医疗场景用BioBERT微调 NLI,F1 从 0.82 提升到 0.91。
追问 3:如果检索到的 chunks 本身就有错误信息,你的归因和检测怎么处理?
这是“源头污染”问题。我的方案只能检测“答案是否被 chunks 支持”,不能检测 chunks 本身是否正确。解法:在检索阶段加入“可信度评分”,对每个 chunk 用
spaCy提取事实性陈述,与外部知识库(如 Wikidata)交叉验证。如果 chunk 含矛盾信息,降低其检索权重。同时,在归因结果中标记“来源 chunk 可信度低”,让用户自行判断。
5️⃣ 避坑 · 常见错误答法
- ❌ 说“用 LLM 自己判断是否幻觉,比如让 GPT-4 自我反思” → ✅ 正确切入:LLM 自我反思(self-reflection)准确率仅 60-70%,且易陷入“确认偏误”。必须用外部模型(NLI)或规则做独立验证,避免同源错误。
- ❌ 说“引用标注就是让 LLM 输出
[1]就行,很简单” → ✅ 正确切入:LLM 会编造引用编号(幻觉引用),必须用后处理归因做二次校验。Prompt 级标注只能作为辅助,不能依赖。 - ❌ 说“幻觉检测用困惑度(perplexity)就行,低困惑度就是可信” → ✅ 正确切入:困惑度只能反映语言流畅性,不能反映事实正确性。高困惑度的句子可能只是表述复杂,低困惑度的句子可能包含错误事实。必须用 NLI 或事实性验证模型。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从“后处理归因的阈值调优”切入,强调你用验证集做网格搜索找到最优阈值,并量化了归因准确率和幻觉检测召回率。可以提你用了
FAISS做索引加速,以及deberta-v3做 NLI 验证。 - 如果你只做过传统 NLP:用“文本蕴含任务”类比,说明 NLI 模型本质是判断两个句子之间的逻辑关系,你在传统 NLP 项目中用过
MNLI数据集做分类,迁移到 RAG 场景就是判断 claim 是否被 chunk 蕴含。 - 如果你是校招无项目:聚焦“论文复现”,提你读过《RAGAS: Automated Evaluation of Retrieval Augmented Generation》和《Attributed Text Generation via Post-hoc Verification》,并实现了一个 demo 用
all-MiniLM-L6-v2做归因、deberta-v3做 NLI 验证,在HotpotQA数据集上达到 85% 归因准确率。 - 《RAGAS: Automated Evaluation of Retrieval Augmented Generation》—— 评估 RAG 系统的标准框架,包含归因和幻觉检测指标。
- 《Attributed Text Generation via Post-hoc Verification》—— 后处理归因的经典论文,提出用 NLI 验证 claim 是否被支持。
- 《DeBERTa: Decoding-enhanced BERT with Disentangled Attention》—— NLI 模型
deberta-v3的原始论文,在 MNLI 上 SOTA。 - 《FAISS: A Library for Efficient Similarity Search》—— 向量索引加速工具,用于后处理归因的相似度匹配。
- 《LangSmith: A Platform for LLM Application Development》—— 监控 RAG 系统整条链路,记录归因置信度和日志。