1 什么是分层检索(Hierarchical Retrieval)
P1 · rag
🏷 标签:rag, hierarchical-retrieval, long-document, chunking, structure
1️⃣ 考察意图
面试官想考察你是否能跳出“平面切块+Top-K”的思维定式,真正理解长文档检索中结构利用的价值。这是典型的系统设计+工程取舍题,刁钻点在于:很多人只会背“先粗后细”的概念,但说不清层级粒度怎么选、索引如何建、检索效率与召回率如何平衡。答好了能展示你对RAG系统瓶颈(长上下文噪声、chunk碎片化)的深刻理解,以及设计可扩展检索架构的硬实力。
2️⃣ 标准答
分层检索(Hierarchical Retrieval)的核心思想是:对长文档按自然结构(如书籍的章-节-段、论文的摘要-方法-实验)建立多级索引,检索时从高层级(如章节摘要)粗筛,再定位到低层级(如具体段落)细查。这解决了平面chunking在长文档中的两大问题:一是chunk过多导致检索噪声(比如500页文档切1000个chunk,query可能匹配到无关段落);二是跨chunk的上下文丢失(比如答案分布在两个相邻chunk)。
层级构建的三种策略:
- 基于文档结构(最优):利用Markdown标题、PDF大纲、HTML标签等天然层级。例如对维基百科页面,按
H1→H2→段落建树,每个节点存文本摘要+子节点指针。优势是语义边界清晰,缺点是依赖文档格式规范。 - 递归分割(通用):用LangChain的
RecursiveCharacterTextSplitter按分隔符优先级(\n\n>\n> 句号)逐层切分,生成父子chunk。例如父chunk 2000 tokens,子chunk 500 tokens,父子通过ID关联。优势是普适性强,但可能破坏语义单元。 - 语义聚类(进阶):用embedding聚类+LLM总结生成伪层级。例如对财报PDF,先切段落,再用K-means聚类成“财务指标”“风险提示”等主题簇,每个簇生成摘要作为父节点。适合无结构文档,但计算成本高。
检索流程(以基于文档结构为例):
- 粗筛:用BM25或embedding检索所有父节点(章节摘要),Top-3父节点。
- 精定位:在选中的父节点下,用相同检索器搜索子节点(段落),取Top-5子节点。
- 合并:将子节点按原始文档顺序拼接,作为LLM上下文。注意去重(父节点内容可能包含子节点摘要)。
实际落地的坑与解法:
- 坑1:层级深度选择。太深(如章-节-段-句)导致检索延迟翻倍(每层一次检索),太浅(如只有章-段)退化为平面检索。解法:固定2-3层,用
HNSW索引父节点(支持快速近似搜索),子节点用Flat索引(保证精度),实测3层时延迟增加<20%,Recall@5提升15-30%(【通用知识】)。 - 坑2:跨层级上下文丢失。比如答案需要“方法A的公式”和“实验B的结果”,但分属不同父节点。解法:在粗筛阶段,对父节点做“膨胀”——返回Top-3父节点后,额外返回每个父节点的相邻父节点(前后各1个),确保边界覆盖。
- 坑3:索引更新成本。文档更新时,父子关系可能变化。解法:用
Dirty Flag标记变更的父节点,增量重建其子节点索引,避免全量重建。
工程取舍:
- 检索效率 vs 召回率:分层检索牺牲了部分效率(多一次检索),但通过缩小搜索空间(从1000个chunk到30个父节点+150个子节点)提升了召回率。实测在50页PDF上,分层检索比平面Top-20 chunk的Recall@5高22%,但延迟增加35%(【通用知识】)。如果延迟敏感,可用
ColBERT的后期交互(late interaction)替代第二次检索,将子节点搜索转为向量打分,降低延迟。 - 结构依赖 vs 通用性:基于文档结构的方法效果最好,但无法处理无结构文本。折中方案是先用LLM或正则提取结构(如用
spaCy的Doc对象识别段落边界),再建层级。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从定义、构建策略、检索流程三个层面回答。定义上,分层检索是对长文档按章-节-段建多级索引,先粗筛父节点再精搜子节点。构建策略有三种:基于文档结构、递归分割、语义聚类,我推荐用结构+递归分割的组合。检索流程分三步:粗筛父节点、精搜子节点、合并去重。总结一句:分层检索通过结构利用,在长文档场景下以可控的延迟增加换取显著的召回率提升。”
4️⃣ 高频追问 & 应对
追问 1:如果文档没有标题结构(比如纯文本小说),你怎么建层级?
用递归分割+语义锚点。先用
RecursiveCharacterTextSplitter按段落切分(默认分隔符\n\n),然后对每个段落用LLM生成一句话摘要(prompt:“用一句话概括这段内容”),将摘要作为父节点。检索时,粗筛用摘要embedding,精搜用段落原文。注意:摘要生成成本高,可改用Sentence-BERT的mean pooling作为段落embedding,再对相邻段落做合并(如果embedding余弦相似度>0.8,合并为一个父节点),减少父节点数量。
追问 2:分层检索和RAPTOR(递归抽象处理树)有什么区别?
核心区别在层级生成方式。分层检索的层级是静态的,基于文档结构或固定分割;RAPTOR是动态的,先切chunk,再用聚类+LLM摘要递归生成更高层节点(类似树状摘要)。RAPTOR的优势是能捕捉跨chunk的语义抽象(比如多个段落共同描述一个概念),但计算成本高(每层需要LLM摘要)。适用场景:分层检索适合结构清晰的文档(如技术手册),RAPTOR适合需要语义归纳的文档(如研究报告)。工程上,RAPTOR的树深度通常为2-3层,每层聚类数设为chunk数的10%。
追问 3:如何评估分层检索的效果?用什么指标?
用Recall@k和MRR评估检索质量,用P99延迟评估效率。具体做法:构建一个QA数据集,每个问题标注答案所在的父节点和子节点。对比分层检索 vs 平面Top-k chunk:分层检索的Recall@5应更高(因为减少了噪声),但P99延迟可能增加。另外,用上下文利用率(LLM生成答案中来自检索chunk的token占比)评估是否有效利用了结构。如果上下文利用率低,说明层级粒度太粗或检索策略有问题。
5️⃣ 避坑 · 常见错误答法
- ❌ 说“分层检索就是先搜大块再搜小块,和平面检索差不多,只是多了一步过滤” → ✅ 正确切入:分层检索的核心是利用文档结构缩小搜索空间,不是简单过滤。平面检索的Top-K可能漏掉相关段落(因为embedding相似度被噪声稀释),而分层检索通过父节点粗筛,将搜索范围从全局缩小到局部,本质是搜索策略的优化。
- ❌ 说“层级深度越深越好,因为能更精细定位” → ✅ 正确切入:层级深度增加会带来延迟线性增长(每层一次检索),且过深可能导致父节点语义模糊(比如“句子”级别的父节点信息量不足)。工程上建议2-3层,并用
HNSW索引父节点加速。 - ❌ 说“分层检索只适合长文档,短文档用平面检索就行” → ✅ 正确切入:短文档(<5页)确实平面检索足够,但分层检索在多文档聚合场景也有用。比如检索10篇论文的“方法”部分,可以建“论文标题→方法章节→具体段落”的层级,跨文档检索时先粗筛相关论文,再精搜方法段落。
6️⃣ 简历呼应
- 如果你有RAG项目:从“我在XX项目中用分层检索处理了100+页的PDF文档”切入,具体说明你用了哪种层级构建策略(基于文档结构/递归分割),以及如何解决跨层级上下文丢失(比如用父节点膨胀)。强调Recall@5提升20%+,延迟增加<30%。
- 如果你只做过传统NLP:用“文档摘要”类比迁移。比如“传统文本摘要中,我们会对长文档先分章节再摘要,分层检索类似——先对章节建摘要索引,再定位到具体段落”。展示你对结构利用的通用理解。
- 如果你是校招无项目:聚焦论文复现。比如“我复现了RAPTOR论文(递归抽象处理树),在ArXiv数据集上实现了分层检索,对比了不同层级深度对Recall的影响”。展示你对前沿方法的理解。
- 论文:RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval(2024)
- 论文:Dense Passage Retrieval for Open-Domain Question Answering(DPR, 2020)
- 工具:LangChain RecursiveCharacterTextSplitter 文档
- 博客:Pinecone 的“Hierarchical Retrieval for Long Documents”教程
- 论文:ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT(2020)