Qdrant

Predicting Weak Retrieval Without an LLM

8.5内容质量

TL;DR · AI 摘要

无需LLM即可预测检索质量,通过信号检测弱检索,提升系统效率。

核心要点

  • 使用dense_variance和evidence_coverage等信号可检测弱检索。
  • height和spread信号反映检索器的置信度和结果分布。
  • 无需LLM,仅通过Qdrant查询即可实现弱检索检测。

结构提纲

按章节快速跳转。

  1. 当前检索系统在处理查询时存在效率问题,需要改进方法。

  2. 弱检索是指检索结果未能包含查询所需的关键信息。

  3. 通过计算信号来预测弱检索,无需调用LLM。

  4. 信号分为高度、分布、覆盖和一致性四类,各有不同的检测方式。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 预测弱检索
    • 信号分类
      • 高度 (height)
      • 分布 (spread)
      • 覆盖 (coverage)
      • 一致性 (agreement)
    • 检测方法
      • dense_variance
      • evidence_coverage
      • retriever_divergence
      • dense_agreement

金句 / Highlights

值得收藏与分享的关键句。

#Qdrant#检索系统#信号检测#AI
打开原文

不依赖 LLM 的弱检索预测 - Qdrant

返回搜索质量

不依赖 LLM 的弱检索预测

Dylan Couzon

·

2026 年 6 月 24 日

大多数检索系统对每个查询运行一个管道,这在两个方向上都是错误的默认设置:单次通过无法满足复杂查询的需求,而对每个查询进行重排序或重写则在简单查询上浪费了计算资源。更糟糕的是,单次通过会静默失败。当相关文档从未进入前列时,系统仍然会根据它所获得的任何内容进行回答,没有任何迹象表明出了问题。

昂贵的修复方法已被充分理解,包括交叉编码器、ColBERT 晚期交互、查询重写和分解,因此真正的问题是何时使用它们:理想情况下,你可以在不花费任何代价的情况下廉价地检测到弱检索,并仅对需要的查询进行升级。但什么能廉价地告诉你检索是弱的?这取决于检索失败的方式,我们通过三个语料库对其进行测量。

“弱检索”的含义

检测弱检索始于一个可衡量的定义。只有前几个结果会被使用:模型的 top-k 片段或展示给用户的页面。称这个为窗口。良好的检索将查询所需的所有证据都包含在窗口中;当即使一个证据缺失时,无论召回率看起来如何,检索都是弱的。

将窗口设置为你的系统所消费的任何内容。在已标记的分割中,当你知道每个查询需要哪些文档时,弱检索是一个你可以预测的二进制标签。

廉价信号

信号是从结果中计算出的一个数字,用于预测弱证据。有两个标准:

  • 它在标记数据上能区分良好的检索和弱检索。
  • 它足够便宜,可以在每个查询上运行。

“廉价”排除了显而易见的方法:在每个查询上询问 LLM “这足够吗?”会增加模型调用的开销,这是你试图保护的路径。这里的信号读取检索器已经返回的内容,最多再加一个 Qdrant 查询。热路径中没有 LLM。

它们都不是新的:预测检索是否成功是查询性能预测(QPP),而 dense_variance 接近其未归一化的查询承诺。贡献不是一个新的预测器,而是哪些已知的预测器能证明其成本,并在什么类型的语料库中适用。

家族

信号

它读取的内容

何时标记为弱

高度

code
max_score

top-1 融合得分

范围

code
dense_variance

原始密集余弦值的方差

覆盖

code
evidence_coverage

top-k 文本中出现的查询实体

一致性(密集 vs 稀疏)

code
retriever_divergence

密集 vs 稀疏 top-k 重叠

高(它们不一致)

一致性(跨密集模型)

code
dense_agreement

独立密集模型 top-k 重叠

低(它们不一致)

