首页 > 教程攻略 > ai资讯 >一文说清大模型RAG应用中的两种高级检索模式:你还只知道向量检索吗?

一文说清大模型RAG应用中的两种高级检索模式:你还只知道向量检索吗?

来源:互联网 时间:2026-08-25 13:46:57

RAG检索进阶:融合检索与递归检索,到底怎么玩?

聊到RAG(检索增强生成),大家肯定都知道那个“R”代表检索。这个环节有多重要,不用多说——它直接决定了后续生成质量的底牌。而基于向量的语义检索,可以说是最基础、最广为人知的检索模式了。

不过,在实际落地的时候,单纯用一次向量检索,往往有点“不够用”。你会发现,简单的top-K召回,对很多复杂的、多层次的需求显得力不从心。所以在模块化RAG兴起的今天,各种新范式和新算法都在检索这个核心环节上做了大量的创新和优化。

这篇文章,咱们就聊两种在实际RAG应用里非常灵活、也相当有效的高级检索模式:

融合检索(Fusion Retrieval)

递归检索(Recursive Retrieval)

融合检索

融合检索,说白了,就是把多种不同的检索方法组合在一起,取长补短。它的核心思路是:

用多个不同维度的检索方式去查询,然后把召回的结果通过排序算法(比如经典的RRF)重新排序、融合,再交给后续的生成环节

。这么做的目的,就是为了弥补单个向量索引在检索精确性上的短板。

那么,这种“多路不同的检索”具体怎么实现?在实际应用中,可以根据业务场景灵活选择,比如:

从不同角度重写问题、使用不同的检索算法、或者构建不同类型的索引

,都是可行的路径。

基于问题重写与扩展

这种方式,是借助查询重写(或查询转换器)模块,把用户输入的原始问题扩展成多个不同表达或从不同角度细化的子问题。然后分别对这些子问题进行检索,最后把召回的知识块通过一个重排(reranker)模块重新排序,只取最终的top_K给生成环节用。

通过Rewriter模块进行问题扩展

基于多种类型的索引

虽然高维向量索引在语义检索上很出色,但它也不是万能的。比如,你可能需要借助知识图谱索引来精确获取实体间的复杂关系,或者用树状的摘要索引来更好地回答那些偏概要性的问题。所以,你可以同时构建多路不同类型的索引(比如向量索引和关键词索引)对同一个问题进行检索,然后把召回的知识块重排序后取top_K。

(当然,也可以用同一种索引,但采用不同的检索与评分算法)

基于向量索引与关键词索引对问题进行多路检索

基于复合方案的多路检索

这种方式是上面两种的“合体”。也就是说,同时借助问题扩展和索引扩展,来实现更多路的知识召回。召回的知识块多了,理论上找到更相关信息的概率也大了,但代价也很明显:系统性能的消耗和模型使用成本都会相应增加。在实际项目中,需要根据测试结果来权衡取舍。


基于问题扩展+索引扩展的融合检索

融合检索的关键技术

实现融合检索其实并不复杂。在LangChain或LlamaIndex这些主流框架里,都有现成的转换器(rewriter)、检索器(retriever)和排序器(reranker)概念和组件,你可以自由组合来实现。

  • 查询扩展:

    可以借助LLM自己实现,也可以直接用开箱即用的组件,比如LlamaIndex里的QueryTransform。

  • Reranker:

    可以自己写个RRF算法函数,或者用Cohere Reranker这类专业的排序模型。

  • 检索融合:

    可以扩展已有的Retriever组件,自定义一个融合检索器。有些框架甚至有现成的,比如LlamaIndex的QueryFusionRetriever。下面是一个典型的融合检索器扩展示例:

......class FusionRetriever(BaseRetriever):

    # 基于多个检索器构造融合检索器
    # 参数:检索器列表与top_k
    def __init__(
        self,
        retrievers: List[BaseRetriever],
        similarity_top_k: int = 3,
    ) -> None:
        self._retrievers = retrievers
        self._similarity_top_k = similarity_top_k
        super().__init__()

    # 实现检索方法
    def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        
        # 查询重写,自行实现rewrite_query
        querys = rewrite_query(query_bundle.query_str, num=3)
        
        # 调用辅助方法得到全部检索结果,自行实现run_queries
        results_dict = asyncio.run(run_queries(querys, self._retrievers))

        # RRF重新排序,自行实现rerank_results
        final_results = rerank_results(results_dict, similarity_top_k=self._similarity_top_k)

        return final_results


递归检索

相较于融合检索,递归检索的玩法要更复杂一些,但思路非常符合人类的认知习惯。想象一下,你要在一大堆书里找一段特定的文字,你会怎么干?肯定不是一本本地翻。合理的做法是:

  • 先做一些基本筛选,比如根据出版社或者出版年份过滤。
  • 看看目录或简介,锁定可能相关的几本书。
  • 最后在这几本书里,再根据目录和具体内容,找到目标文字。

这本质上就是一种递归检索:

在不同层次上构建chunks节点和检索器(比如摘要层和内容层、主要内容层和嵌入内容层),并在它们之间建立链接关系。这样,在每次检索时,系统就能自动向下递归探索,直到达到结束条件。

