在 RAG 系统中,文档的切块(chunking)方式直接决定了检索质量和生成效果。切得太大,检索时容易引入噪音,语义匹配变得模糊;切得太小,虽然检索更精准,但上下文信息不足,生成模型难以给出完整准确的回答。父子分块策略就是为了同时兼顾检索精确性和生成完整性而设计的一种实用方法。
1. 什么是父子分块
父子分块的核心思想很直观:
- 子块(child chunk):用来做检索的小粒度文本片段。通常按语义或固定长度切成较小的段落、句子甚至短语,使问题和文档片段之间的语义匹配更精准。
- 父块(parent chunk):用来做生成的大粒度上下文。当某个子块被检索命中后,系统会返回该子块所属的更大范围文本,甚至整个章节或整篇文档,以确保生成模型有足够的信息来理解背景、避免断章取义。
简单说就是:用小块去搜,用大块去喂给模型生成。
2. 为什么需要父子分块
只用小块或只用大块都有明显缺陷:
只用小块的坏处
- 信息残缺:比如检索到“年假天数为 18 天”这个小片段,但缺失了适用人群、生效日期等上下文,模型只能猜测,容易给出不完整甚至错误的回答。
- 阅读不连贯:若一个问题需要综合多个小节的信息,给模型的上下文是十来个互相没有衔接的小片段,模型难以正确整合。
只用大块的坏处
- 检索精度下降:一篇 2000 字的政策文档被整体当做一块,其中包含多种主题,但向量嵌入只能表达整体语义,造成问题“如何申请年假”与这个包含大量无关内容的块匹配度不高,容易被漏掉。
- 噪音过多:即使侥幸被检索到,大块中夹杂大量无关内容,会稀释关键信息,增加模型的认知负担,甚至诱发幻觉。
父子分块将两种粒度的优势结合起来:用子块确保精准检索,用父块保证完整的语境传递给生成模块。
3. 如何实施父子分块
实现父子分块并不复杂,常见的方法是:
a) 双层切分与关联
- 将文档按大粒度切分成父块,例如按章节、按标题段落、或按固定的大长度(如 2000 字符)切分。
- 在每个父块内部,再做更细粒度的子块切分,比如按 500 字符重叠切分,或按句子/自然段落切分。
- 在索引构建时,仅将子块的内容生成向量并存入向量数据库,同时记录每个子块属于哪个父块(通常存父子映射关系或存储父块的 ID/索引)。
b) 检索时的小块搜索、大块还原
- 用户提问时,用向量搜索匹配子块,返回 top‑k 个子块。
- 根据子块关联的父块 ID,将对应的父块取出来(注意去重,因为多个子块可能属于同一个父块)。
- 将取出的父块全文(或多个父块)作为上下文输入给 LLM 进行生成。
这样,检索的精确度由细粒度的子块保证,模型看到的上下文却是完整连贯的父块。
c) 简单替代方案:小块检索 + 上下文扩展
如果不想维护双层的块结构,也可以只用小块进行索引,但在检索后做一个上下文扩展:根据小块在原始文档中的位置,向前后各扩展若干字符或句子,取一个更大的片段。这类似于“动态拼出父块”,在工程上更简单,但需要对原始文档做快速定位,适合有全文存储的场景。
4. 一个真实场景示例
某公司用 RAG 解答技术产品规格查询。原始文档《数据采集器规格书》中,有一个父块是“电源要求”这一整节,内容包含输入电压、电流、适配器型号、功耗表格等,总长约 1500 字符。这个父块下划分了多个子块,如“输入电压:100‑240V AC”“功耗:最大 25W”等,每个子块约 50‑100 字符。
用户提问:“这个采集器最大功耗是多少?”
- 检索阶段:问题向量与子块“功耗:最大 25W”匹配得分最高。
- 还原阶段:系统根据映射关系,找到该子块所属的父块,即整个“电源要求”节。
- 生成阶段:模型读到完整的电源要求章节内容,不仅回答“最大功耗为 25W”,还能补充说明“典型功耗 15W,适配器规格等”。如果用户接着问相关适配器,由于父块已经包含了适配器信息,模型可一并作答,无需再次检索。
若只返回“功耗:最大 25W”这个子块,模型可能只能干巴巴地回答“25 瓦”,无法解释限制条件,也无法应对连续追问。
5. 父子分块的实际好处
- 检索质量更高:小块语义聚焦,嵌入匹配更准,减少漏检和误检。
- 回答更完整、准确:充足的上下文帮助模型理解术语、前提条件,减少断章取义造成的错误。
- 降低整体成本:相比只用大块,父子分块避免了让模型处理大量无关内容,节省 token;相比只靠小块后多次拼接,减少了碎片化带来的理解偏差。
- 灵活可调:可以独立调整子块大小(影响检索精度)和父块大小(影响生成完整性),解耦优化。
父子分块是 RAG 实践中很经典的一招,投入改造成本低,但效果提升明显,尤其适用于文档结构清晰、需要综合理解的知识密集型任务。