1. 为什么RAG需要父子索引?核心痛点解析
在传统RAG(检索增强生成)流程中,开发者最常遇到的痛点就是"文档粒度困境"——当我们将一篇长文档(比如10页的PDF技术手册)直接切分成固定大小的文本块(如512个token)进行向量化存储时,会出现两种典型问题:
-
检索阶段:查询可能匹配到某个细碎的文本片段,但这个片段缺乏足够的上下文信息。比如搜索"Langchain的异步调用优化"时,可能只返回一个包含该短语的句子,而丢失了前后文的关键参数说明和代码示例。
-
生成阶段:LLM拿到的检索结果可能是零散的几个文本块,需要自行拼凑上下文,容易导致生成内容不连贯。实测显示,这种情况下生成结果的准确率会下降30-40%。
父子索引(Parent-Document Retrieval)的核心理念是建立两层结构:
- 子文档:仍按常规方式切分文本块(保持检索精度)
- 父文档:保留更大的上下文单元(如完整章节或逻辑段落)
当检索到相关子文档时,系统会返回其所属的整个父文档作为上下文。这就好比在图书馆找资料时,先通过目录定位到具体段落(子文档),然后直接借阅整章内容(父文档)进行深度阅读。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 父子索引的工程实现关键点
2.1 文档分片策略设计
在Langchain中实现父子索引时,分片策略直接影响最终效果。以下是经过实战验证的三种分片方法:
python复制from langchain.text_splitter import RecursiveCharacterTextSplitter
# 方法1:固定大小分片(基础版)
child_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
# 方法2:按标题层级分片(推荐)
parent_splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "H1"), ("##", "H2")]
)
# 方法3:语义分片(高级)
from semantic_text_splitter import TextSplitter
splitter = Text
