RAG多路召回+重排序+混合检索

发布时间:2026/7/1 18:24:59

RAG多路召回+重排序+混合检索 一、问题导入在做RAG应用时是否遇到过这种情况明明知识库里存了答案但大模型就是答非所问这种问题通常出现在检索这一步只用一个检索器就像用渔网捞针要么网眼太大漏掉关键信息要么网眼太小捞出一堆垃圾举个真实的例子你问“Transformer的注意力机制怎么工作”用关键词检索可能只匹配到“Transformer”这个词他只会返回返回一篇讲电源变压器的文档用向量检索虽然它能理解语义但可能被大量“注意力”“机制”这类泛泛而谈的文档淹没所以我们就使用了RAG里提升检索效果的三个关键技术多路召回、重排序、混合检索二、多路召回“鱼”和“熊掌”兼得2.1什么是“路”核心多路召回就是同时用多个检索器把各自觉得相关的候选文档都“召回”回来常见的两“路”关键词检索代表BM25它是基于词频统计的像搜索引擎的老祖宗擅长精确匹配专有名词、产品型号、代码报错信息但它的缺点是不懂同义词和语义你搜“笔记本”它就不会想到“笔记本电脑”向量检索代表Embedding模型向量数据库它是把句子变成高维空间里的坐标语义相近的句子坐标也近它擅长理解模糊意图、跨语言、同义改写但它的缺点是对数字、专名敏感度低容易返回看似相关但实际空洞的“漂亮废话”2.2多路召回怎么实现思路就是同时发起关键词搜索和向量搜索各取前 N 条结果合并成一个候选池。这样一来关键词路就会帮我们捞回精确命中向量路帮我们捞回语义相关核心多路召回的“路”不限于这两种你还可以加入图谱检索、结构化SQL查询等组成三路、四路召回但关键词向量是最基础的“黄金搭档”三、重排序重排序就是把召回的候选文档重新“排排坐”3.1为什么召回了还需要排多路召回合并之后候选文档的数据会翻倍比如各路取10条合并后去重可能剩15条这些文档只是“看起来可能相关”我们需要一个更聪明、更慢但更精准的裁判把它们按真正相关性重新排序这就是重排序3.2重排序模型的本质核心重排序模型是一个交叉编码器它是直接把“查询文档”拼接起来交给模型让模型深度理解两者是否真正匹配这和向量检索的双编码器分别编码查询和文档再算相似度有本质不同交叉编码器能捕捉到细粒度的交互但速度慢只适合处理少量候选常见开源模型bge-reranker-v2-m3、Cohere Rerank、Jina Reranker。线上用通常选 API本地部署可选 FlagEmbedding 等3.3重排序流程3.3.1把多路召回的候选文档去重3.3.2将每个文档和查询组成一对输入Rerank模型3.3.3模型会给每对打分相关性分数3.3.4按照分数从高到低排序截取前K条送入大模型这样最终交给LLM的上下文就全面且精准四、混合检索混合检索就是把多路召回与重排序串成一条流水线核心混合检索不是简单的“用多个检索器”而是一套多路召回 → 融合去重 → 重排序 → 截断的标准化流水线当然在融合多路结果时有两个关键分数归一化向量检索的相似度分如0.85和 BM25 的分数如23.7不在一个量级不能直接加减常用倒数秩融合RRF来重新算分score_doc SUM( 1 / (k rank_of_doc) )其中k是一个常数通常取60这个方法无视原始分数只看各路的排名公平又简单去重同一文档可能会被多路召回保留最高排名或合并分数就可至此整条增强检索链路就清晰了查询-关键词向量两路召回 → RRF合并去重 → Rerank精细打分 → 取Top K文档 → 拼接指令给LLM生成答案五、实操Python可以自行改为Java用LangChain搭一个混合检索Rerank流水线基于LangChain和本地组件来实现5.1准备环境pip install langchain langchain-community chromadb sentence-transformers rank_bm25 pip install FlagEmbedding # 用于本地Rerank模型可选5.2准备文档和向量库假设有5篇简单文档documents [ Transformer 架构基于自注意力机制。, 注意力机制允许模型关注输入的不同部分。, BM25是一种基于词频的检索算法。, 苹果公司发布了新的MacBook Pro。, 苹果是一种常见的水果富含维生素。 ]建立向量索引和BM25索引from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma from rank_bm25 import BM25Okapi import numpy as np # 向量索引 embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vectorstore Chroma.from_texts(documents, embeddings) # 关键词索引BM25 tokenized_docs [doc.split() for doc in documents] bm25 BM25Okapi(tokenized_docs)5.3定义多路召回器LangChain 的EnsembleRetrievr 可以轻松组合多个检索器内部会用 RRF 融合。但我们需要自定义一下把 BM25 包装成一个检索器from langchain.schema import BaseRetriever, Document from typing import List class BM25Retriever(BaseRetriever): # 切词需与索引时的切法一致 def _get_relevant_documents(self, query: str) - List[Document]: tokenized_query query.split() scores bm25.get_scores(tokenized_query) # 按分数取 Top K top_n np.argsort(scores)[::-1][:3] # 召回3条 return [Document(page_contentdocuments[i], metadata{}) for i in top_n] # 向量检索器 vector_retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 使用EnsembleRetriever混合 from langchain.retrievers import EnsembleRetriever ensemble_retriever EnsembleRetriever( retrievers[vector_retriever, BM25Retriever()], weights[0.5, 0.5], # 这里权重影响RRF中的k其实EnsembleRetriever内部用加权RRF源码可查 c60 # RRF中的常量k )EnsembleRetriever内部实现RRF算法我们只需要传入检索器列表5.4假如重排序器可以用FlagEmbedding的本地Rerankerfrom FlagEmbedding import FlagReranker reranker FlagReranker(BAAI/bge-reranker-v2-m3, use_fp16True) # 自定义一个 Rerank 函数 def rerank_documents(query: str, docs: List[Document], top_k: int 2): pairs [[query, doc.page_content] for doc in docs] scores reranker.compute_score(pairs) # 按分数排序 sorted_indices np.argsort(scores)[::-1] sorted_docs [docs[i] for i in sorted_indices[:top_k]] return sorted_docs5.5组装完整流水线def hybrid_search(query: str): # 1. 多路召回 RRF融合 candidate_docs ensemble_retriever.get_relevant_documents(query) print(f召回了 {len(candidate_docs)} 篇文档) # 2. 重排序 final_docs rerank_documents(query, candidate_docs, top_k2) # 3. 拼接上下文可以喂给LLM context \n.join([doc.page_content for doc in final_docs]) return context # 测试 query 注意力机制 print(hybrid_search(query))运行后你会看到先召回多路文档再经Rerank筛选出和“注意力机制”最相关的两条过滤掉“苹果”相关的不相关文档六、问题总结6.1多路召回的结果怎么合并最合理优先用 RRF倒数秩融合它不依赖原始分数的量纲各路平等竞争,简单拼接再加去重只能算“合并”融合的质量差很多6.2重排序模型太慢实时性不强怎么办6.2.1严格控制多路召回的候选数量比如各路只取 10-20 条融合后控制在 20 条以内再送入 Rerank6.2.2选用轻量模型或 APICohere 的 Rerank 端到端很快本地部署可以用 onnx 加速6.2.3如果仍不够考虑放弃重排序只用 RRF 融合后直接截断虽然精度稍降但速度飞快6.3如何选择Embedding模型和Rerank模型6.3.1文本嵌入可选 BGE、Jina、M3E 等中文优化模型6.3.2Rerank 模型选与 Embedding 同一系列通常配合更好如 bge-reranker 配 bge-embedding核心向量模型和 Rerank 模型最好用同语料训练或同一团队产出避免“语义鸿沟”6.4混合检索适合所有RAG场景吗不是。如果你的知识库非常垂直且结构化纯关键词检索可能就够如果文档全是短句问答对单路向量也能胜任。混合检索的价值在于通用和未知场景——当你不知道用户会怎么提问时它最保险6.5如何评估混合检索效果自己做一个小的标注数据集查询-相关文档对计算 Hit Rate命中率 和 MRR平均倒数排名。比如 Top5 命中率是否比单路提升。在复盘时可以用少量 case 手动验证避免过早陷入指标调参总结多路召回负责“海选广撒网”重排序负责“精选优中优”混合检索把它们串成一条工业级流水线

相关新闻