Soup's Blog

Back

RAG实战(五)重排序与查询集成Blur image

代码开源Github地址

RAG重排序与查询集成:提升检索精度的关键技术#

在前面的章节中,我们学习了如何优化文档索引和检索策略。但是,初次检索的结果往往不够精确。本章将深入探讨如何通过重排序和查询集成技术进一步提升检索质量。

为什么要重排序?#

向量检索的局限性

场景:

用户查询: "Python中如何处理异常?"

向量检索结果(按相似度排序):
1. 文档A: "Python异常处理机制...try-except..." (相似度: 0.85)
2. 文档B: "Python中的错误类型...Exception类..." (相似度: 0.83)
3. 文档C: "Python编程基础...变量、函数..." (相似度: 0.82)
python

问题分析:

  • → 文档A最相关,排序正确 ✅
  • → 但相似度差异很小(0.85 vs 0.83 vs 0.82)
  • → 向量相似度不能完全反映真实相关性
  • → 文档C不太相关但相似度也不低

解决方案:重排序 🎯

  • → 使用更强大的模型重新评估文档相关性
  • → 考虑查询和文档的精确匹配度
  • → 调整排序,确保最相关的文档排在前面

本章技术概览#

技术核心功能优势复杂度推荐指数
交叉编码器重排序精确相关性评估准确度最高⭐⭐⭐⭐⭐⭐⭐⭐
倒数排序融合(RRF)多结果融合鲁棒性强⭐⭐⭐⭐⭐⭐
多查询检索多角度查询召回率高⭐⭐⭐⭐⭐⭐
查询扩展语义扩充覆盖面广⭐⭐⭐⭐⭐
混合检索向量+关键词全面性好⭐⭐⭐⭐⭐⭐⭐⭐

Part 1: 交叉编码器重排序 - Cross-Encoder Reranking#

1.1 核心概念#

双编码器(Bi-Encoder) vs 交叉编码器(Cross-Encoder):

双编码器(用于初始检索)

查询 → 编码器 → 查询向量 ──┐
                            ├→ 余弦相似度
文档 → 编码器 → 文档向量 ──┘

优点:快速,可预先计算文档向量
缺点:查询和文档独立编码,无法捕捉细粒度交互
plaintext

交叉编码器(用于重排序)

查询 + 文档 → 编码器 → 相关性分数

优点:查询和文档联合编码,更精确
缺点:慢,无法预先计算
plaintext

1.2 工作流程#

RAG + 重排序流程

1. 初始检索(双编码器)
   → 从大量文档中快速检索top-k个候选
   → 例如:从10000个文档中检索top-50

2. 重排序(交叉编码器)
   → 对top-k个候选重新评分
   → 更精确地排序

3. 返回最终结果
   → 返回重排序后的top-n个文档
   → 例如:返回最相关的top-5
plaintext

1.3 实现本地交叉编码器模型#

1.4 实际应用演示#

运行结果:

1.5 常用交叉编码器模型#

1.6 技术优势与适用场景#

优势:

  • 精确度显著提升:交叉编码器能捕捉查询和文档的细粒度交互
  • 解决语义鸿沟:弥补向量检索的局限性
  • 灵活配置:可根据需求调整初始检索和重排序的比例
  • 质量可控:通过分数阈值控制返回文档的质量

适用场景:

  • 高精度要求的问答系统
  • 法律、医疗等专业领域检索
  • 需要精确匹配的搜索应用
  • 对检索质量要求极高的生产环境

性能考虑: ⚠️

  • 计算开销:重排序会增加响应时间
  • 资源需求:需要加载额外的模型
  • 批量优化:建议批量处理以提高效率

交叉编码器重排序技术通过更精细的相关性评估,显著提升了RAG系统的检索精度,是构建高质量智能问答系统的关键技术之一。


Part 2: 倒数排序融合 - Reciprocal Rank Fusion (RRF)#

2.1 核心概念#

倒数排序融合(RRF)是一种融合多个排序列表的算法,它不需要知道具体的分数,只需要排名。这种方法特别适合融合来自不同检索系统的结果。

2.2 RRF算法原理#

RRF公式

对于文档d,其RRF分数为:

RRF(d) = Σ (1 / (k + rank_i(d)))
plaintext

其中:

  • rank_i(d): 文档d在第i个排序列表中的排名
  • k: 常数,通常取60
  • Σ: 对所有排序列表求和

