
RAG 幻觉 vs. 检索失败:一个诊断框架
如何判断 RAG 系统的错误输出是幻觉问题(LLM)还是检索问题(流水线)——一个结构化的诊断框架,包含症状对比、流程图和修复策略。
用户向你的 RAG 系统提问。答案是错的。然后呢?
这就是大多数团队犯同样错误的时刻:他们假设问题出在 LLM 上,然后开始调整 prompt。他们添加诸如"仅使用提供的上下文"或"如果答案不在上下文中就说不知道"之类的指令。有时这有帮助。但往往没有效果,因为真正的问题从来不是 LLM——而是检索流水线向它输入了错误或缺失的上下文。
RAG 系统的错误输出有两种根本不同的根因,针对一种的修复对另一种毫无作用。幻觉是生成问题:LLM 拥有正确的上下文但在回答中编造或扭曲了信息。检索失败是流水线问题:LLM 从一开始就没有收到正确的上下文,因此它要么编造内容、引用不相关的段落,要么给出不完整的回答。
误诊根因意味着在错误的修复上浪费时间。本文提供了一个结构化的框架来区分这两种问题。
两种失败模式
检索失败
检索流水线没有找到包含答案的文档或片段。LLM 收到的上下文是不相关的、部分相关的或空的——然后它尽力作答。
检索失败发生在 LLM 的上游。嵌入模型、分块策略、向量库查询、元数据过滤器或重排序步骤未能识别正确的内容。LLM 工作正常——它只是使用了错误的输入。
LLM 幻觉
检索流水线提供了正确的上下文。LLM 收到了包含答案的相关文档。但生成的响应与提供的上下文相矛盾、扭曲或编造了上下文中不存在的信息。
幻觉发生在检索的下游。流水线完成了它的工作。LLM 没有忠实地呈现它收到的内容。
为什么这种区分很重要
检索失败的修复是流水线工作:调整分块大小、改进嵌入、修复元数据过滤器、添加重排序、修复索引损坏。再多的 prompt 工程也无法修复一个检索不到正确文档的流水线。
幻觉的修复是生成工作:改进 prompt、使用结构化输出格式、添加引用要求、切换到更强的模型,或实施针对源上下文的生成后事实核查。
用错误的修复方法会浪费时间,甚至可能让情况更糟。对一个存在检索失败的系统添加"仅从上下文中回答"的指令,只会导致它拒绝回答——上下文中没有包含答案,所以指令按设计工作了,但用户体验却下降了。
诊断流程图
按照以下顺序来诊断 RAG 系统的错误输出是检索问题还是幻觉问题。
步骤 1:捕获检索到的上下文。
在诊断任何问题之前,你需要看到 LLM 实际收到了什么。记录或显示检索流水线为该查询返回的片段。如果你的系统不暴露这些信息,那这就是首先要修复的——你无法诊断你无法观察到的东西。
步骤 2:检索到的上下文是否包含正确答案?
自己阅读检索到的片段。正确回答该查询所需的信息是否存在于上下文中?
- 如果否:这是检索失败。继续阅读下方的检索诊断部分。
- 如果是:继续步骤 3。
步骤 3:LLM 的响应是否忠实地代表了检索到的上下文?
将 LLM 的回答与检索到的上下文进行对比。响应是否准确反映了上下文中的内容,还是它在矛盾、修饰或编造?
- 如果响应矛盾或添加了上下文中没有的信息:这是幻觉。继续阅读幻觉诊断部分。
- 如果响应准确但不完整:可能是两者之一——上下文可能包含完整答案但 LLM 遗漏了部分(遗漏性幻觉),或者上下文本身不完整(部分检索失败)。检查源文档是否包含未被检索到的信息。
步骤 4:失败是一致的还是间歇性的?
多次运行相同的查询(temperature 大于 0 时)。
- 如果答案以相同方式持续错误:更可能是检索失败(每次都检索到相同的错误上下文)。
- 如果答案在正确和错误之间变化:更可能是幻觉(LLM 在使用上下文时具有非确定性)。
症状对比表
| 症状 | 检索失败 | LLM 幻觉 |
|---|---|---|
| 答案自信但错误 | 常见——LLM 从不相关上下文中虚构 | 常见——LLM 在有正确上下文的情况下仍然编造 |
| 答案说"我不知道"但应该知道 | 可能——正确上下文未被检索到 | 不太可能——LLM 在上下文中有答案但选择不使用(罕见) |
| 答案引用了真实文档但引用了错误的部分 | 可能——从正确文档中检索了错误的片段 | 可能——LLM 在上下文内部错误归因 |
| 答案引用了不存在的文档 | 不太可能——检索返回真实文档 | 可能——LLM 编造了引用 |
| 答案包含错误的具体数字或日期 | 检查上下文——如果数字不在检索到的片段中,是检索失败 | 如果数字在上下文中但 LLM 改变了它们,是幻觉 |
| 答案部分正确、部分编造 | 可能——检索到了一些相关上下文,但缺少一些 | 可能——LLM 将真实上下文与编造内容混合 |
| 相同查询返回不同的错误答案 | 不太可能——检索是确定性的 | 可能——非确定性生成 |
| 问题在流水线更改后突然出现 | 可能——索引、嵌入或分块更改破坏了检索 | 不太可能——除非模型或 prompt 被更改 |
| 问题影响特定主题但不影响其他主题 | 可能——那些文档未被索引,或分块将它们碎片化了 | 不太可能——幻觉通常不是特定于主题的 |
诊断检索失败
一旦你确认正确的上下文未被检索到,就要缩小检索流水线中失败发生的位置。
检查 1:源文档是否在索引中?
通过元数据(文件名、文档 ID)直接在向量库中查询该文档。如果文档不在索引中,则它要么从未被索引,要么因索引损坏而丢失。这是摄入或索引完整性问题,不是检索问题。
检查 2:相关片段是否在索引中?
文档可能已被索引,但回答查询的特定段落可能以碎片化答案的方式被分割到了多个片段中。检索源文档的所有片段,并检查是否有任何单个片段包含完整答案。如果答案跨越两个或更多片段,你的分块策略需要调整——更大的片段、更多的重叠或语义分块。
检查 3:嵌入是否捕获了语义关系?
为查询和应该被检索到的片段生成嵌入。计算它们的余弦相似度。如果尽管片段与查询在语义上相关但相似度很低,则嵌入模型未能捕获该关系。这在嵌入模型未经训练的领域特定词汇上会发生。考虑使用领域特定的嵌入模型或查询扩展。
检查 4:元数据过滤器是否过于严格?
如果你的检索流水线使用元数据过滤器(日期范围、文档类型、部门),请验证过滤器是否在排除正确的文档。这是检索失败的一个出人意料的常见原因——一个在配置时正确的过滤器随着新文档以不同元数据模式到达而变得过时。
检查 5:重排序器是否在降低正确片段的排名?
如果你在初始检索后使用重排序步骤,重排序器可能将正确片段的得分评为低于不相关片段。检查重排序前的结果,看正确片段是否最初被检索到但随后被降级。