直觉是转移到新语料库的内容:

  • 高度和范围:一个自信的检索器会将它的 top 分数分开;一个迷失的检索器会将它们聚集在一起。
  • 覆盖:查询中提到的实体是否出现在检索到的文本中。
  • 一致性:当两个检索器或两个密集模型返回不同的文档时,通常其中一个迷失了,尤其是在术语和词汇表之外的术语上。
  • 范围只在保持其大小的分数上携带信息。在基于排名的 RRF 下,从原始密集余弦值中读取它,该方法会丢弃大小;或在像 DBSF 这样的保持分数的融合下,从融合分数中读取它。

信号是如何计算的

范围信号是检索器分数的总体方差:

code
import
statistics
def
dense_variance
(
dense_ranking
):
# spread of the raw dense cosines
return
statistics
.
pvariance
([
score
for
_
,
score
in
dense_ranking
])

dense_variance 读取原始密集排名,只需要一个额外的 Qdrant 查询,该查询重用了你已经嵌入的查询向量,因此不需要额外的模型调用:

code
def
dense_ranking
(
query_vector
,
window_k
=
10
):
points
=
client
.
query_points
(
collection_name
=
"your_collection"
,
query
=
query_vector
,
using
=
"dense"
,
limit
=
window_k
,
with_payload
=
False
,
)
.
points
return
[(
p
.
id
,
p
.
score
)
for
p
in
points
]

两种一致性信号都是 top-k 集合重叠。retriever_divergence 比较密集和稀疏排名;dense_agreement 在两个或更多独立的密集模型之间平均重叠。不管怎样,不一致意味着检索效果差:

code
from
itertools
import
combinations
def
jaccard
(
a
,
b
):
# set overlap of two top-k id lists
a
,
b
=
set
(
a
),
set
(
b
)
return
len
(
a
&
b
)
/
len
(
a
|
b
)
if
a
or
b
else
1.0
def
retriever_divergence
(
dense_ids
,
sparse_ids
):
return
1
-
jaccard
(
dense_ids
,
sparse_ids
)
# high when they disagree
def
dense_agreement
(
rankings
):
# one top-k id list per model
scores
=
[
jaccard
(
a
,
b
)
for
a
,
b
in
combinations
(
rankings
,
2
)]
return
sum
(
scores
)
/
len
(
scores
)
# low when they disagree

一致性信号并不是免费的:dense_agreement 运行额外的密集模型,每个查询只需几个嵌入。尽管如此,这仍然比使用大型语言模型(LLM)判断便宜得多。

哪些信号触发取决于失败模式

根据信号在标记数据集上区分良好检索和弱检索的效果(用AUC衡量,0.5表示随机,1.0表示完美)对每个信号进行评分。我们在三个以不同方式失败的语料库上运行了所有信号:MuSiQue(多跳问答)以及BEIR集合中的NFCorpus(医学术语)和SciFact(科学声明)。

每个语料库中每个信号的分离AUC。密集分布的信号在所有三个语料库中都有效;其他信号只在语料库以它们的方式失败时才有帮助。堆叠:bge-base + miniCOIL 与 RRF 融合,加上 mxbai-embed-large 和 arctic-embed-m 用于一致性信号;窗口是按语料库划分的,因此在列内进行比较,而不是跨列。

没有一个信号在所有三个语料库中都是最好的,哪些信号值得计算取决于语料库的失败方式:

  • 词汇不匹配(NFCorpus):在这个语料库中,术语和超出词汇表的术语似乎使密集和稀疏以及独立的密集模型在弱查询上产生分歧。一致性信号从接近随机的水平上升到0.73到0.76,与分布信号处于同一水平,这是衡量它们值得的唯一情况。
  • 排名精度(SciFact):正确的文档被检索到但排名太低。分布和高度可以捕捉到这一点(0.75到0.76);一致性信号则没有帮助。
  • 可达性(MuSiQue):答案需要一个查询无法表达的跳转,因此第一次检索即使错误也会显得很自信。最好的廉价信号只能达到0.73,一致性信号下降到接近随机:没有廉价信号能可靠地捕捉到缺失的跳转,因此解决方法是分解(生成能够到达下一个跳转的新查询),而不是更好的门控。

