RAG检索召回率低调优:分块策略、重排序
RAG(检索增强生成)召回率低,往往不是模型问题,而是检索链路中的分块、排序或检索方式没调好。
本文按照“先定位、再调分块、加重排、做混合检索”的顺序,带你用可执行的方式提升召回率,全程不需要改大模型,只要调整检索服务即可。
先定位:召回率低是“没召回”还是“召回错”
动手调优前,先跑一次检索测试,确认瓶颈在哪。
- 准备几组带标准答案的测试问题,数量不用多,20条左右足够。
- 用当前RAG系统的检索接口,打印出每道问题召回的前5条片段。
- 人工判断:是相关片段根本没进结果,还是进了但排在后面。
如果相关片段完全没出现,优先检查分块和检索方式;
如果出现了但排位靠后,优先调重排序。
这一步能避免盲目调参。
分块策略:让片段更贴合问题粒度
分块大小和重叠直接影响召回命中。
常见做法是按固定字符切分,但不同文档类型需要不同参数。
调整块大小和重叠率
先看看当前分块配置。
以LangChain的RecursiveCharacterTextSplitter为例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?", ".", "!"]
)
- chunk_size 建议从 256 到 800 之间测试。代码类或结构清晰的文档可以稍小,政策法规、技术文档建议 400-600。
- chunk_overlap 保留 10%-20%,避免关键句子被拦腰截断。
- 如果文档里有明确的章节标题,把标题拼进每个块的开头,能显著提升命中。
按语义边界分块
固定长度切分容易把完整逻辑拆散。
可以先用Markdown标题、段落或句子做一级分隔,再对过长段落做二次切分。
推荐的做法:
- 先按
\n\n分段,再对超过chunk_size的段做递归切分。 - 尽量让每个块包含一个完整的知识点,而不是机械数 tokens。
调整后重新跑测试集,记录召回率变化。
如果相关片段从无到有,说明分块粒度已更贴合问题。
重排序:把高相关片段提到最前
分块解决了“能不能召回”,重排序解决“召回后排序准不准”。
当前主流做法是接入交叉编码器Rerank模型,比如bge-reranker-v2-m3。
集成Rerank服务
以本地部署为例,用FlagEmbedding加载模型:
from FlagEmbedding import FlagReranker
reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True)
# 对检索结果重排
pairs = [[query, doc] for doc in retrieved_docs]
scores = reranker.compute_score(pairs)
实际集成时,让RAG系统先召回Top 20-50条,再用Rerank模型截取Top 5,效果比直接向量检索Top 5好很多。
Rerank服务建议独立部署,避免推理阻塞主链路。
重排注意事项
- Rerank模型有最大输入长度限制,超长片段需截断或按句子拆开打分。
- 分数阈值要按业务数据验证,不要照搬默认阈值。
- 如果召回结果本身质量差,重排救不回来,必须回头调分块或检索方式。
混合检索:向量 + 关键词互补
向量检索擅长语义相似,但对专有名词、精确编号不敏感。
混合检索把BM25关键词检索和向量召回融合,能显著提升“精确命中”场景的召回率。
常见融合方式:RRF
RRF(Reciprocal Rank Fusion)是简单有效的排序融合方法。
假设向量检索和BM25各返回一个排名列表,对每个文档计算:
score = 1 / (60 + rank_vector) + 1 / (60 + rank_bm25)
60是常数项,也可以换成50或100。
按融合分排序后取Top N。
在Milvus和Elasticsearch中实现
如果你用Milvus做向量检索,用Elasticsearch做关键词检索,可以在应用层先分别查,再在代码里做RRF融合。
伪代码如下:
vector_results = milvus_search(query, top_k=20)
bm25_results = es_search(query, top_k=20)
fused = rrf_fusion(vector_results, bm25_results)
也可以直接用Elasticsearch的rank_feature或rrf查询(建议以所用ES版本官方文档为准)。
融合后重新跑测试集,重点看原来漏掉的精确编号、型号、术语是否回来了。
常见问题与避坑
为什么调了分块召回率反而下降?
块越小,上下文越碎片化;
块越大,噪声越多。
每次只改一个参数,用同一测试集对比,不要同时动多个变量。
Rerank模型很慢怎么办?
缩短输入片段数量,先向量召回Top 20再做重排,不要对全库重排。
同时可以换轻量Rerank模型或对长文档按句切分后并行打分。
混合检索结果不稳定?
检查向量检索和关键词检索的Top K是否合理,以及融合常数的设定。
建议先在离线测试集上跑一遍,确定稳定参数后再上线。
验证调优效果
用同一批测试问题,对比调优前和调优后的召回率、命中率、排名位置。
具体指标:
- Recall@5:相关片段出现在Top 5的比例。
- MRR(平均倒数排名):第一个相关片段位置越靠前越好。
- 端到端问答质量:检索改善后,生成答案是否更准确。
最后,如果生产环境使用云服务器部署检索服务,建议先在小规格实例上验证,确认资源占用和响应延迟后再扩容。
调优过程要保留每一轮参数记录,方便回滚和持续优化。
如果你正在处理RAG检索召回率低调优,建议先按本文步骤完整执行,再根据自己的文档类型和业务场景做微调;
遇到异常时优先回看避坑和高频问题部分。