4.2 检索器类型与配置


4.2 检索器类型与配置

本节摘要:检索器决定"哪些节点有机会进入合成"。本节比较向量检索、关键词(BM25)检索、融合检索与自动合并检索四类,用一组"精确术语问题 vs 口语化问题"的对照实验展示各自边界,并给出 top_k、相似度阈值、过滤器的调参次序。

向量检索的盲区

向量检索强在"换个说法也能找到",弱在"一字之差必须精确匹配"。实验:语料里有型号 "XR-2000",问"XR-2000 的保修期"——嵌入模型未必把型号串编码得足够可分辨;反过来问"机器坏了能保修多久"(口语),BM25 又抓不到。两类问题的对照:

from llama_index.core.retrievers import ( VectorIndexRetriever, BM25Retriever, QueryFusionRetriever) from llama_index.core.query_engine import RetrieverQueryEngine vec = index.as_retriever(similarity_top_k=4) # 纯向量 bm25 = BM25Retriever.from_defaults(nodes=all_nodes, similarity_top_k=4) # 纯关键词 for q in ["XR-2000 的保修期是多久", "机器坏了能保修多久"]: print("向量:", [n.score for n in vec.retrieve(q)]) print("关键词:", [n.score for n in bm25.retrieve(q)])

在多数语料上你会观察到:型号/编号/人名类查询 BM25 明显占优,口语化描述向量占优。而真实用户两种问法都有——这就是融合检索存在的理由。

融合检索:两条通道各取所长

fusion = QueryFusionRetriever( [vec, bm25], similarity_top_k=6, num_queries=1, # 不做查询扩展,纯两路合并 mode="reciprocal_rerank_fusion", # 倒数排名融合:不比分数只比名次 ) nodes = fusion.retrieve("XR-2000 保修") print([(n.node.metadata.get("file_name"), round(n.score, 3)) for n in nodes])

reciprocal_rerank_fusion 的巧处在于绕开了两套打分量纲不可比的问题——向量给余弦、BM25 给 BM25 分,直接加权毫无意义;各取排名的倒数再融合,量纲天然统一。这是工程上"简单但正确"的典范。

自动合并检索:层级分块的配套武器

第 2 章说"切分粒度要对齐信息单元",但有时既要句子级的精细命中、又要章节级的完整上下文。层级分块(小节点挂在大块下)配 AutoMergingRetriever:小节点被多个命中时,自动"上卷"成父块送入合成:

from llama_index.core.node_parser import HierarchicalNodeParser from llama_index.core.retrievers import AutoMergingRetriever from llama_index.core import StorageContext, load_index_from_storage # 三层切分:2048 → 512 → 128 h_parser = HierarchicalNodeParser.from_defaults( chunk_sizes=[2048, 512, 128]) nodes = h_parser.get_nodes_from_documents(docs) # 建索引时保存层级关系 storage = StorageContext.from_defaults() storage.docstore.add_documents(nodes) merging_index = VectorStoreIndex( [n for n in nodes if n.id_ in leaf_nodes], storage_context=storage) base = merging_index.as_retriever(similarity_top_k=6) auto = AutoMergingRetriever(base, storage_context=storage, verbose=True) # 若 128 级的多个兄弟节点同时命中,自动换成它们的 512 级父块

它的效果与句子窗口检索(2.3 节)异曲同工——细粒度检索、粗粒度生成——但粒度层次更多,适合结构长的文档(规章、长报告)。

调参次序

经验上的调参优先级:先 similarity_top_k(从 4 开始,重排器在场时可放大到 10–20);再上重排器截断(4.1 节);然后才考虑相似度阈值 retrieval_similarity_top_k 之外的 score cutoff——阈值对分数分布敏感,换嵌入模型就得重调,放在最后动。过滤器(3.3 节)则不是调参,是业务约束,有明确范围就尽早加上,能省下大量无效召回。

💡 关键直觉:检索器解决"查全",重排器解决"排对"。先保证正确内容出现在候选里(召回率),再操心排序——顺序反了会在错误的候选集上白费重排算力。

本节要点回顾

  • 两类问题两把刀:精确术语归 BM25,口语化归向量;真实系统两种问法并存。
  • 融合用排名不用分数:倒数排名融合解决两套量纲不可比,简单且正确。
  • 层级召回:AutoMergingRetriever 配层级分块,细命中粗上下文,适合长结构文档。
  • 调参次序:top_k → 重排 → 阈值;阈值对分数分布敏感,最后动。
  • 查全先于排对:先修召回率再修排序,重排救不回没进候选集的内容。

常见问题

BM25 需要中文分词吗? 需要,BM25 的效果高度依赖分词质量。LlamaIndex 的 BM25 实现基于 rank_bm25,中文语料要传入分词后的文本(或指定中文分词器),否则按字切分的关键词匹配会很弱。这是中文 BM25 最常见的坑,没有之一。

融合检索的权重要怎么调? 倒数排名融合的好处恰恰是不太需要调权——两路排名直接融合已够好。真要偏向某一路(比如术语查询多的场景偏 BM25),可以在融合公式里给该路的排名倒数乘个系数,但先跑默认值,有评估数据再动手。

层级分块的三层粒度怎么定? 一个实用锚点:叶子层对齐"单个信息单元"(一个条款、一小节),中层是叶子的大约四倍,顶层接近模型一次能舒服消化的长度。别机械照搬参数——用 2.3 节的对照实验在三层候选里选,你的语料会给出答案。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U