示例演示

假设有2个排序列表,k=60:

列表1: [DocA, DocB, DocC]  (DocA排名1, DocB排名2, DocC排名3)
列表2: [DocC, DocA, DocD]  (DocC排名1, DocA排名2, DocD排名3)
plaintext

RRF分数计算:

DocA: 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325
DocB: 1/(60+2) + 0        = 0.0161
DocC: 1/(60+3) + 1/(60+1) = 0.0159 + 0.0164 = 0.0323
DocD: 0        + 1/(60+3) = 0.0159
plaintext

最终排序: DocA > DocC > DocB > DocD

2.3 实现RRF融合器#

2.4 使用示例#

运行结果:

RRF融合结果:
1. [RRF分数: 0.0164] 文档A: Python异常处理......
2. [RRF分数: 0.0164] 文档C: 编程基础......
3. [RRF分数: 0.0161] 文档B: 错误类型......
4. [RRF分数: 0.0161] 文档A: Python异常处理......
5. [RRF分数: 0.0159] 文档C: 编程基础......
6. [RRF分数: 0.0159] 文档D: 最佳实践......
plaintext

2.5 实现完整的RRF检索器#

2.6 实际应用演示#

运行结果:

2.7 技术优势与适用场景#

优势:

  • 无需分数归一化:直接使用排名,避免不同系统的分数尺度问题
  • 鲁棒性强:对单个检索器的异常结果不敏感
  • 简单高效:算法简单,计算开销小
  • 可扩展性好:容易集成新的检索系统

适用场景:

  • 多检索系统融合:结合向量检索、关键词检索等不同方法
  • 联邦搜索:融合来自不同数据源的结果
  • 专家系统:结合不同专业领域的检索器
  • 容错系统:需要鲁棒性的生产环境

性能考虑: ⚠️

  • 排名质量依赖:结果质量取决于各个检索器的排名质量
  • 常数选择:k值需要根据具体场景调整
  • 重复文档处理:需要处理不同检索器返回的相同文档

RRF技术通过简单而有效的方法融合多个检索系统的结果,显著提升了检索的鲁棒性和准确性,是构建复杂检索系统的关键技术之一。


Part 3: 多查询检索 - Multi-Query Retrieval#

3.1 核心概念#

多查询检索是一种通过生成多个查询变体来提高检索召回率的先进技术。其核心思路是:

  1. 从单个用户查询生成多个相似但不同的查询
  2. 对每个查询分别进行检索
  3. 融合所有检索结果

3.2 为什么需要多查询?#

问题:单一查询可能不够全面

用户查询: "Python如何读取文件?"

