【RAG】【retrievers13】相对分数融合和基于分布的分数融合
案例目标
本案例演示了使用QueryFusionRetriever的两种旨在改进互惠排名融合(Reciprocal Rank Fusion)的方法:
- 相对分数融合:由Weaviate提出的算法,对每个结果集应用MinMax缩放器,然后进行加权求和
- 基于分布的分数融合:基于每个结果集分数的均值和标准差进行缩放的方法
通过这两种融合方法,我们可以在不使用额外模型或过度计算的情况下,对多个检索器的结果进行重新排序,从而提高检索质量。
技术栈与核心依赖
核心库
- llama-index-llms-openai
- llama-index-retrievers-bm25
检索与融合
- QueryFusionRetriever
- VectorStoreIndex
- BM25Retriever
- SentenceSplitter
数据处理
- SimpleDirectoryReader
- RetrieverQueryEngine
- nest_asyncio
环境配置
安装依赖
%pip install llama-index-llms-openai %pip install llama-index-retrievers-bm25
环境设置
import os import openai os.environ["OPENAI_API_KEY"] = "sk-..." openai.api_key = os.environ["OPENAI_API_KEY"]
注意:需要设置有效的OpenAI API密钥才能运行此示例。
案例实现
1. 数据准备与索引构建
下载Paul Graham的文章并创建向量索引:
# 下载数据 !mkdir -p 'data/paul_graham/' !wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt' # 加载文档 documents = SimpleDirectoryReader("./data/paul_graham/").load_data() # 创建向量索引 splitter = SentenceSplitter(chunk_size=256) index = VectorStoreIndex.from_documents( documents, transformations=[splitter], show_progress=True )2. 创建检索器
创建向量检索器和BM25检索器,每个检索器返回top-10最相似的节点:
from llama_index.retrievers.bm25 import BM25Retriever vector_retriever = index.as_retriever(similarity_top_k=5) bm25_retriever = BM25Retriever.from_defaults( docstore=index.docstore, similarity_top_k=10 )
3. 相对分数融合实现
使用Weaviate的相对分数融合算法,对每个结果集应用MinMax缩放器,然后进行加权求和:
from llama_index.core.retrievers import QueryFusionRetriever retriever = QueryFusionRetriever( [vector_retriever, bm25_retriever], retriever_weights=[0.6, 0.4], # 向量检索器权重更高 similarity_top_k=10, num_queries=1, # 设置为1以禁用查询生成 mode="relative_score", use_async=True, verbose=True, )
相对分数融合算法首先将每个检索器的分数归一化到[0,1]范围,然后根据权重进行加权求和。这里我们给向量检索器更高的权重(0.6),BM25检索器权重为0.4。
4. 基于分布的分数融合实现
使用基于分布的分数融合算法,根据每个结果集分数的均值和标准差进行缩放:
retriever = QueryFusionRetriever( [vector_retriever, bm25_retriever], retriever_weights=[0.6, 0.4], similarity_top_k=10, num_queries=1, # 设置为1以禁用查询生成 mode="dist_based_score", use_async=True, verbose=True, )
基于分布的分数融合算法使用每个检索器分数的均值和标准差进行标准化,然后根据权重进行加权求和。这种方法可以更好地处理分数分布不均匀的情况。
5. 查询与响应生成
将融合检索器集成到查询引擎中,生成自然语言响应:
# 应用嵌套异步以在笔记本中运行 import nest_asyncio nest_asyncio.apply() # 创建查询引擎 query_engine = RetrieverQueryEngine.from_args(retriever) # 执行查询 response = query_engine.query("What happened at Interleafe and Viaweb?") # 显示响应 from llama_index.core.response.notebook_utils import display_response display_response(response)案例效果
我们比较了两种融合方法在查询"What happened at Interleafe and Viaweb?"时的检索结果:
相对分数融合结果
- Score: 0.60 - You wouldn't need versions, or ports, or any of that crap...
- Score: 0.59 - The UI was horrible, but it proved you could build a whole store...
- Score: 0.40 - We were determined to be Microsoft Word, not Interleaf...
- Score: 0.36 - In its time, editor was one of best general-purpose site builders...
- Score: 0.25 - I kept the code tight and didn't have to integrate with any other software...
基于分布的分数融合结果
- Score: 0.42 - You wouldn't need versions, or ports, or any of that crap...
- Score: 0.41 - The UI was horrible, but it proved you could build a whole store...
- Score: 0.32 - We were determined to be Microsoft Word, not Interleaf...
- Score: 0.30 - In its time, editor was one of best general-purpose site builders...
- Score: 0.27 - To find out, we decided to try making a version of our store builder...
结论:两种融合方法都能有效地结合向量检索和BM25检索的结果,但分数分布略有不同。相对分数融合的分数范围更广(0.07-0.60),而基于分布的分数融合分数更集中(0.18-0.42)。两种方法都能正确识别与Interleaf和Viaweb相关的内容。
生成的响应示例
"At Interleaf, there was a group called Release Engineering that was as large as group writing the software. They had to deal with versions, ports, and other complexities. In contrast, at Viaweb, software could be updated directly on server, simplifying process. Viaweb was founded with $10,000 in seed funding, and software allowed building a whole store through browser without need for client software or command line inputs on server. The company aimed to be easy to use and inexpensive, offering low monthly prices for their services."
案例实现思路
分数融合算法原理
相对分数融合算法
- 从多个检索器获取结果集和分数
- 对每个检索器的分数应用MinMax缩放:
- 计算每个检索器的最小和最大分数
- 将分数归一化到[0,1]范围
- 根据权重对归一化分数进行加权求和
- 按融合分数对结果重新排序
normalized_score = (score - min_score) / (max_score - min_score)fused_score = w1 * norm_score1 + w2 * norm_score2
基于分布的分数融合算法
- 从多个检索器获取结果集和分数
- 对每个检索器的分数应用基于分布的缩放:
- 计算每个检索器分数的均值和标准差
- 使用Z-score标准化分数
- 根据权重对标准化分数进行加权求和
- 按融合分数对结果重新排序
normalized_score = (score - mean_score) / std_devfused_score = w1 * norm_score1 + w2 * norm_score2
QueryFusionRetriever工作流程
QueryFusionRetriever接收多个检索器作为输入,根据指定的融合模式(relative_score或dist_based_score)对结果进行融合。 它首先并行执行所有检索器获取结果,然后应用相应的融合算法对分数进行归一化和加权求和, 最后返回融合后的top-k结果。这种设计使得在不使用额外重排序模型的情况下, 能够有效结合不同检索器的优势。
扩展建议
1. 动态权重调整
根据查询类型和内容动态调整不同检索器的权重,例如对关键词密集的查询增加BM25权重,对概念性查询增加向量检索权重。
2. 多种融合算法集成
结合相对分数融合、基于分布的分数融合和互惠排名融合,通过投票或学习机制选择最佳融合结果。
3. 自适应分数归一化
根据检索器分数分布的特点自动选择最适合的归一化方法,提高融合结果的稳定性和可靠性。
4. 检索器性能评估
实现检索器性能的实时评估机制,根据历史表现动态调整融合策略和权重分配。
5. 多模态检索融合
扩展融合算法以支持多模态检索,如文本、图像和音频检索结果的融合。
6. 查询意图感知融合
结合查询意图分析,根据不同的查询意图类型(事实查询、概念查询、比较查询等)选择最适合的融合策略。
总结
相对分数融合和基于分布的分数融合是两种改进互惠排名融合的有效方法,它们能够在不使用额外模型的情况下,有效结合多个检索器的结果。
相对分数融合通过MinMax缩放将分数归一化到[0,1]范围,然后进行加权求和,适合处理分数范围差异较大的情况。基于分布的分数融合则使用均值和标准差进行标准化,能够更好地处理分数分布不均匀的情况。
通过QueryFusionRetriever,我们可以轻松实现这两种融合方法,并将其集成到查询引擎中,生成高质量的自然语言响应。这些技术为构建更强大的混合检索系统提供了坚实的基础,特别适合需要结合语义检索和关键词检索的场景。
