RAG(检索增强生成)里,检索这一步往往比看起来更关键。单靠向量语义检索能解决不少问题,但一到复杂问答、长文档或者结构化内容,单一路径就容易露出短板。模块化 RAG 之后,检索层也开始分化出更多做法。这里挑两种更常见、也更值得实际项目里考虑的模式:融合检索(Fusion Retrieval)和递归检索(Recursive Retrieval)。
融合检索(Fusion Retrieval)
融合检索的思路不复杂:同一个问题走多条检索路径,把结果汇总后再排一次序。它不是追求'某一种检索最好',而是承认不同检索方式擅长的方向不一样。语义检索找相关上下文,关键词检索补精确命中,图谱或摘要索引则适合补关系和结构信息。单独看都不完美,拼起来通常更稳。
多路检索通常怎么做
常见的实现方式大致有三类。
- 问题重写或扩展:先用 Query Rewriter、Query Transform 之类的组件把原问题改写成几个不同说法,再分别检索。命中的 chunks 经过重排后取 Top-K。这个办法很常见,收益也直接,代价是多跑几次检索。
- 多种索引并行检索:同一个问题同时查向量索引、关键词索引,必要时再加知识图谱索引或摘要索引。它的优点是覆盖面更广,缺点也明显,链路一长,延迟和维护成本都会上来。
- 问题扩展 + 索引扩展:前两种一起用。召回会更全,但系统压力也最大。这个方案不是不能做,只是上线前最好先看业务到底需不需要这么'铺开'。很多场景里,简单的多查询加重排已经够用了。
关键组件和一个 LangChain 示例
在 LangChain 和 LlamaIndex 里,这类能力都不算冷门:重写器、检索器、重排器基本都有现成组件,自己组合就行。
- 查询扩展:可以自己调用 LLM 实现,也可以用框架里的 QueryTransform 之类组件。
- Reranker:可以自己写 RRF,也可以接 Cohere Reranker 这类专门模型。
- 检索融合:有的框架已经提供了融合检索器,比如 LlamaIndex 的
QueryFusionRetriever。
一个典型的 LangChain 写法大概是这样:
from langchain.retrievers import ContextualCompressionRetriever, MultiQueryRetriever
from langchain.vectorstores import FAISS
from langchain.llms import OpenAI
from langchain.embeddings import HuggingFaceEmbeddings
# 初始化向量存储和检索器
embeddings = HuggingFaceEmbeddings()
db = FAISS.load_local("./faiss_index", embeddings)
llm = OpenAI(temperature=0)
# 创建多路查询检索器
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=db.as_retriever(), llm=llm
)
# 执行查询
query = "如何部署大模型?"
relevant_docs = multi_query_retriever.get_relevant_documents(query)
如果想再稳一点,可以接一个 Reranker。RRF 的思路就是把不同检索源里的排名换算成分数再求和,越靠前权重越高。常见形式是 Score = sum(1 / (rank + k)),其中 k 是平滑系数,通常取 60 左右。