## 可能的相关文档:
- "Python文件读取open()函数"  ✅ 匹配
- "读写文件的最佳实践"        ❌ 可能不匹配(没有"Python"
- "使用pathlib处理文件路径"  ❌ 可能不匹配(没有"读取"
python

解决方案:生成多个查询变体

原始查询: "Python如何读取文件?"

生成的查询变体:
1. "在Python中打开和读取文件"
2. "Python file I/O操作"
3. "使用open()函数读取文件内容"
4. "Python文件处理方法"

→ 不同变体可能匹配不同的相关文档
→ 融合结果,提高召回率
plaintext

3.3 实现使用LLM生成查询变体#

3.4 实际应用演示#

运行结果:

3.5 技术优势与适用场景#

优势:

  • 提高召回率:多个查询变体覆盖更多相关文档
  • 增强鲁棒性:对查询表述的变化不敏感
  • 语义多样性:涵盖不同角度和表达方式
  • 易于集成:可与现有检索系统无缝集成

适用场景:

  • 复杂查询:需要多角度理解的复杂问题
  • 专业领域:技术、学术等专业内容检索
  • 多语言检索:支持不同语言表达方式
  • 容错系统:需要高召回率的应用场景

性能考虑: ⚠️

  • 计算开销:需要执行多次检索操作
  • LLM依赖:查询生成依赖语言模型质量
  • 结果去重:需要有效的融合和去重策略

多查询检索技术通过生成多样化的查询变体,显著提高了检索系统的召回率和鲁棒性,是构建高质量智能检索系统的重要技术之一。


Part 4: 查询扩展 - Query Expansion#

4.1 核心概念#

查询扩展是信息检索中的一种关键技术,旨在通过向原始查询中添加相关术语、同义词或上下文信息来增强查询的语义表示,从而提高检索系统的召回率。其核心思想是弥补用户查询与文档集合中相关文档之间可能存在的词汇不匹配问题。

主要方法:

  1. 基于同义词词典:使用预定义的词典(如 WordNet)添加同义词。
  2. 基于词嵌入:利用词向量模型(如 Word2Vec, GloVe)找到语义相近的词汇。
  3. 基于查询日志:分析历史查询数据,找到经常一起出现的查询词。
  4. 伪相关反馈:假设初次检索返回的顶部文档是相关的,并从中提取扩展词。
  5. 基于LLM的扩展:利用大语言模型强大的语义理解和生成能力,根据查询的意图和上下文生成相关的扩展术语。

本部分将重点介绍基于LLM的查询扩展和伪相关反馈两种高级策略。

4.2 实现基于LLM的查询扩展#

LLM能够深入理解查询的意图和上下文,生成高质量、语义相关的扩展词,而不仅仅是机械地添加同义词。

以下是优化后的 QueryExpander 类,它更加健壮,并提供了更好的提示词和输出处理。

输出内容如下:

Processed prompts: 100%|██████████| 1/1 [00:00<00:00,  5.79it/s]
原始查询: Python机器学习
扩展查询: Python数据分析 OR Python统计分析 OR Python数据挖掘
plaintext

4.3 实现伪相关反馈#

伪相关反馈是一种更高级的查询扩展技术,它利用初次检索的结果来指导查询扩展,特别适合文档库特定的术语和上下文。

输出内容如下:

这种查询扩展方法能够显著提高检索系统的召回率,特别是在处理专业领域查询时,能够更好地理解用户的真实信息需求。


5.1 核心概念#

混合检索结合向量检索(语义搜索)和关键词检索(如BM25),利用两者的优势。

向量检索 vs 关键词检索

## 向量检索(语义搜索) 优点: ✅ 理解语义,能匹配同义词 ✅ 能处理模糊查询
✅ 跨语言能力(多语言模型)

缺点: ❌ 对精确术语匹配不敏感 ❌ 对罕见词或专有名词效果差 ❌ 计算成本高

## 关键词检索(BM25) 优点: ✅ 精确匹配关键词 ✅ 对专有名词、代码等效果好 ✅ 计算快速

缺点: ❌ 不理解语义 ❌ 无法匹配同义词 ❌ 对查询措辞敏感

## 混合检索 = 向量检索 + 关键词检索 🎯 → 结合两者优势 → 适用于大多数场景

5.2 实现向量+BM25混合检索#

输出内容如下:

混合检索通过结合语义理解和关键词匹配,能够在各种查询场景下提供更稳定、更准确的检索结果。自适应权重调整和LLM重排序进一步提升了检索系统的智能性和实用性。


综合实战:完整的高级检索系统#

将所有技术整合成一个系统

输出内容:

📥 加载交叉编码器模型: ./Models/ms-marco-MiniLM-L-6-v2/cross-encoder/ms-marco-MiniLM-L6-v2
🗑️ 已删除旧的 Chroma 集合 'local_rerank'
✅ BM25索引构建完成
plaintext
## 测试不同模式
modes = ["simple", "hybrid", "hybrid_multiquery_rerank", "multiquery"]

question = "Python中如何处理异常?"

for mode in modes:
    print(f"\n{'='*60}")
    print(f"测试模式: {mode}")
    print(f"{'='*60}\n")
    
    result = advanced_system.query(question, mode=mode)
    
    print(f"\n💡 答案:\n{result['answer']}\n")
python

输出内容如下:

实验总结#

重排序: 使用交叉编码器提升精度 RRF融合: 简单有效的结果融合方法 多查询: 提高召回率 混合检索: 结合向量和关键词检索

技术组合建议

检索质量层级:
Level 1: 向量检索 (基础)

Level 2: 混合检索 (向量 + BM25)

Level 3: 混合检索 + RRF融合

Level 4: 多查询 + 混合检索 + RRF

Level 5: 多查询 + 混合检索 + RRF + 重排序 (最强)

根据应用场景选择合适的级别:
- 快速原型: Level 1
- 生产基础: Level 2-3
- 高质量应用: Level 4-5
plaintext
RAG实战(五)重排序与查询集成
http://www.soupcola.top/blog/rag_blogs/rag_blogs-5
Author Soup Cola
Published at 2026年1月31日