跳到主要内容

检索空洞问题:为什么你的 RAG 拒绝说“我不知道”

· 阅读需 12 分钟
Tian Pan
Software Engineer

向生产环境中的 RAG 系统提一个你的语料库无法回答的问题,看看会发生什么。它很少会说“我没有那方面的信息”。相反,它会检索出五个排名最高的片段——由于没有更好的匹配项,这五个片段其实是五个最不糟糕的无关内容——然后将它们交给模型,并配上类似“请使用以下上下文回答用户的问题”的提示词。模型在被训练为要乐于助人的同时,手中握着与主题有几分相似的文本,于是产生了一个自信的回答。这个答案的错误在架构上是不可见的:检索成功了,生成也成功了,每个片段都在检索到的文档中有据可查,但用户却被误导了。

这就是检索空洞问题。它不是任何单一层级的 bug。它是一个流水线的涌现行为,该流水线将 “top-k” 视为一种契约,却从不询问 top-k 的质量如何。ICLR 2025 上发表的一项关于“充分上下文”(sufficient context)的研究量化了这一影响:当 Gemma 获得充分的上下文时,其在事实性问答上的幻觉率约为 10%。当它收到的上下文不足时——即检索到的文档实际上并不包含答案——该比率会飙升至 66%。向描述不足的查询中添加检索到的文档会让模型错得更自信,而不是更少。

大多数团队采取的补救措施是“提高相似度阈值”。这起初有一点帮助,但很快就会失效。真正的解决方案需要将检索重新构想为一个分类问题,其输出空间包含“空答案”,而不是一个输出始终为列表的排序问题。

为什么 top-k 是错误的抽象

向量搜索是一个排序原语。你给它一个查询嵌入(embedding),它会返回余弦空间中排序后的 k 个最近邻。这个原语对于这些邻居是否“相关”是持中立态度的。在一个烹饪食谱语料库中查询“德国股票期权的税务处理”,仍然会返回五个食谱,排序依据是哪些食谱恰好与查询向量共享了最多的偶然词汇。嵌入空间中的距离并不等于语义相关性;它仅代表“这是我们能找到的最接近的东西”。

问题在提示词组装阶段进一步加剧。标准的 RAG 提示词通常以祈使句形式编写:“请使用以下上下文来回答问题。”模板中没有预留位置来说“这些上下文都不相关,所以请承认你不知道”。LLM 收到五个无关的段落以及使用它们的指令,它照做了。研究人员称之为弃权悖论(abstention paradox):检索本应通过将输出建立在真实文档之上来减少幻觉,但当文档偏离主题时,检索反而会 增加 幻觉,因为添加任何上下文都会提高模型不合理的自信。

2025 年一项关于 LLM 弃权行为的调查将其归结为校准失败。模型不知道检索到的上下文意味着什么——它们只是将其视为真理。上游流水线从未发出过“此次检索置信度低”的信号。因此,“低置信度检索”和“高置信度检索”在到达模型时是无法区分的。模型对它们一视同仁。生成的答案建立在排名最高(但并非真正响应)的文本之上。

相似度阈值是必要的,但并不充分

大多数团队的第一反应是增加余弦相似度截断:如果最高分低于 0.7,则返回“无答案”。这是一个正确的方向,但实施方式不对。几乎立即就会出现三个问题。

首先,0.7 这个数字只是一个民间默认值,而非经过校准的值。常见的阈值区间通常如下:0.9+ 表示近乎精确匹配,0.7–0.8 表示相关但非完美,0.5–0.6 表示松散相关,0.3–0.4 表示弱连接。但这些区间是特定于模型和特定于语料库的。从 text-embedding-3-small 切换到多语言模型,整个分布都会发生偏移。索引一个高度相似的技术文档库,每个分数都会向 0.9 压缩,使得 0.7 变得毫无意义。系统的正确阈值只能通过保留部分查询、打标签并观察信噪比拐点来凭经验发现。

其次,即使在单一系统中,全局阈值也是错误的,因为不同的查询类型具有不同的分数分布。一个具体的事实性查询(“Jane 的邮箱是什么?”)应该达到 0.75+ 的精准层级匹配,而一个探索性查询(“关于定价策略我们知道些什么?”)合理地检索到 0.5–0.6 的文档时,这些文档实际上也是非常有用的。对两者都坚持 0.7 的阈值,要么会丢失有用的探索性结果,要么会通过糟糕的具体查询结果。按查询类别进行校准——将阈值视为查询意图的函数——通常比全局截断能带来 2-3 倍的精确度提升。

第三,相似度是相关性的代理指标,而非衡量标准。两个句子可能因为共享词汇和句法结构而具有很高的余弦相似度,即使它们讨论的是不同的事情。一个关于股票期权的税务问题会在余弦上匹配一份关于公司薪酬的文档,即使该文档从未涉及税务。双编码器(bi-encoder)嵌入针对检索速度进行了优化,而非针对相关性判断。将阈值提高到一定程度后,它在过滤掉那些“自信的无关项”之前,就会开始丢弃真正有用的匹配项。

两阶段模式:宽检索,窄分类

真正有效的生产模式将检索和相关性视为两个独立的问题。第一阶段撒大网 —— 从向量搜索中检索 50 或 100 个候选结果,不设置严格的阈值。第二阶段在这些候选结果上运行 交叉编码重排序器 (cross-encoder reranker),使用专门为判断相关性(而非快速生成相似度)而训练的模型,为每个 (query, document) 对评分。

