RAG(检索增强生成)技术中,R 代表 Retrieval(检索),这一环节对最终生成质量至关重要。基于向量(Vector)的语义检索是最为熟知的基础模式,但在实际应用中,仅使用单一向量检索往往难以满足多样化的复杂需求。在模块化 RAG 的时代,许多新范式与算法都对检索环节进行了大量创新与优化。本文将深入探讨两种在 RAG 应用中可灵活应用的高级检索模式:融合检索(Fusion Retrieval)与递归检索(Recursive Retrieval)。
融合检索(Fusion Retrieval)
融合检索是一种结合多维度检索的方法。简单来说,就是通过多个不同的检索方法进行查询检索,并对召回的结果通过排序算法(如 RRF)重新排序融合后用于后续生成。融合检索可以组合多路不同维度的检索结果,以弥补单个向量索引在检索精确性上的不足。
1. 实现多路检索的方式
在实际应用中,可以根据自身需要选择不同的形式来实现多路检索:
- 基于问题重写与扩展:借助查询重写(Query Rewriter)或查询转换器对输入问题进行扩展,生成多个不同表达形式或不同角度细化的输入问题。对每个问题分别进行检索,然后对召回的知识块(Chunks)通过重排(Reranker)模块进行重新排序,并取最终的 Top-K 用于后续生成环节。
- 基于多种类型的索引:尽管基于高维向量的索引在很多场景下的自然语言语义检索表现不错,但并非全能。例如,你可能想借助知识图谱索引来更精确地获取实体之间的复杂关系;或者借助树状的摘要索引来更好地回答概要性问题。因此,可以同时通过多路不同类型的索引(如向量索引与关键词索引)对输入问题进行检索,并对召回的知识块进行重排序处理后获取 Top-K。
- 基于复合方案的多路检索:这是对上面两种方法的组合。即同时借助于问题扩展与索引扩展来实现更多路的知识召回,再通过重新排序获得 Top-K。这种组合方法由于召回了更多的 Chunks,有利于获取更相关的知识,但同时也增加了系统性能的消耗与模型使用的成本,在实际使用时需要根据测试结果进行取舍。
2. 融合检索的关键技术与代码示例
实现融合检索并不复杂,不管在 LangChain 还是 LlamaIndex 框架中,都有转换器(Rewriter)、检索器(Retriever)、排序器(Reranker)的概念与组件,可以自行组合来实现融合检索。
- 查询扩展:借助 LLM 自行实现;或者借助已有组件,比如 LlamaIndex 中的 QueryTransform 组件。
- Reranker:自行实现 RRF(Reciprocal Rank Fusion)算法函数,或者借助 Cohere Reranker 这样的专业排序模型实现。
- 检索融合:扩展已有的 Retriever 组件,实现自定义融合检索器;有的框架有现成的融合检索器,比如 LlamaIndex 的
QueryFusionRetriever。
以下是一个典型的融合检索器扩展的 Python 代码示例(基于 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 \frac{1}{rank + k}$,其中 $k$ 为平滑系数(通常设为 60)。
递归检索(Recursive Retrieval)
相对于易于理解的融合检索,另外一种较复杂的检索方法是递归检索。想象一下,如果你想在一大堆书中找到你所关注的一段文字,最快的方法不是简单粗暴的逐本翻阅,你可能会这么做:做一些基本过滤,查看书籍简介定位少量书籍,最后在几本书中借助目录找到内容。这本质上就是一种递归检索。
在不同层次上构建 Chunks 节点与检索器(比如摘要层与内容层、主要内容层与嵌入内容层),并建立层次之间的链接关系,使得能够在每次检索时自动实现向下递归探索,直至达到结束条件。
1. 链接形态与应用场景
从一级的 Chunks 链接到的二级对象引用可以是以下几种:
- 一个可以直接读取内容的二级 Chunk 块:本质是上一个 Chunk 关联查找的过程。常见应用场景包括父子块(小 Chunk 保存大 Chunk 引用)、摘要 Chunk 保存详细内容 Chunk 引用、假设性问题 Chunk 保存内容 Chunk 引用。这种方式主要用于解决 Chunk 的语义精确性与丰富性之间的矛盾。
- 一个可以检索出多个二级 Chunk 块的检索器:通过检索出来的一级 Chunk 找到对应的二级检索器,并递归调用这个检索器再次检索。典型场景是在多文档问答中,通过生成摘要文档实现分层过滤,降低单一层次检索下的精度不足和知识干扰。
- 一个可以查询后输出答案的 RAG 引擎:一级 Chunk 链接到的对象不再是输出检索结果的检索器,而是一个 RAG 引擎,其输出的答案将作为后续生成的上下文。适用于对文档中嵌入的复杂内容(如表格)做深度查询,例如解析 HTML 页面中的表格元素创建独立 RAG 引擎。
- 一个可以规划与完成问答的 Agent 智能体:在检索出基础 Chunk 后,根据其中保存的 Agent 引用继续探索,调用 Agent 获取答案作为后续生成的上下文。区别在于后端 Agent 具备更强大的查询与工具能力,可以在后端提供更丰富的二次输出能力。
2. 递归检索的代码逻辑示意
虽然具体实现依赖框架,但核心逻辑如下:
# 伪代码示例:层级递归检索逻辑
def recursive_search(node, query):
# 第一层:摘要层检索
summary_chunks = search_in_summary_layer(query)
results = []
for chunk in summary_chunks:
if chunk.has_child_node():
# 递归进入子节点(详情层)
child_results = recursive_search(chunk.child_node, query)
results.extend(child_results)
else:
# 直接返回当前节点内容
results.append(chunk.content)
return results
对比与最佳实践
| 特性 | 融合检索 (Fusion Retrieval) | 递归检索 (Recursive Retrieval) |
|---|---|---|
| 核心机制 | 多路并行检索 + 重排序 | 层级结构 + 深度探索 |
| 优势 | 提高召回率,覆盖不同维度信息 | 处理长文档,平衡精度与上下文 |
| 劣势 | 计算开销较大,延迟较高 | 实现复杂,链路较长可能累积误差 |
| 适用场景 | 通用问答,需综合多源信息 | 长文档分析,结构化数据查询 |
实施建议
- 性能权衡:融合检索虽然效果好,但会显著增加 API 调用次数和推理时间。在生产环境中,建议先评估业务对延迟的容忍度,再决定是否开启多路检索。
- 索引策略:对于长文档,推荐采用'摘要 - 详情'的递归结构。先检索摘要确定相关段落,再加载详情内容,避免一次性加载过多 Token 导致上下文溢出。
- 框架选择:LangChain 和 LlamaIndex 均提供了丰富的支持。LlamaIndex 的
ParentDocumentRetriever和Summary Index非常适合实现递归检索;LangChain 的MultiQueryRetriever则是融合检索的便捷实现。 - 监控与调优:无论采用哪种模式,都需要持续监控检索命中率(Hit Rate)和生成质量。如果效果不佳,优先调整 Reranker 模型或优化 Chunk 切分粒度。
总结
检索在复杂 RAG 应用中的重要性不言而喻。基于单一的向量语义检索很难满足实际企业生产环境下的复杂应用需求,以原型去应对生产的需求会导致举步维艰。所以,了解与学习不同的检索策略、算法、场景与范式对于提高 RAG 应用的'生产就绪'能力必不可少。
本文对 RAG 应用中较为复杂也最强大的融合检索与递归检索进行了详细剖析。实际上在目前的主流开发框架中(LangChain 或 LlamaIndex)都有着更丰富的检索索引、算法与组件的支持,包括但不限于:基于知识图谱索引的检索、基于关键词表的检索、基于向量的 BM25 检索算法、带语义路由的多路检索器、自动元数据过滤的检索以及多 Chunk Size 下的自动合并检索等。开发者应根据具体业务场景,灵活组合这些工具,构建高效、准确的 RAG 系统。