三个基准无法确立一个通用的信号,因此交付的是方法,而不是默认值:在自己的数据上测量分离度,并保留有效的方法(evidence_coverage 在三个语料库中都没有分离任何内容,因此我们将其删除)。唯一应该普遍适用的模式是上限:当失败是可达性问题,而不是嵌入混淆时,结果看起来健康,而没有廉价信号能发现这一点。

找到你的信号

获胜信号本身并不传递,但方法可以。在校准分割中,根据分离程度对每个候选信号进行评分:

code
from
sklearn.metrics
import
roc_auc_score
def
separation
(
values
,
weak_labels
):
auc
=
roc_auc_score
(
weak_labels
,
values
)
return
max
(
auc
,
1
-
auc
)
# separation, regardless of direction

两条规则:保留分离程度高于某个阈值(0.65 是一个合理的起点)的信号,并丢弃与更强信号高度重复的信号(绝对相关性高于 0.85),因为冗余信号会增加成本,而不是提供信息。在校准分割上设置阈值;保留一个测试分割用于最终结果。让失败模式首先指出问题,术语或标识符密集语料库上的信号一致性,精确度缺失的分布和高度,然后通过数字确认,因为获胜者是语料库特定的。

将信号转化为门控机制

一个阈值将信号转化为一个决策。将选定的信号调整为较低值表示较弱,从而否定那些在弱检索上表现较高的信号(如 retriever_divergence),因此一个单一的下限决定了:低于该下限,将检索视为较弱并升级处理:

code
def
retrieval_is_weak
(
result
):
return
signal
(
result
)
<
FLOOR
# signal oriented so lower means weaker

这个下限是一个权衡:提高它以捕获更多弱检索并升级更多,降低它以减少升级次数并漏掉更多。一个坚实的默认值在校准集上最大化捕获率减去误报率(Youden 点);当漏掉的代价比额外升级更高时,目标应是召回率,比如 90%。如果两个信号分离良好且相关性极低,可以在任一信号触发时进行门控。

选定信号在良好检索和弱检索中的分布,以及校准后的下限。阴影区域表示升级处理。

对弱检索进行处理

你升级处理的方式是一个简单的选择:重新排序、重写、分解、放宽过滤条件,或转交给人员处理。门控机制不关心具体选择哪种方式;昂贵的决策是是否升级,而这个决策在每次查询中都是免费进行的。升级处理无法做到的是发明语料库中没有的证据:当没有可发现的内容时,胜利在于检测到弱检索并放弃回答,而不是基于薄弱证据进行回答。一个可运行的示例将门控机制连接到一个完整的自我纠正循环中。

将此方法适配到你的语料库

这里的获胜者并不具有可移植性;方法是:

  • 定义窗口和每个查询所需的证据。
  • 在校准分割上标记弱检索。
  • 对廉价信号进行基准测试;保留能分离的信号,丢弃冗余的。
  • 将胜出信号设置为一个门控机制,仅在它触发时进行升级。

检索质量可以从结果的廉价统计中观察到,但只有当失败是这些统计可以检测到的失败时才如此。在你自己的数据上测量是哪个信号。

相关工作

这与校正和自适应检索并行。区别在于决策的来源:对已经检索到的内容的廉价统计,不需要额外的模型调用,也不需要训练。

  • 查询性能预测有许多后检索预测器;这里的问题是,最廉价的一个能转移多远,以及它在何处达到上限。
  • CRAG 训练一个检索评估器,Self-RAG 对生成器进行微调以批评其自身的上下文;两者都使用训练好的模型,而这里使用的是免费的统计。
  • Adaptive-RAG 在检索前根据查询复杂度进行路由,这是本文反对的问题形状方法:根据你获得的证据进行门控,而不是根据问题的形状。
  • 充分上下文的工作方式是使用一个大型语言模型(LLM)判断者,而不是自由信号,来提出同样的“这足够吗?”问题。

完整的循环、纠正措施和评估工具可在自我纠正检索循环研讨会中找到。关于其升级后的构建模块,请参阅晚期交互模型、混合搜索和查询分解。