RAG 中父子分块检索怎么做?长文档和多跳问题如何补全上下文?
简化版
父子分块把文档切两遍:小的子块参与检索(语义集中,找得准),命中后把它所属的大父块交给模型(上下文完整,答得全),也就是「小块用来找,大块用来答」。答案跨越相邻段落时,可以按需做邻居扩展补前后片段。多跳问题的证据分散在多处,一次 Top-k 检索往往不够,要先分解子问题再迭代检索,每一步保留来源、证据不足就停,避免错误中间结论继续传播。关键——不能简单把 Top-k 调大(大量无关上下文会增成本,还触发「中间遗忘」)。
详细版
补全上下文的常见策略:
- 父子检索:小子块匹配、返回较完整父块;
- 邻居扩展:命中一个 chunk 后补同文档前后片段;
- 层次摘要:为章节/文档建摘要索引,先定位范围再深入原文;
- 问题分解:多跳问题拆成多个子问题,按依赖顺序检索;
- 迭代检索:从首轮证据抽取实体/线索,再发起下一轮;
- 证据图:把实体、关系、来源组织起来支持跨文档查询。
前三种解决「找到了但上下文不够」,后三种解决「一次找不全」。应根据问题动态选检索轮数、上下文窗口、停止条件。
完整版教学
一、父子检索解决什么
小块匹配更精确,却可能缺标题、定义、例外条款;大块上下文完整,却因为一段里混着几件事而不容易被命中。父子检索为每个小块记录所属父块,两种尺寸各干各的活:
命中【子块】"逾期利率为 0.05%/天"(精确匹配)
→ 返回【父块】"第五条 违约责任:...逾期利率为 0.05%/天...(含前提和例外)"
→ 生成模型拿到完整上下文
适合章节结构明确的手册、合同、技术文档。有两条使用原则:父块回填放在重排之后——重排拿问题和片段一起打分,子块语义集中打分才准,换成父块再重排判断会变模糊;父块不宜过大——过大会重新引入噪声,可只返回命中句周围窗口并保留标题路径。
二、邻居扩展的适用场景
若答案跨越相邻段落,可在命中块前后补 1-2 个块。但要校验:必须同文档、同章节、连续位置——不能把索引里相邻但原文无关的块硬拼。
优点:邻居扩展比固定大 overlap 更省索引空间,因为只在查询时按需取上下文,而非建库时就冗余存储。
三、什么是多跳问题(单跳 vs 多跳)
单跳(一段证据直接答):"产品 A 的保修期多久?"
多跳(连接多个事实):"产品 A 的负责人所在部门今年发布了哪些项目?"
需要:① 找负责人 → ② 找他的部门 → ③ 找该部门项目
如果直接把完整问题编码成一个向量,多个关系被压缩在一起,而单个文档往往只覆盖其中一跳,因而未必与整句高度相似。这是单轮 Top-k 检索在多跳问题上常见的失败机制,但具体能否命中仍取决于语料、模型与问题表达。父子检索和邻居扩展只能补全一处证据的上下文,补不出分散在别处的另一跳。
四、问题分解与迭代检索
规划子问题(有依赖):
1. 产品 A 的负责人是谁? → 检索得到"张三"
2. 张三属于哪个部门? → 用"张三"检索得到"研发部"
3. 研发部今年发布了哪些项目? → 用"研发部"检索
每步保存:文档 ID + 原文片段 + 置信信号
关键原则:某一步没有可靠证据时应停止或换查询,而不是让模型猜一个中间答案继续(否则错误逐步传播)。互不依赖的子问题可并行检索降延迟。
五、层次检索与停止条件
长文档建「文档摘要 → 章节摘要 → 原始片段」多级索引,先按问题选文档/章节,再在限定范围搜细节。适合「总结整份报告主要风险」这类范围型问题。但摘要会漏细节,最终事实要回到原始片段。
迭代检索可能无限扩散,生产系统必须限制:最大跳数、每跳候选数、总 token,并在证据已覆盖问题要点时停止。可缓存子查询结果、并行无依赖步骤、用轻量模型做规划。
多跳链路每增加一步都会传播召回误差和生成假设,因此必须保留证据路径、设置停止条件,并验证最终答案是否由检索证据支持。
六、常见误区与追问
- 误区:多跳问题把 Top-k 调大就行。 大量无关上下文增成本、触发中间遗忘,反而更差,要分解+迭代。
- 误区:长上下文能自动解决多跳。 研究表明关键信息在中间时模型利用下降(lost in the middle),仍要先筛选组织证据。
- 误区:邻居扩展可以随便拼相邻块。 必须校验同文档/同章节/连续位置,否则拼进无关内容。
- 误区:层次摘要可以当最终事实。 摘要会漏细节,事实要回到原始片段。
- 误区:父块回填越早做越好。 回填要放在重排之后,否则重排拿混杂多件事的父块打分,排序反而变差。
- 追问:父子检索兼顾了什么? 子块精确匹配 + 父块完整上下文,“找得准”和”读得全”兼得。
- 追问:为什么一次向量检索常难处理多跳? 多个关系压进一个向量,而单个文档通常只覆盖一跳,相关证据可能排不到前列。
- 追问:中间步骤没证据怎么办? 停止或换查询,绝不让模型猜中间答案继续(防错误传播)。
- 追问:迭代检索怎么防无限扩散? 限最大跳数/每跳候选/总 token,证据覆盖要点即停,缓存+并行降本。
七、策略判断表
| 策略 | 检索单位 | 返回上下文 |
|---|---|---|
| 固定 Chunk | 同一文本块 | 命中的块 |
| Parent-Child | 小块 | 对应父块 |
| 邻居扩展 | 命中块 | 前后相邻块 |
| Multi-hop | 当前问题/中间问题 | 多轮证据链 |
八、加强记忆
补上下文记「小块找、大块答」:父子检索让子块负责精确匹配、父块负责完整上下文,回填放在重排之后;邻居扩展按需补前后片段,要校验同文档连续位置,比大 overlap 省空间;长文档靠层次摘要先定范围再回原文。多跳记「沿线索连续找卡」:单跳”找到一张卡就能答”,多跳”分解子问题→迭代检索(每步用上步实体、保留证据、无证据即停)“。核心认知钉死:别简单调大 Top-k(增噪+中间遗忘)、长上下文不自动解决多跳、每一步都要证据链兜底不让模型猜、迭代要设停止条件。
项目实战落地
项目里怎么做的
《AI Agentic RAG高级企业知识库平台》的「父子分块-制度手册」策略把文档切两遍:父块 1200 字、子块 300 字、子块之间重叠 30 字,父块之间不重叠。切分结果都存在 knowledge_chunk 表里,靠 chunk_type(普通块、父块、子块)和 parent_id 区分层级。
- 只有子块参与检索。 向量化时只给普通块和子块生成向量,父块刻意跳过;向量检索和 BM25 的候选也都只取这两类。
- 回填放在链路最后。 检索顺序是「查询改写 → 双路召回 → RRF 融合 → 重排 → 父块回填 → 阈值过滤」,重排之前全程用子块。
- 回填时合并同父。 命中的子块换成它的父块,几个子块属于同一个父块时只保留一份,排序位次和分数沿用排在最前面的那个子块。
- 保留命中痕迹。 回填后的结果记下
matched_chunk_id,来源标成「……→父块回填」,页面上能追溯到实际匹配的是哪一小段。
项目里三套检索策略,只有「完整-混合检索加重排加改写」打开了父块回填开关。
为什么这样取舍
- 父块之间不重叠。 父块要整块交给模型,重叠只会让模型读到大段重复内容。
- 回填不提前。 父块里混着好几条规定,拿它去重排,相关性判断会变模糊。
面试官还会追问
- 父块被删了或者数据不一致,回填时找不到父块,这条结果会怎样?
- 切的时候用了父子分块,检索策略却没开父块回填,效果为什么反而比普通分块还差?
学完《AI Agentic RAG高级企业知识库平台》,上面这些追问你都会迎刃而解。