首页 / 文章 / 超越Top-K:RAG中的相关性阈值、混合搜索与重排序

超越Top-K:RAG中的相关性阈值、混合搜索与重排序

了解为何向量数据库与大型语言模型结合并不能构成成熟的RAG系统,以及分块、相似度阈值、混合搜索、重排序和评估机制如何填补这一缺陷。

1628 词

检索增强生成通常被描述为三步流程:查找与问题相关的文档,将其交给语言模型,再由模型生成答案。这个过程看似简单,但要确保其可靠性却并非易事。那种直接将嵌入搜索与大型语言模型相连的流程,在上下文不足时会给出自信的答案,会忽略精确的标识符,而在知识库中没有相关内容时则会编造答案。正是在这些方面,这种简单的设计会出问题,而从结构感知的分块处理到可量化的评估等各个阶段,则能将其转变为值得信赖的检索架构。

简单的流程及其隐含的假设

大多数教程所采用的基准实现方式如下:将文档分割成多个块,嵌入这些块,存储向量;在查询时嵌入问题,获取距离最近的top_k个块,并将它们拼接进提示语中。这种方法在演示中可以正常运行,但它隐含了一个假设,即每个块都是一个有意义的单元,且“距离最近”就等同于“相关”。

按照文档结构进行分块

以员工手册为例,那种简单的处理方式会将其随意切成1,000字符一段,结果往往是把某项政策一分为二,还将一个主题的结尾与另一个主题的开头拼接在一起。而更合理的处理方式则是遵循文档本身的结构,从而生成诸如远程办公、安全保障、带薪休假和费用报销之类的独立块。

一个结构完整的段落能为嵌入模型提供足够的上下文,使其理解文本的实际内容以及各语句之间的关联。这样生成的向量更为纯净,语义搜索也能返回更多相关的结果。

Top-K返回的是最接近的结果,而非最相关的结果

更好的分块处理方式反而会引发新的误解。将top_k = 5设置为“给我五个相关结果”,但实际上它要求的是距离最近的五个结果,无论其中是否有真正有用的内容。关于远程工作问题的典型得分分布可能如下:

Remote Work       0.62
Paid Time Off     0.36
Security          0.30
Expenses          0.28
Other Policy      0.24

用户需要的很可能是第一个匹配结果。其余四个匹配度都很低,只是因为需要填满列表才被列入其中。将这五个结果全部传递给模型,会导致有用信息与可能有用但关联较弱甚至无关的文本混在一起。此时模型必须自行区分有效信号与噪声,这不仅会增加计算成本,还会降低答案的可预测性。

无法回答的问题需要特殊处理

一个特别重要的情况是知识库根本无法回答的问题,比如手册中从未提及的“该公司的健康保险免赔额是多少?”。Top-K方法仍会返回五个结果,而简单的处理流程会将最接近的答案视为依据来猜测答案。

在企业环境中,正确的处理方式是说明现有文档包含的信息不足。一个设计良好的系统应当能够返回类似如下的结果:

No sufficiently relevant context was found.

在检索结果与模型之间添加相关性过滤器

要同时处理匹配度较低的情况以及无法回答的问题,需要增加一个处理阶段。传统的流程如下:

Vector Search
   ↓
Top-K
   ↓
LLM

改进后的流程将Top-K结果视为候选列表,并在模型之前插入过滤器:

Vector Search
   ↓
Top-K candidates
   ↓
Relevance Filter
   ↓
LLM

最简单的过滤器就是相似度阈值,达到或超过该阈值的候选项会被保留:

score >= threshold
    → keep

而低于该阈值的候选项则会被剔除:

score < threshold
    → discard

如果没有任何候选项通过筛选,系统会返回“无相关内容”的响应,而不会向模型输入有噪声的数据。

根据测试数据确定阈值

阈值应基于数据来确定。在一个企业手册数据集上进行的小规模实验中,对比了多个不同阈值下可回答(“已知”)查询的召回率与无法回答(“未知”)查询的拒绝率:

| Threshold | Known-query recall | Unknown-query rejection |
| --------: | -----------------: | ----------------------: |
|      0.20 |               100% |                      0% |
|      0.25 |               100% |                      0% |
|      0.30 |               100% |                     50% |
|      0.35 |               100% |                     50% |
|      0.40 |               100% |                     50% |
|  **0.45** |           **100%** |                **100%** |
|      0.50 |               100% |                    100% |
|      0.55 |               100% |                    100% |

在这个数据集上,0.45是第一个既能保留所有已知查询又能拒绝所有未知查询的阈值,因此在测试的所有数值中表现最佳。但这个数值并不具有通用性——相似度得分会受到嵌入模型、语料库、查询表述以及检索设置的影响,不同模型的得分范围差异极大。此外,以50%为间隔设置的拒绝率也表明未知查询的数量非常少,因此在实际应用中需要更大量的标注数据才能可靠地确定该阈值。真正可迁移的是方法本身:通过测量已知查询和未知查询的检索表现,依据实际数据而非直觉来选择阈值。

