文章目录
- 【60.Python+AI】LlamaIndex高级检索:从基础向量搜索到知识图谱增强
-
- 导入语
- [1 ~> 基础向量搜索的局限性](#1 ~> 基础向量搜索的局限性)
-
- [1.1 基础RAG的检索流程](#1.1 基础RAG的检索流程)
- [1.2 三个典型翻车场景](#1.2 三个典型翻车场景)
- [2 ~> 句子窗口检索:还原文块上下文](#2 ~> 句子窗口检索:还原文块上下文)
-
- [2.1 核心思路](#2.1 核心思路)
- [2.2 检索流程](#2.2 检索流程)
- [2.3 LlamaIndex 配置代码](#2.3 LlamaIndex 配置代码)
- [2.4 适用场景](#2.4 适用场景)
- [3 ~> 自动合并检索:解决碎片化问题](#3 ~> 自动合并检索:解决碎片化问题)
-
- [3.1 问题根源](#3.1 问题根源)
- [3.2 核心思路](#3.2 核心思路)
- [3.3 检索流程](#3.3 检索流程)
- [3.4 LlamaIndex 配置代码](#3.4 LlamaIndex 配置代码)
- [3.5 什么时候用](#3.5 什么时候用)
- [4 ~> 递归检索:层级文档的对策](#4 ~> 递归检索:层级文档的对策)
-
- [4.1 问题场景](#4.1 问题场景)
- [4.2 核心思路](#4.2 核心思路)
- [4.3 检索流程](#4.3 检索流程)
- [4.4 实现示例](#4.4 实现示例)
- [5 ~> 知识图谱+向量双索引融合](#5 ~> 知识图谱+向量双索引融合)
-
- [5.1 向量检索做不到的事](#5.1 向量检索做不到的事)
- [5.2 知识图谱能做什么](#5.2 知识图谱能做什么)
- [5.3 双索引融合流程](#5.3 双索引融合流程)
- [5.4 LlamaIndex 中的知识图谱索引](#5.4 LlamaIndex 中的知识图谱索引)
- [5.5 适用场景总结](#5.5 适用场景总结)
- [思考 && 总结](#思考 && 总结)
- 结尾
【60.Python+AI】LlamaIndex高级检索:从基础向量搜索到知识图谱增强
📖 文章简介: 本文深入LlamaIndex的高级检索策略,在基础向量搜索之上,系统讲解四种进阶索引技术:递归检索(Recursive Retrieval)在文档层级之间逐层缩小范围、句子窗口检索(Sentence Window Retrieval)利用上下文窗口还原语义完整性、自动合并检索(Auto-Merging Retrieval)解决分块过细导致的碎片化问题,以及知识图谱+向量双索引融合带来的多跳推理能力。每种策略均配有Mermaid检索流程图、配置代码和适用场景,适合已入门LlamaIndex、想让RAG召回率再上一个台阶的开发者。

🎬 个人主页: 源码骑士
❄ 专栏传送门: 《Android开发基础》《python基础课程》
⭐️热衷从源码视角拆解技术底层原理,将复杂架构讲得通俗易懂
🎬 源码骑士的简介:
5年Android Framework系统开发经验,曾主导多项系统级性能优化专项
技术栈覆盖Android系统全链路(Binder/Handler/AMS/WMS/启动流程)及Java后端全家桶(Spring + MyBatis + Redis + Oracle)
累计产出原创技术文章100+篇,文章以流程图为特色,被读者评价为"看一篇胜过啃一周源码"
导入语
你搭好了一个基础的RAG系统------文档分块、embedding、向量检索、大模型生成,跑通了。但用户开始抱怨:"明明答案就在文档里,为什么搜不到?"
问题不在大模型,在检索。基础向量搜索在面对复杂文档时就像一个只会查字典的人------他只能找到包含关键字的页面,但做不了"上下文推理"和"跨段落关联"。
这篇文章的目标很明确:在基础向量搜索之上,一层一层往上叠加LlamaIndex的高级检索策略。 看完之后你会知道,面对层次化文档用递归检索、面对碎片化问答用句子窗口、面对跨实体推理用知识图谱------每种问题都有对应的检索武器。
1 ~> 基础向量搜索的局限性
1.1 基础RAG的检索流程
#mermaid-svg-McS4On1BBW7eUHPp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-McS4On1BBW7eUHPp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-McS4On1BBW7eUHPp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-McS4On1BBW7eUHPp .error-icon{fill:#552222;}#mermaid-svg-McS4On1BBW7eUHPp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-McS4On1BBW7eUHPp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-McS4On1BBW7eUHPp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-McS4On1BBW7eUHPp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-McS4On1BBW7eUHPp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-McS4On1BBW7eUHPp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-McS4On1BBW7eUHPp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-McS4On1BBW7eUHPp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-McS4On1BBW7eUHPp .marker.cross{stroke:#333333;}#mermaid-svg-McS4On1BBW7eUHPp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-McS4On1BBW7eUHPp p{margin:0;}#mermaid-svg-McS4On1BBW7eUHPp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-McS4On1BBW7eUHPp .cluster-label text{fill:#333;}#mermaid-svg-McS4On1BBW7eUHPp .cluster-label span{color:#333;}#mermaid-svg-McS4On1BBW7eUHPp .cluster-label span p{background-color:transparent;}#mermaid-svg-McS4On1BBW7eUHPp .label text,#mermaid-svg-McS4On1BBW7eUHPp span{fill:#333;color:#333;}#mermaid-svg-McS4On1BBW7eUHPp .node rect,#mermaid-svg-McS4On1BBW7eUHPp .node circle,#mermaid-svg-McS4On1BBW7eUHPp .node ellipse,#mermaid-svg-McS4On1BBW7eUHPp .node polygon,#mermaid-svg-McS4On1BBW7eUHPp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-McS4On1BBW7eUHPp .rough-node .label text,#mermaid-svg-McS4On1BBW7eUHPp .node .label text,#mermaid-svg-McS4On1BBW7eUHPp .image-shape .label,#mermaid-svg-McS4On1BBW7eUHPp .icon-shape .label{text-anchor:middle;}#mermaid-svg-McS4On1BBW7eUHPp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-McS4On1BBW7eUHPp .rough-node .label,#mermaid-svg-McS4On1BBW7eUHPp .node .label,#mermaid-svg-McS4On1BBW7eUHPp .image-shape .label,#mermaid-svg-McS4On1BBW7eUHPp .icon-shape .label{text-align:center;}#mermaid-svg-McS4On1BBW7eUHPp .node.clickable{cursor:pointer;}#mermaid-svg-McS4On1BBW7eUHPp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-McS4On1BBW7eUHPp .arrowheadPath{fill:#333333;}#mermaid-svg-McS4On1BBW7eUHPp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-McS4On1BBW7eUHPp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-McS4On1BBW7eUHPp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-McS4On1BBW7eUHPp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-McS4On1BBW7eUHPp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-McS4On1BBW7eUHPp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-McS4On1BBW7eUHPp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-McS4On1BBW7eUHPp .cluster text{fill:#333;}#mermaid-svg-McS4On1BBW7eUHPp .cluster span{color:#333;}#mermaid-svg-McS4On1BBW7eUHPp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-McS4On1BBW7eUHPp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-McS4On1BBW7eUHPp rect.text{fill:none;stroke-width:0;}#mermaid-svg-McS4On1BBW7eUHPp .icon-shape,#mermaid-svg-McS4On1BBW7eUHPp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-McS4On1BBW7eUHPp .icon-shape p,#mermaid-svg-McS4On1BBW7eUHPp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-McS4On1BBW7eUHPp .icon-shape .label rect,#mermaid-svg-McS4On1BBW7eUHPp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-McS4On1BBW7eUHPp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-McS4On1BBW7eUHPp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-McS4On1BBW7eUHPp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提问
Embedding向量化
向量相似度搜索
返回Top-K文档块
拼接后交给LLM生成答案
这个流程的问题在于:你的文档已经被切成了小块,每个块都丢失了上下文信息。
1.2 三个典型翻车场景
| 场景 | 基础向量搜索的表现 |
|---|---|
| 一个定义分散在三个相邻段落 | 只检索到其中一个段落,LLM拿到不完整信息 |
| 用户问"第三章讲了什么" | 第三章被切成40个小块,没有一个能概括全貌 |
| 需要跨实体推理 | A提到B、B提到C、问A和C的关系------向量检索完全做不到 |
2 ~> 句子窗口检索:还原文块上下文
2.1 核心思路
基础检索只返回匹配的那一小块。句子窗口检索在返回结果时,把匹配块的前后各扩展N个句子一起返回。
2.2 检索流程
#mermaid-svg-n40TXSh9ebv3Ccqo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n40TXSh9ebv3Ccqo .error-icon{fill:#552222;}#mermaid-svg-n40TXSh9ebv3Ccqo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n40TXSh9ebv3Ccqo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n40TXSh9ebv3Ccqo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n40TXSh9ebv3Ccqo .marker.cross{stroke:#333333;}#mermaid-svg-n40TXSh9ebv3Ccqo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n40TXSh9ebv3Ccqo p{margin:0;}#mermaid-svg-n40TXSh9ebv3Ccqo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster-label text{fill:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster-label span{color:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster-label span p{background-color:transparent;}#mermaid-svg-n40TXSh9ebv3Ccqo .label text,#mermaid-svg-n40TXSh9ebv3Ccqo span{fill:#333;color:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo .node rect,#mermaid-svg-n40TXSh9ebv3Ccqo .node circle,#mermaid-svg-n40TXSh9ebv3Ccqo .node ellipse,#mermaid-svg-n40TXSh9ebv3Ccqo .node polygon,#mermaid-svg-n40TXSh9ebv3Ccqo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n40TXSh9ebv3Ccqo .rough-node .label text,#mermaid-svg-n40TXSh9ebv3Ccqo .node .label text,#mermaid-svg-n40TXSh9ebv3Ccqo .image-shape .label,#mermaid-svg-n40TXSh9ebv3Ccqo .icon-shape .label{text-anchor:middle;}#mermaid-svg-n40TXSh9ebv3Ccqo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-n40TXSh9ebv3Ccqo .rough-node .label,#mermaid-svg-n40TXSh9ebv3Ccqo .node .label,#mermaid-svg-n40TXSh9ebv3Ccqo .image-shape .label,#mermaid-svg-n40TXSh9ebv3Ccqo .icon-shape .label{text-align:center;}#mermaid-svg-n40TXSh9ebv3Ccqo .node.clickable{cursor:pointer;}#mermaid-svg-n40TXSh9ebv3Ccqo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-n40TXSh9ebv3Ccqo .arrowheadPath{fill:#333333;}#mermaid-svg-n40TXSh9ebv3Ccqo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-n40TXSh9ebv3Ccqo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-n40TXSh9ebv3Ccqo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n40TXSh9ebv3Ccqo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-n40TXSh9ebv3Ccqo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n40TXSh9ebv3Ccqo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster text{fill:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo .cluster span{color:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-n40TXSh9ebv3Ccqo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n40TXSh9ebv3Ccqo rect.text{fill:none;stroke-width:0;}#mermaid-svg-n40TXSh9ebv3Ccqo .icon-shape,#mermaid-svg-n40TXSh9ebv3Ccqo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n40TXSh9ebv3Ccqo .icon-shape p,#mermaid-svg-n40TXSh9ebv3Ccqo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-n40TXSh9ebv3Ccqo .icon-shape .label rect,#mermaid-svg-n40TXSh9ebv3Ccqo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n40TXSh9ebv3Ccqo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n40TXSh9ebv3Ccqo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n40TXSh9ebv3Ccqo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提问
Embedding检索
匹配到第5块文档
句子窗口扩展
窗口大小=3
返回块 4,5,6
交给LLM生成
2.3 LlamaIndex 配置代码
python
from llama_index.core.node_parser import SentenceWindowNodeParser
from llama_index.core.indices.postprocessor import MetadataReplacementPostProcessor
# 创建句子窗口解析器
node_parser = SentenceWindowNodeParser.from_defaults(
window_size=3, # 前后各扩展3个句子
window_metadata_key="window", # 元数据key
original_text_metadata_key="original_text"
)
nodes = node_parser.get_nodes_from_documents(documents)
# 检索后处理器:用小块的embedding去搜索,但返回窗口上下文
postprocessor = MetadataReplacementPostProcessor(
target_metadata_key="window"
)
2.4 适用场景
| 场景 | 是否推荐 | 原因 |
|---|---|---|
| 定义类文档(术语分散在多行) | ✅ 强烈推荐 | 补足上下文避免断章取义 |
| 结构化问答(FAQ) | ❌ 不需要 | 每条FAQ本身就是独立完整单元 |
| 长报告、论文 | ✅ 推荐 | 概念经常跨段分布 |
3 ~> 自动合并检索:解决碎片化问题
3.1 问题根源
如果你的文档切得太细(比如每256 token一块),一个完整的论述可能被切成十几块。向量搜索只能返回其中一部分,LLM看到的是"碎片化"的信息。
3.2 核心思路
自动合并检索做了两件事:
- 建索引时:构建层级结构------大块(父节点)包含多个小块(子节点)
- 检索时:从最底层的小块开始搜,如果某个父节点下的子节点被命中了足够多,就把整个父节点替换回来
3.3 检索流程
#mermaid-svg-rLOcZfGy2aijHio1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rLOcZfGy2aijHio1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rLOcZfGy2aijHio1 .error-icon{fill:#552222;}#mermaid-svg-rLOcZfGy2aijHio1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rLOcZfGy2aijHio1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rLOcZfGy2aijHio1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rLOcZfGy2aijHio1 .marker.cross{stroke:#333333;}#mermaid-svg-rLOcZfGy2aijHio1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rLOcZfGy2aijHio1 p{margin:0;}#mermaid-svg-rLOcZfGy2aijHio1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rLOcZfGy2aijHio1 .cluster-label text{fill:#333;}#mermaid-svg-rLOcZfGy2aijHio1 .cluster-label span{color:#333;}#mermaid-svg-rLOcZfGy2aijHio1 .cluster-label span p{background-color:transparent;}#mermaid-svg-rLOcZfGy2aijHio1 .label text,#mermaid-svg-rLOcZfGy2aijHio1 span{fill:#333;color:#333;}#mermaid-svg-rLOcZfGy2aijHio1 .node rect,#mermaid-svg-rLOcZfGy2aijHio1 .node circle,#mermaid-svg-rLOcZfGy2aijHio1 .node ellipse,#mermaid-svg-rLOcZfGy2aijHio1 .node polygon,#mermaid-svg-rLOcZfGy2aijHio1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rLOcZfGy2aijHio1 .rough-node .label text,#mermaid-svg-rLOcZfGy2aijHio1 .node .label text,#mermaid-svg-rLOcZfGy2aijHio1 .image-shape .label,#mermaid-svg-rLOcZfGy2aijHio1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-rLOcZfGy2aijHio1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rLOcZfGy2aijHio1 .rough-node .label,#mermaid-svg-rLOcZfGy2aijHio1 .node .label,#mermaid-svg-rLOcZfGy2aijHio1 .image-shape .label,#mermaid-svg-rLOcZfGy2aijHio1 .icon-shape .label{text-align:center;}#mermaid-svg-rLOcZfGy2aijHio1 .node.clickable{cursor:pointer;}#mermaid-svg-rLOcZfGy2aijHio1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rLOcZfGy2aijHio1 .arrowheadPath{fill:#333333;}#mermaid-svg-rLOcZfGy2aijHio1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rLOcZfGy2aijHio1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rLOcZfGy2aijHio1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rLOcZfGy2aijHio1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rLOcZfGy2aijHio1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rLOcZfGy2aijHio1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rLOcZfGy2aijHio1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rLOcZfGy2aijHio1 .cluster text{fill:#333;}#mermaid-svg-rLOcZfGy2aijHio1 .cluster span{color:#333;}#mermaid-svg-rLOcZfGy2aijHio1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rLOcZfGy2aijHio1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rLOcZfGy2aijHio1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-rLOcZfGy2aijHio1 .icon-shape,#mermaid-svg-rLOcZfGy2aijHio1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rLOcZfGy2aijHio1 .icon-shape p,#mermaid-svg-rLOcZfGy2aijHio1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rLOcZfGy2aijHio1 .icon-shape .label rect,#mermaid-svg-rLOcZfGy2aijHio1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rLOcZfGy2aijHio1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rLOcZfGy2aijHio1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rLOcZfGy2aijHio1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
用户提问
向量搜索
返回Top-K小块
检查命中分布
某个父节点下
命中>=阈值?
用父节点替换
所有命中的子节点
保持小块返回
交给LLM
3.4 LlamaIndex 配置代码
python
from llama_index.core.node_parser import HierarchicalNodeParser
from llama_index.core.retrievers import AutoMergingRetriever
# 层级分块:小块512,大块2048
node_parser = HierarchicalNodeParser.from_defaults(
chunk_sizes=[2048, 512], # 父节点大小, 子节点大小
chunk_overlap=50
)
nodes = node_parser.get_nodes_from_documents(documents)
# 自动合并检索器
retriever = AutoMergingRetriever(
vector_retriever,
storage_context,
verbose=True
)
3.5 什么时候用
你的文档切得越细(为了更精准的向量匹配),就越需要用自动合并来保证LLM收到的不是一堆碎片。
4 ~> 递归检索:层级文档的对策
4.1 问题场景
你有一本300页的技术手册,用户问"第三章的整体框架是什么?"
基础向量检索在这个问题上完全失败------因为第三章的框架不存在于任何一个段落里,它是跨50个段落的宏观概念。
4.2 核心思路
递归检索相当于"先查目录,再看章节,最后读段落"的人类阅读方式:
- 第一层:在摘要/章节标题级别检索,确定"这个话题在第三章"
- 第二层:深入到第三章的内容节点中检索相关内容
- 把两层的检索结果合并后交给LLM
4.3 检索流程
#mermaid-svg-G83L3GhXWTkXMWgx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-G83L3GhXWTkXMWgx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G83L3GhXWTkXMWgx .error-icon{fill:#552222;}#mermaid-svg-G83L3GhXWTkXMWgx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G83L3GhXWTkXMWgx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G83L3GhXWTkXMWgx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G83L3GhXWTkXMWgx .marker.cross{stroke:#333333;}#mermaid-svg-G83L3GhXWTkXMWgx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G83L3GhXWTkXMWgx p{margin:0;}#mermaid-svg-G83L3GhXWTkXMWgx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-G83L3GhXWTkXMWgx .cluster-label text{fill:#333;}#mermaid-svg-G83L3GhXWTkXMWgx .cluster-label span{color:#333;}#mermaid-svg-G83L3GhXWTkXMWgx .cluster-label span p{background-color:transparent;}#mermaid-svg-G83L3GhXWTkXMWgx .label text,#mermaid-svg-G83L3GhXWTkXMWgx span{fill:#333;color:#333;}#mermaid-svg-G83L3GhXWTkXMWgx .node rect,#mermaid-svg-G83L3GhXWTkXMWgx .node circle,#mermaid-svg-G83L3GhXWTkXMWgx .node ellipse,#mermaid-svg-G83L3GhXWTkXMWgx .node polygon,#mermaid-svg-G83L3GhXWTkXMWgx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-G83L3GhXWTkXMWgx .rough-node .label text,#mermaid-svg-G83L3GhXWTkXMWgx .node .label text,#mermaid-svg-G83L3GhXWTkXMWgx .image-shape .label,#mermaid-svg-G83L3GhXWTkXMWgx .icon-shape .label{text-anchor:middle;}#mermaid-svg-G83L3GhXWTkXMWgx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-G83L3GhXWTkXMWgx .rough-node .label,#mermaid-svg-G83L3GhXWTkXMWgx .node .label,#mermaid-svg-G83L3GhXWTkXMWgx .image-shape .label,#mermaid-svg-G83L3GhXWTkXMWgx .icon-shape .label{text-align:center;}#mermaid-svg-G83L3GhXWTkXMWgx .node.clickable{cursor:pointer;}#mermaid-svg-G83L3GhXWTkXMWgx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-G83L3GhXWTkXMWgx .arrowheadPath{fill:#333333;}#mermaid-svg-G83L3GhXWTkXMWgx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-G83L3GhXWTkXMWgx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-G83L3GhXWTkXMWgx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G83L3GhXWTkXMWgx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-G83L3GhXWTkXMWgx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G83L3GhXWTkXMWgx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-G83L3GhXWTkXMWgx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-G83L3GhXWTkXMWgx .cluster text{fill:#333;}#mermaid-svg-G83L3GhXWTkXMWgx .cluster span{color:#333;}#mermaid-svg-G83L3GhXWTkXMWgx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-G83L3GhXWTkXMWgx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G83L3GhXWTkXMWgx rect.text{fill:none;stroke-width:0;}#mermaid-svg-G83L3GhXWTkXMWgx .icon-shape,#mermaid-svg-G83L3GhXWTkXMWgx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G83L3GhXWTkXMWgx .icon-shape p,#mermaid-svg-G83L3GhXWTkXMWgx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-G83L3GhXWTkXMWgx .icon-shape .label rect,#mermaid-svg-G83L3GhXWTkXMWgx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G83L3GhXWTkXMWgx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-G83L3GhXWTkXMWgx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-G83L3GhXWTkXMWgx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提问
第一层检索:
在摘要/章节级搜索
定位到相关章节
第二层检索:
在该章节内做向量搜索
返回章节内相关块
合并两层结果交给LLM
4.4 实现示例
python
from llama_index.core.schema import IndexNode
from llama_index.core import SummaryIndex, VectorStoreIndex
# 第一层:为每个章节建摘要索引
chapter_summaries = IndexNode(
index_id="chapter_3",
text="第三章主要讲解异步编程与协程...",
)
summary_index = VectorStoreIndex(chapter_summaries)
# 第二层:每个章节有自己的向量索引
chapter_3_index = VectorStoreIndex(chapter_3_nodes)
# 递归检索器
from llama_index.core.retrievers import RecursiveRetriever
retriever = RecursiveRetriever(
"vector", # 第一层用向量检索定位章节
retriever_dict={
"chapter_3": chapter_3_index.as_retriever(),
},
verbose=True
)
5 ~> 知识图谱+向量双索引融合
5.1 向量检索做不到的事
向量检索本质上是语义相似度匹配 ------找到和问题最相似的段落。但有些问题需要的不是相似度,而是推理:
- "A公司和B公司有什么关系?"
- "这个技术方案依赖哪些前置条件?"
- "这本书里前后矛盾的地方在哪?"
5.2 知识图谱能做什么
知识图谱抽取出实体 和关系,构建成一张图:
bash
知识图谱示例
[Python] --被用于--> [后端开发]
[Python] --被用于--> [数据分析]
[后端开发] --需要--> [Django框架]
[数据分析] --需要--> [Pandas库]
当你问"做后端开发需要学什么"时,知识图谱可以沿着"后端开发→Django框架"这条关系链推理,而不是靠简单的语义匹配。
5.3 双索引融合流程
#mermaid-svg-pXbsElnItDOcyigR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pXbsElnItDOcyigR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pXbsElnItDOcyigR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pXbsElnItDOcyigR .error-icon{fill:#552222;}#mermaid-svg-pXbsElnItDOcyigR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pXbsElnItDOcyigR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pXbsElnItDOcyigR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pXbsElnItDOcyigR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pXbsElnItDOcyigR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pXbsElnItDOcyigR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pXbsElnItDOcyigR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pXbsElnItDOcyigR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pXbsElnItDOcyigR .marker.cross{stroke:#333333;}#mermaid-svg-pXbsElnItDOcyigR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pXbsElnItDOcyigR p{margin:0;}#mermaid-svg-pXbsElnItDOcyigR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pXbsElnItDOcyigR .cluster-label text{fill:#333;}#mermaid-svg-pXbsElnItDOcyigR .cluster-label span{color:#333;}#mermaid-svg-pXbsElnItDOcyigR .cluster-label span p{background-color:transparent;}#mermaid-svg-pXbsElnItDOcyigR .label text,#mermaid-svg-pXbsElnItDOcyigR span{fill:#333;color:#333;}#mermaid-svg-pXbsElnItDOcyigR .node rect,#mermaid-svg-pXbsElnItDOcyigR .node circle,#mermaid-svg-pXbsElnItDOcyigR .node ellipse,#mermaid-svg-pXbsElnItDOcyigR .node polygon,#mermaid-svg-pXbsElnItDOcyigR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pXbsElnItDOcyigR .rough-node .label text,#mermaid-svg-pXbsElnItDOcyigR .node .label text,#mermaid-svg-pXbsElnItDOcyigR .image-shape .label,#mermaid-svg-pXbsElnItDOcyigR .icon-shape .label{text-anchor:middle;}#mermaid-svg-pXbsElnItDOcyigR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pXbsElnItDOcyigR .rough-node .label,#mermaid-svg-pXbsElnItDOcyigR .node .label,#mermaid-svg-pXbsElnItDOcyigR .image-shape .label,#mermaid-svg-pXbsElnItDOcyigR .icon-shape .label{text-align:center;}#mermaid-svg-pXbsElnItDOcyigR .node.clickable{cursor:pointer;}#mermaid-svg-pXbsElnItDOcyigR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pXbsElnItDOcyigR .arrowheadPath{fill:#333333;}#mermaid-svg-pXbsElnItDOcyigR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pXbsElnItDOcyigR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pXbsElnItDOcyigR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pXbsElnItDOcyigR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pXbsElnItDOcyigR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pXbsElnItDOcyigR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pXbsElnItDOcyigR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pXbsElnItDOcyigR .cluster text{fill:#333;}#mermaid-svg-pXbsElnItDOcyigR .cluster span{color:#333;}#mermaid-svg-pXbsElnItDOcyigR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pXbsElnItDOcyigR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pXbsElnItDOcyigR rect.text{fill:none;stroke-width:0;}#mermaid-svg-pXbsElnItDOcyigR .icon-shape,#mermaid-svg-pXbsElnItDOcyigR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pXbsElnItDOcyigR .icon-shape p,#mermaid-svg-pXbsElnItDOcyigR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pXbsElnItDOcyigR .icon-shape .label rect,#mermaid-svg-pXbsElnItDOcyigR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pXbsElnItDOcyigR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pXbsElnItDOcyigR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pXbsElnItDOcyigR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提问
向量检索
知识图谱检索
语义相关的Top-K块
沿关系链推理出的相关实体
合并与去重
融合后的上下文
既有语义又有推理
LLM生成答案
5.4 LlamaIndex 中的知识图谱索引
python
from llama_index.core import KnowledgeGraphIndex
from llama_index.core import StorageContext
# 从文档中构建知识图谱
kg_index = KnowledgeGraphIndex.from_documents(
documents,
storage_context=storage_context,
max_triplets_per_chunk=10, # 每块最多抽取10个三元组
include_embeddings=True # 同时保留向量索引
)
# 查询时可以指定使用KG
query_engine = kg_index.as_query_engine(
include_text=True, # 包含原文
response_mode="tree_summarize",
retriever_mode="hybrid" # 混合模式:KG+向量
)
5.5 适用场景总结
| 检索策略 | 适合的文档类型 | 解决的核心问题 |
|---|---|---|
| 基础向量搜索 | 独立、短小的文档 | --- |
| 句子窗口检索 | 知识点分散的教程 | 上下文缺失 |
| 自动合并检索 | 细粒度分块的文档 | 信息碎片化 |
| 递归检索 | 层级化的书籍/手册 | 宏观概念搜索 |
| KG+向量融合 | 实体关系密集的文档 | 跨实体推理 |
思考 && 总结
LlamaIndex 真正拉开与普通RAG差距的地方就在于这些高级检索策略:
- 句子窗口检索是最容易上手也最立竿见影的优化: 用小块embedding保证匹配精度,用窗口扩展保证上下文完整。一个参数就能显著改善答案质量。
- 自动合并检索对付的是"分块强迫症": 为了高召回率把文档切得很细,但LLM又需要完整的上下文,自动合并正好解决了这个矛盾------搜的时候用小块,返回的时候合并成大块。
- 递归检索是处理书籍和手册级长篇文档的唯一选择: 先用摘要/标题层定位到章节,再在章节内做细粒度检索,这完全模拟了人类的阅读方式。
- 知识图谱补上了向量检索最大的短板------推理能力: 语义相似度≠逻辑关系。当你的文档里实体关系密集(企业关系、技术依赖、因果链条),KG+向量的双索引融合是不二之选。
- 四种策略可以组合使用: 句子窗口+自动合并、递归+KG,它们不是互斥的。实际的RAG系统往往是多策略的组合拳。
基础RAG做到60分很容易,但从60分到90分,靠的就是这些高级检索策略。下一节我们对比LangChain和LlamaIndex在这方面的差异。
结尾
各位小伙伴,本文的内容到这里就全部结束了,源码骑士在这里再次感谢您的阅读!
源码骑士 --- Android Framework & 全栈开发
👀 关注:跟博主一起从源码视角深耕底层原理,见证每一次成长
❤️ 点赞:让优质内容被更多人看见,让知识传递更有力量
⭐ 收藏:把核心知识点存好,在需要时随时查、随时用
💬 评论:分享你的经验或疑问,评论区一起交流避坑
🔄 一键四连:不要忘记给博主"一键四连"哦!
🗡️ 寄语:技术之路难免有困惑,但同行的人会让前进更有方向
结语:检索是RAG的"嗓子眼"------向量搜索再准、分块策略再好,如果检索策略用错了,整个系统的答案质量就卡在这里。把本文的四种高级检索策略记牢,下次用户反馈"搜不到"时,你就知道该换哪把武器了。不要忘记给博主"一键四连"哦!