超越Top-K:RAG中的相关性阈值、混合搜索与重排序
了解为何向量数据库与大型语言模型结合并不能构成成熟的RAG系统,以及分块、相似度阈值、混合搜索、重排序和评估机制如何填补这一缺陷。
检索增强生成通常被描述为三步流程:查找与问题相关的文档,将其交给语言模型,再由模型生成答案。这个过程看似简单,但要确保其可靠性却并非易事。那种直接将嵌入搜索与大型语言模型相连的流程,在上下文不足时会给出自信的答案,会忽略精确的标识符,而在知识库中没有相关内容时则会编造答案。正是在这些方面,这种简单的设计会出问题,而从结构感知的分块处理到可量化的评估等各个阶段,则能将其转变为值得信赖的检索架构。
简单的流程及其隐含的假设
大多数教程所采用的基准实现方式如下:将文档分割成多个块,嵌入这些块,存储向量;在查询时嵌入问题,获取距离最近的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集成任务。
相关阅读
- 结合pgvector、BM25与交叉编码器重排器的混合RAG检索方案 — 了解为何纯向量搜索无法识别零件编号和错误代码,以及如何在LangChain中结合pgvector、BM25与重排技术实现精准的RAG检索。
- 合理选择LLM规模:基于任务负载的路由、检索与评估方法 — 学习如何根据工作负载选择小型或大型语言模型,衡量每项成功任务的成本,并优先运用路由、RAG、缓存与验证技术。
- 设计基于实体的RAG流程:分块、过滤与流式处理 — 详细介绍基于实体的RAG架构:考虑结构的文本分块、安全的标记分割、三阶段检索过滤、结果重组、提示词设计以及流式处理方式。