下面这张图可以简单示意其原理:

从图里可以看出,

递归检索的技术基础,是能够从一级索引检索出来的chunks,链接到二级的chunks或者其他具备检索功能的装置(比如检索器、Chain、RAG引擎甚至Agent)。实现这种链接的方式,通常是在一级的chunk对象中(比如LangChain的Document对象或LlamaIndex的Node对象)保存二级对象的引用。

从一级chunks链接到的二级对象引用,可以是以下几种:

  • 一个可以直接读取内容的二级chunk块

  • 一个可以检索出多个二级chunk块的检索器

  • 一个可以查询后输出答案的RAG引擎

  • 一个可以规划与完成问答的Agent智能体

下面我们具体看看这几种不同的链接形态及其应用场景和递归流程。

从chunk链接到chunk

这种递归检索的本质,就是一级chunk查找关联chunk的过程:通过检索找到一级chunk,然后根据它的引用直接找到对应的二级chunk返回。在RAG里这么做的意义,通常是为了解决那个老生常谈的问题:chunk的语义精确性和上下文的丰富性往往是矛盾的,所以需要把这两种需求分离设计。

常见的应用场景有:

  • 在一个小的chunk中保存对应的大的chunk引用(父子块)

    ——用于在更精准的语义搜索基础上,提供更丰富的上下文。
  • 在一个摘要chunk中保存对应的详细内容chunk的引用

    ——用于增强回答偏概要性或笼统性问题的能力。
  • 在一个假设性问题的chunk中保存对应的内容chunk的引用

    ——通过假设性问题来兼容更多的提问形式,提高召回精确性。

下图展示了这种方式的检索流程(注意并非所有的一级chunk都一定要有二级chunk的链接),蓝色部分表示实际检索过程:

从chunk链接到检索器

这种情况下,通过检索出来的一级chunk找到对应的二级检索器(注意不是chunk),然后递归调用这个检索器再次检索,并把二次检索出来的chunks用于后续生成。

这种方式的典型场景是多文档问答

。通过生成摘要文档来实现分层过滤,可以显著降低单一层次检索下的精度不足、知识干扰等问题:

  • 在摘要与原始文档层面分别做嵌入和索引,并建立链接。
  • 在摘要级别做检索,获得相关的摘要知识块。
  • 根据摘要块的关联信息,链接到原始文档块的检索器。
  • 递归检索原始文档的知识块,找到top-k用于生成。

下图表示了这种方式下的检索流程:

从chunk链接到RAG引擎

这种方式和上一种的区别在于:一级chunk链接到的对象不再是一个输出chunks的检索器,而是一个完整的RAG引擎,它输出的答案将直接作为后续生成的上下文。上一种场景中的检索器,自然也可以换成RAG引擎,达到类似的效果。

除此之外,

还有一种典型的场景是用于对文档中嵌入的复杂内容进行深度查询

。比如,一个HTML页面中除了文字,还嵌入了一个或多个结构化表格。很多时候,我们需要对这些嵌入的表格做更复杂的自然语言提问(比如需要借助SQL或Pandas)。递归检索就可以这样用:

  • 对解析出来的表格元素创建独立的RAG引擎,可以基于Pandas或者SQL数据库,以满足对这个嵌入表格的复杂查询。
  • 对每个结构化表格生成一个摘要内容chunk,并链接到表格的独立RAG引擎。
  • 这些表格的摘要chunk与文档的其他chunk一起创建向量索引,并构建一个顶层的RAG引擎提供对外查询。

下图表示了这种方式下的检索流程:

从chunk链接到Agent

最后一种方式是从chunk节点链接到Agent。在检索出基础chunk后,根据其中保存的Agent引用继续探索,调用Agent获取答案作为后续生成的上下文。这种模式本质上与“chunk + RAG引擎”类似,

区别在于后端Agent具备更强大的查询和工具调用能力,因此可以提供更丰富的二次输出能力

仍然以多文档RAG应用为例,我们可以做如下设计来支持更复杂的问答场景:

  • 对每个文档创建一个Agent,每个Agent拥有两个工具:一个用来回答事实性问题,另一个用来回答高层总结与分析类问题。
  • 对每个文档创建摘要文档与chunks,并链接到对应的后端Agent。
  • 对摘要文档的chunks创建一级向量索引和RAG引擎,提供对外查询。

下图表示了这种方式下的检索流程:


到此,我们把两种复杂但强大的检索模式详细剖析了一遍。检索在RAG应用中的重要性不言而喻,单一的向量语义检索在复杂的生产环境中往往力不从心。以原型去应对生产需求,很快就会发现“举步维艰”。因此,了解和掌握不同的检索策略、算法、场景与范式,是让RAG应用真正走向“生产就绪”的关键一环。

实际上,在LangChain和LlamaIndex这些主流开发框架中,还有着更丰富的检索索引、算法和组件支持,包括但不限于:

  • 基于知识图谱索引的检索
  • 基于关键词表的检索
  • 基于向量的BM25检索算法
  • 带语义路由的多路检索器
  • 自动元数据过滤的检索
  • 多chunk size下的自动合并检索