很多人做 RAG,第一反应是:“我已经把文档向量化了,为什么还是搜不准?”
问题通常不在大模型,而在检索。RAG 的核心不是把所有文档都塞给模型,而是在用户问题进来后,从知识库里找到最能支撑答案的证据。证据找错了,模型再强也只能“认真胡说”。
这一章重点讲清楚几件事:关键词检索和向量检索到底有什么区别?为什么生产环境很少只用纯向量检索?混合检索为什么要用 RRF?Rerank 又解决什么问题?
一、检索要解决的核心问题
检索的本质很简单:给定一个用户问题,从海量文档中找出最相关的几条。
但“相关”有两种完全不同的理解。第一种是字面相关,也就是查询词和文档里的词重叠;第二种是语义相关,也就是表达不同,但意思接近。
比如用户问“苹果手机怎么截图”,文档里写的是“iPhone 如何截屏”。从字面看,“苹果手机”和“iPhone”不一样,“截图”和“截屏”也不一样;但从语义看,它们说的是同一件事。
这就是为什么 RAG 里会同时出现关键词检索、向量检索、混合检索、Rerank 等多种策略。它们不是重复造轮子,而是在解决不同类型的“相关”。
二、关键词检索:字面匹配,靠统计
关键词检索的代表是 BM25。它的核心不是“理解意思”,而是判断查询词在文档里有没有出现、出现得多不多、这个词在全库里稀不稀缺。
可以把它想成一个图书管理员:他给每个词都建了一张卡片,记录这个词出现在哪些文档里。用户来查“手机 截图”,系统会快速找到包含这些词的文档,再按相关性排序。
BM25 的优势非常明显:只要查询里有产品型号、人名、版本号、代码、法规条款、缩写,它通常比向量检索更稳。比如“M4 Pro”“CUDA 12.4”“RAG”“iPhone 15 Pro Max”,这些词只要文档里出现,BM25 很容易精准命中。
它的短板也很明显:不懂同义词。用户搜“截图”,文档写“截屏”;用户搜“报销”,文档写“费用 reimbursement”;词面不重叠时,BM25 很容易漏召回。
# 用 rank_bm25 做关键词检索的极简示例from rank_bm25importBM25Okapi corpus=[["苹果","手机","截图","方法"],["iPhone","截屏","教程"],["安卓","手机","拍照"],]bm25=BM25Okapi(corpus)query=["苹果","手机","截图"]scores=bm25.get_scores(query)print(scores)# 每篇文档的 BM25 分数三、向量检索:语义匹配,靠 Embedding
向量检索的核心思路是:先用 Embedding 模型把文本变成一串数字向量,再用向量距离判断语义是否接近。
在这个空间里,“苹果手机怎么截图”和“iPhone 如何截屏”虽然词面不同,但意思相近,所以向量距离会更近;“数据库索引优化”和“手机截屏教程”虽然都可能包含技术词,但语义距离会更远。
Embedding 把文本投影到语义空间,语义相近的文本距离更近。
向量检索最擅长解决“换一种说法”的问题,比如同义词、近义词、口语化表达、概念相关问题。用户不需要说出文档里的原词,系统也能找到大致相关的内容。
但向量检索不是万能的。它对精确词不如 BM25 稳,尤其是产品型号、版本号、代码、参数、人名、专有名词。比如“Pro Max 256GB”和“Pro 128GB”在语义上很近,但业务上可能完全不同。
向量检索通常使用 ANN 索引快速找近邻,用速度换取可接受的召回精度。
# 伪代码:向量检索的基本过程query_vector=embedding_model.embed_query("iPhone 如何截屏")results=vector_store.search(vector=query_vector,top_k=20,filter={"doc_type":"help_center"})foriteminresults: print(item.score, item.text[:80])四、关键词检索和向量检索的核心区别
如果只记一句话:BM25 负责精确命中,向量检索负责语义召回。
两者不是谁更高级的问题,而是各自解决的问题不同。BM25 像“按字找”,向量检索像“按意思找”。生产级 RAG 如果只用一种方式,通常都会有明显盲区。
五、混合检索:两路都跑,合并取长补短
既然 BM25 和向量检索各有盲区,最自然的工程方案就是:两路都跑。
用户问题进来后,一路走 BM25,保证专有名词、编号、代码、版本号不丢;另一路走向量检索,保证同义词、口语表达、语义相关内容能召回。最后把两路结果去重、融合、排序。
混合检索通常把 BM25 和向量检索并行执行,再用融合算法合并结果。
这里有一个关键点:不能简单把 BM25 分数和向量相似度相加。因为二者分数体系完全不同。BM25 是统计分数,可能是任意正数;向量相似度常见是余弦值,通常在 -1 到 1 或 0 到 1 的区间。直接加权就像把摄氏度和公里数加在一起,数学上能算,业务上没意义。
所以工程上常用 RRF,也就是 Reciprocal Rank Fusion。它不看原始分数,只看每路结果的排名。一个文档如果在 BM25 和向量检索里都排得靠前,它最终排名就会很高。
RRF 用排名倒数融合多路检索结果,适合分数体系不同的召回通道。
def reciprocal_rank_fusion(results_list,k=60):""" results_list: 多路检索结果,每路是按相关性排序的 doc_id 列表 k: 平滑参数,常用60,避免第一名权重过大""" scores={}forresultsinresults_list:forrank, doc_idinenumerate(results,start=1): scores[doc_id]=scores.get(doc_id,0.0)+1.0/(k + rank)returnsorted(scores.items(),key=lambda x: x[1],reverse=True)vector_results=["doc_a","doc_b","doc_c"]bm25_results=["doc_b","doc_d","doc_a"]merged=reciprocal_rank_fusion([vector_results, bm25_results])print(merged)六、Rerank:召回之后,还要精排
混合检索解决的是“候选尽量别漏”。但候选多了以后,噪声也会增加。Rerank 解决的就是“谁更应该排在前面”。
典型做法是两阶段:第一阶段用 BM25 / 向量检索快速召回 Top-50 或 Top-100;第二阶段用 Reranker 对 query-document 逐对判断,重新排序,最后只把 Top-5 或 Top-10 放进 Prompt。
为什么不一开始就用 Reranker?因为 Cross-Encoder 或 LLM 评审成本高、延迟高,不能直接对全库扫描。它适合做精排,不适合做大规模初筛。
# 伪代码:召回 + Rerank + Prompt 组装query="M4 Pro 芯片参数是多少?"bm25_docs=bm25_retriever.search(query,top_k=50)vector_docs=vector_retriever.search(query,top_k=50)candidates=rrf_merge([bm25_docs, vector_docs],top_k=80)ranked_docs=reranker.rerank(query, candidates,top_k=8)context=build_context(ranked_docs)answer=llm.generate(question=query,context=context)七、检索前的 Query 处理:别让坏问题直接进检索器
很多 RAG 系统搜不准,不是因为向量库差,而是用户问题本身太短、太口语、太含糊。
比如用户问“这个怎么弄?”如果没有上下文,检索器根本不知道“这个”指什么。再比如用户问“报销有什么要求”,文档里可能写的是“费用 reimbursement policy”,直接检索就可能漏。
因此,在线 RAG 常在检索前增加 Query Rewrite、Multi-Query、HyDE、Decomposition、Self-Query 等处理,让检索器看到更适合搜索的问题。
Query Transform 让用户问题更适合检索,尤其适合复杂和模糊问题。
这些策略不能无脑全开。Multi-Query 会增加召回量,也会增加 Rerank 成本;HyDE 对抽象概念问题有帮助,但对精确事实问题可能引入偏差;问题拆解适合多跳查询,但简单 FAQ 用它反而浪费延迟。
八、不同场景怎么选检索策略
检索策略不是越复杂越好。正确的做法是先判断问题类型,再选择合适的召回方式。
如果问题里有强精确词,比如型号、订单号、法律条款、函数名,优先用 BM25;如果问题是自然语言描述、同义词很多,优先向量检索;如果是企业知识库,大多数情况下建议直接上混合检索;如果候选噪声大,再加 Rerank。
检索策略选型可以从问题形态出发,而不是一味堆复杂度。
九、生产级 RAG 检索链路怎么搭
一个可上线的 RAG 检索系统,通常不是一个 vector_store.similarity_search 这么简单。它至少要包含 Query 处理、多路召回、过滤、融合、精排、证据压缩、引用校验和日志追踪。
生产环境还要考虑权限过滤、租户隔离、缓存、超时降级、冷启动、索引更新、召回效果评测和线上错误分析。否则系统刚 Demo 时看起来很准,一到真实业务就开始不稳定。
生产级在线检索链路需要质量、延迟、成本和可观测性一起设计。
十、怎么判断检索方式真的变好了
检索优化不能只靠“感觉答案更像了”。正确做法是先构建一批黄金问答集,每个问题标注正确证据,再分别评估召回和生成。
常用指标包括 Recall@K、Hit@K、MRR、nDCG、Rerank 后正确证据位置、引用覆盖率、空召回率、P95 延迟和单次请求成本。
如果只看最终答案,很难定位问题。答案错了,可能是没召回,也可能是召回了但排太后,也可能是 Prompt 截断了,还可能是模型生成时没遵守证据。
十一、常见坑:检索方式越多,不代表系统越准
很多团队做 RAG 优化,第一反应是加策略:加 Multi-Query、加 HyDE、加 Rerank、加 Agentic RAG。结果候选越来越多,延迟越来越高,答案却没有明显提升。
原因是:检索系统的瓶颈不一定在召回数量。很多时候是 Chunk 质量、元数据过滤、Rerank 截断、Prompt 组装、权限过滤、索引更新出了问题。
十二、面试回答模板
如果面试官问:关键词检索和向量检索有什么区别?可以这样回答:
关键词检索以 BM25 为代表,基于倒排索引和词频统计,优势是精确命中强,适合产品型号、专有名词、代码、版本号等场景;短板是无法处理同义词和语义相关表达。
向量检索基于 Embedding,把文本映射到语义空间,通过向量距离找相似内容,优势是能处理同义词、口语化和模糊语义;短板是对精确词、数字、型号不够敏感,解释性也弱。
生产级 RAG 通常不会二选一,而是用混合检索:BM25 和向量检索并行召回,用 RRF 融合排序,再用 Reranker 做精排,最后把高质量证据交给 LLM 生成答案。