跳转到内容

02 - 高级检索器组合

02 - 高级检索器组合

学习目标

本章将带你探索 LlamaIndex 的多种检索器策略及其组合方式。你将学到:

  • 基础向量检索器的检索流程
  • FusionRetriever 的多查询 + 倒数排名融合(RRF)算法
  • RouterRetriever 的 LLM 路由决策
  • AutoMergingRetriever 的多粒度检索
  • IndexNode 递归检索机制
  • Postprocessor 的选择策略

前置知识


项目实践

检索器架构概览

LlamaIndex 的所有检索器继承自 BaseRetriever,核心抽象方法是 _retrieve(query_bundle) -> List[NodeWithScore]

VectorIndexRetriever:基础向量检索

检索流程分为四步:

  1. Embedding:如果查询还没有 embedding,调用 embed_model 转换
  2. 构建查询:创建 VectorStoreQuery 对象(包含 query_embedding、similarity_top_k、filters)
  3. 执行搜索:调用 vector_store.query() 获取结果
  4. 文本回退:如果 vector store 不存文本(stores_text=False),从 docstore 获取完整 node
retriever = index.as_retriever(
similarity_top_k=5,
vector_store_query_mode="default", # 或 "hybrid", "sparse", "mmr"
filters=MetadataFilters(filters=[...])
)
nodes = retriever.retrieve("你的查询")

FusionRetriever:多查询 + RRF 融合

FusionRetriever 解决单个查询的语义盲区问题。它先生成多个变体查询,然后对每个变体执行检索,最后用 倒数排名融合(RRF, Reciprocal Rank Fusion) 合并结果。

from llama_index.core.retrievers import QueryFusionRetriever
retriever = QueryFusionRetriever(
retrievers=[retriever1, retriever2],
similarity_top_k=5,
num_queries=4, # 生成 4 个变体查询
use_async=True, # 并行执行所有检索
query_gen_prompt="..." # 可选:自定义查询生成 prompt
)

RRF 算法:每个节点在所有检索结果中的排名被转换为倒数分数 1 / (k + rank),然后累加。排名靠前的节点获得更高分数。

RouterRetriever:LLM 路由决策

RouterRetriever 使用 LLM 判断哪个检索器最适合当前查询。它特别适合混合数据源场景(如同时有结构化数据和向量数据)。

from llama_index.core.retrievers import RouterRetriever
from llama_index.core.selectors import LLMSingleSelector
retriever = RouterRetriever(
selector=LLMSingleSelector.from_defaults(),
retrievers=[
retriever1, # 描述:技术文档
retriever2, # 描述:客户反馈
retriever3, # 描述:产品规格表
]
)

路由 Prompt 设计:每个 retriever 必须提供 description 字段,LLM 根据查询与描述的相关性选择最佳检索器。描述越具体,路由越准确。

AutoMergingRetriever:多粒度检索

当使用 SentenceWindowNodeParser 等分块策略时,AutoMergingRetriever 可以实现”小粒度检索 + 大粒度返回”:

  1. 用小粒度 nodes 索引(如单句)
  2. 检索时匹配最相似的小 nodes
  3. 如果同一父节点下的小 nodes 有多数被命中,自动”合并”返回父节点(完整段落)
from llama_index.core.retrievers import AutoMergingRetriever
retriever = AutoMergingRetriever(
vector_retriever,
storage_context,
auto_merging_threshold=0.5, # 50% 子节点命中则合并
)

设计原因:单句级别的 embedding 检索精度高,但单独返回一个句子给 LLM 时上下文不足。AutoMergingRetriever 在检索精度和上下文完整性之间取得平衡。

IndexNode 递归检索

IndexNode 是一种特殊的节点,它不存储文本,而是指向另一个 retriever、query engine 或 node。当检索到 IndexNode 时,会自动递归进入其指向的对象。

from llama_index.core.schema import IndexNode
# 创建一个指向另一个 retriever 的 IndexNode
index_node = IndexNode(
text="指向技术文档库",
index_id="tech_docs",
)
# 注册 object_map
retriever = index.as_retriever(
object_map={"tech_docs": another_retriever}
)

适用场景:构建”索引中的索引”——按主题分类的文档库,每个主题有自己的独立 retriever,顶层 IndexNode 路由到对应主题。

性能代价:每次递归检索至少增加一次额外的检索操作。深层嵌套可能导致检索延迟指数增长。

Postprocessor 选择策略

LlamaIndex 提供多种节点后处理器,可以在检索后进一步优化结果:

后处理器策略延迟影响
SimilarityPostprocessor按相似度阈值过滤无(纯数值比较)
KeywordNodePostprocessor关键词匹配过滤无(spacy NLP)
LongContextReorder高相关节点放首尾无(排序操作)
SentenceTransformerRerankCross-Encoder 重排序中(本地模型推理)
LLMRerankLLM 批量选择最相关节点高(LLM 调用)

LongContextReorder 的设计原因:LLM 对上下文首尾位置的信息记忆更好(“lost in the middle”现象)。将最相关的节点放在首尾,可以提高回答质量。

问题与规避

陷阱对策
FusionRetriever 的查询生成消耗额外 LLM 调用使用 num_queries=2-4 平衡准确性和成本;缓存常见查询的结果
RouterRetriever 路由不准确确保每个 retriever 的 description 具体且互斥;提供 few-shot 示例
IndexNode 递归过深导致延迟限制递归深度(通常不超过 2 层);在 retriever 中设置 recursion_depth 参数
LLMRerank 成本过高先使用 SimilarityPostprocessor 过滤掉低相似度节点,再对候选集 rerank
AutoMergingRetriever 合并不准确调整 auto_merging_threshold;确保父子节点层级关系正确

设计取舍

单一检索器 vs 组合检索器

维度单一 VectorIndexRetriever组合 (Fusion + Router + Postprocessor)
延迟低(一次向量搜索)高(多次检索 + LLM 路由 + 重排序)
准确率
成本高(额外 LLM 调用)
适用场景单一数据源、简单查询混合数据源、复杂查询

为什么需要多种检索器:没有一种检索策略适合所有场景。向量检索擅长语义匹配但对关键词不敏感;关键词检索正好相反。LlamaIndex 通过组合模式让用户根据查询类型动态选择最优策略。

参考来源