交叉编码器在设计上比双编码器 (bi-encoders) 慢:它们将查询和文档拼接在一起,对这一对数据进行完整的 Transformer 推理,这使得它们能够捕捉到双编码器会遗漏的细微不匹配。一个典型的生产方案是从向量搜索中提取 150 个候选结果,用交叉编码器对前 30 个进行重排序,然后将前 3–8 个发送给 LLM。交叉编码器的分数经过校准,与余弦相似度处于不同的量级 —— 0.5 的重排序分数意味着“中度相关”,而不是“一半匹配”,且分数的分布在不同查询类型中要稳定得多。

现在,阈值决策转移到了重排序器的输出上,在这里它才真正具有意义。而且,这为你免费提供了一项新能力:如果没有文档通过重排序器阈值,流水线可以路由到拒绝回答 (abstention),而不是将一堆糟糕结果中最好的那个交给 LLM。重排序器在这里充当了一个带有“空回答”选项的相关性分类器。这就是架构上的转变 —— 流水线现在有了一个合法的“否”输出。

你可以更进一步,在检索步骤之前放置一个专门的 检索价值分类器 (retrieval-worthiness classifier)。在查询索引之前,一个轻量级分类器会决定该查询是否属于该语料库的域内 (in-domain)。域外 (out-of-domain) 查询会完全跳过检索,并返回一个清晰的“我不涵盖该主题”的响应。这很重要,因为对于真正的域外查询,任何 检索结果都将是不相关的,而重排序器在拒绝所有这些结果方面并不是无限可靠的。使检索本身取决于领域匹配信号,可以减轻下游过滤器的压力。

校准拒绝回答,避免过度拒绝

另一侧的失败模式是过度拒绝:你的系统开始对它 本可以 回答的问题说“我没有相关信息”,从而破坏了检索本应提供的实用性。一项关于检索增强模型是否“知道自己不知道”的 2025 年研究发现,针对拒绝回答进行激进训练的模型,经常会拒绝那些仅凭其内部知识就能正确回答的问题 —— 检索层发出了“上下文糟糕”的信号,模型就将其理解为“拒绝”,即使拒绝是错误的。

生产环境的经验教训是,拒绝回答需要结合多个信号,而不是依赖任何单一阈值。有用的输入包括:

  • 检索信号:最高重排序分及其与次高分的距离。高分簇暗示了一个有充分支持的答案;而一个处于边界的高分且周围没有其他分数,则暗示这是一个伪装成强匹配的弱匹配。
  • 上下文充分性信号:一个分类器 —— 通常只是一个带有结构化提示词的小型 LLM —— 阅读检索到的上下文并判断其中是否包含足够的信息来回答问题。Google 的研究表明,这种分类器在二元(充分/不充分)分类上的准确率可以训练到 93%。
  • 模型自持信心:基于采样的置信度(模型是否五次给出相同的答案?)或基于对数概率 (logprob) 的置信度。这本身是有噪声的,但作为检索信号的交叉检查非常有用。
  • 查询类型先验:事实性问题的拒绝应比探索性问题更激进,因为在“截止日期是什么时候?”上出错比在“关于定价我们是怎么想的?”上含糊其辞后果更严重。

将上下文充分性评分与模型自持信心相结合,产生了一个选择性生成框架。在 Google 的研究中,该框架比仅靠置信度的方法将“准确率-覆盖率”权衡提高了约 10 个百分点。重点不在于确切的数字,而在于正交信号的堆叠,任何单独使用的信号要么会导致过度拒绝,要么会导致拒绝不足。

将“我没有相关信息”视为一等公民式的响应

检索空洞问题最深层的版本不是技术问题,而是架构问题:大多数 RAG 系统的设计方式使得拒绝回答在结构上不太可能发生。提示词模板假设检索是有效的,UX 假设会得到一个自信的回答,评估框架衡量的是语料库覆盖问题的回答质量,而不是不涵盖问题的拒绝质量。每一层都倾向于“产生输出”。

成功交付值得信赖的 RAG 团队会反其道而行之。他们将“我没有相关信息”的响应视为一项 产品功能,拥有自己的 UX、提示词路径、评估集和可观测性。在实践中,这意味着:

  • 在提示词组装代码中有一条明确的拒绝路径,由重排序器和上下文充分性信号触发,切换到不同的系统提示词,要求模型陈述它 需要 什么才能回答,并建议用户可以去哪里查找。
  • 一套 已知不可回答的查询 评估集 —— 语料库确实不涵盖的问题 —— 根据拒绝率和拒绝质量进行评分。没有这套集合,你无法判断提高阈值是提升了信任度,还是只是在你 本应 回答的问题上输出了更多的“我不知道”。
  • 独立的仪表盘,分别监控拒绝率、不充分上下文查询下的幻觉率以及覆盖率损失。这三个指标互有权衡,你无法将它们作为一个数字来优化。
  • 一个反馈渠道,用户可以标记“你拒绝了一些你应该回答的问题”。过度拒绝通常是无声的 —— 用户只是停止提问 —— 因此你必须主动将其暴露出来。

RAG 系统能说的最值得信赖的话就是它不知道。赢得这种信任的工具并非来自更好的检索,而是来自将拒绝回答视为一种工程化能力。一个总是回答的 RAG 总是会在其分布的尾部产生幻觉。一个知道自己局限性的 RAG 才是用户真正可以依赖的。

References:Let's stay in touch and Follow me for more thoughts and updates