检索与排序是不同的任务

假设检索返回了20个候选项。它已经完成了任务:找到了20段很可能相关的文本。还有一个问题需要解决:在这20个候选项中,哪5个最适合作为回答这个特定问题的上下文?这就是重新排序要完成的工作。

检索功能旨在从大量数据中尽可能多地找到相关结果,从而将大约10,000个文本片段缩小为一个可处理的候选集:

10,000 chunks
      ↓
retrieval
      ↓
50 candidates

随后,重新排序功能会更仔细地重新评估这个较小的候选集,通常会使用一个模型同时读取问题与每个候选项,并保留最相关的几个:

50 candidates
      ↓
reranker
      ↓
5 strongest candidates

现在的处理流程如下:

Question
   ↓
Embedding
   ↓
Vector / Hybrid Search
   ↓
Candidate Set
   ↓
Reranking
   ↓
Best Context
   ↓
LLM

语义搜索无法匹配精确术语

嵌入模型在理解含义方面表现优异,但企业数据中有很多术语的价值恰恰在于其精确的拼写形式:

INC-48271
ERR_CONNECTION_RESET
POL-104
AWS us-east-1
customer_12345

在对包含精确代码 ERR_CONNECTION_RESET 的内容块与普通网络相关段落进行排序时,嵌入模型能够识别出查询涉及连接错误问题。

混合检索结合了两种信号

标准的解决方案是混合检索,即同时执行语义搜索和词汇搜索:

Semantic Search
+
Keyword / Lexical Search

针对同一问题会同时进行这两种搜索,其结果会被合并为一个候选集,通常会采用某种融合方法来结合两种排序结果:

Question
                    │
          ┌─────────┴─────────┐
          ↓                   ↓
   Semantic Search      Keyword Search
          │                   │
          └─────────┬─────────┘
                    ↓
              Candidate Set

该系统能够处理同义表述的问题并实现语义相似度匹配,同时也能对标识符进行精确术语匹配。

面向生产的处理流程

当所有阶段都就位后,完整的处理流程如下:

Documents
    ↓
Semantic Chunking
    ↓
Embeddings
    ↓
Vector / Hybrid Retrieval
    ↓
Relevance Filtering
    ↓
Reranking
    ↓
LLM
    ↓
Answer + Sources
    ↓
Evaluation + Observability

模型不再直接位于向量数据库之后。现在,一个真正的检索架构介于用户与大型语言模型之间。如需更深入地了解排序阶段及其延迟带来的价值,请阅读我们关于为何重新排序必须弥补其延迟成本的文章。

值得首先构建的基准方案

了解这些权衡的一种好方法是逐步构建。一个简单的基准方案可以结合 Python、FastAPI、OpenAI 的嵌入模型与大型语言模型,以及 Pinecone 作为向量存储,并包含以下功能:

  • 考虑标题信息的分块处理及分块元数据
  • 支持配置top_k值的语义检索功能
  • 相似度过滤机制
  • 来源标注功能
  • 检索效果评估功能

其处理流程为:

Question
   ↓
Embedding
   ↓
Pinecone Retrieval
   ↓
Top-K Candidates
   ↓
Similarity Threshold
   ↓
Relevant Context
   ↓
LLM
   ↓
Answer + Sources

接下来的自然步骤是引入混合检索与重排序机制,并使用相同的评估集将它们与基准方案进行比较,这样就能实际衡量每一项改进而非仅凭推测。

评估系统的可靠性

“聊天机器人能正常工作吗?”并非一个有用的问题。应将其拆解为可衡量的维度:

  • 检索质量:是否获得了正确的信息?
  • 排序质量:最有用的上下文是否出现在靠前的位置?
  • 依据性:答案是否有检索到的上下文作为支撑?
  • 引用准确性:引用的来源是否能够佐证相关主张?
  • 未知查询处理:系统能否识别出答案不在知识库中的情况?
  • 延迟:检索与生成整个过程需要多长时间?
  • 成本:每次查询的花费是多少?
  • 目标从“该应用能否回答问题?”转变为“我们能否衡量检索架构的可靠性?”

    关键要点

    • RAG并不仅仅是让大语言模型访问文档;真正的难点在于决定检索什么、信任什么、传递什么以及何时拒绝。
    • top_k只能保证数量而非相关性,因此需要根据自身数据设定阈值来筛选候选项。
    • 混合搜索能够捕捉到嵌入向量所模糊的精确标识符,而重排机制则可将广泛的候选集转化为精准的上下文。
    • 答案的质量在模型看到任何上下文之前就已基本确定:更好的上下文能带来更优质的答案以及更可靠的系统。
    • 应将生产环境中的RAG视为具有可衡量阶段的架构问题,而非单纯的LLM集成任务。

    相关阅读