Skip to content

04.4 - RAPTOR 与分层检索

定位: 通过递归摘要构建分层知识树,从"细节"到"概览"多粒度检索——解决"单层分块"的深度不足问题 面试高频度: ⭐⭐⭐ 考查方式: RAPTOR 原理、树状结构、分层检索策略

一、这是什么?为什么需要它?

是什么

RAPTOR(Recursive Abstractive Processing for Tree-Organized Retrieval)是一种分层检索架构,通过递归摘要将文档组织成树状结构,实现从细节到概览的多粒度检索。

传统分块:                  RAPTOR 树状结构:
  [块1] [块2] [块3]           [根节点:全书摘要]
                              /              \
  (所有块在同一层)       [章摘要]          [章摘要]
                            /    \            /    \
                       [节摘要] [节摘要] [节摘要] [节摘要]
                         |  |    |  |    |  |    |  |
                        块...  块...  块...  块...

为什么需要分层检索?

传统 RAG 的问题:
  检索只在一个粒度上工作——文档块的大小是固定的。

  问题 1:粒度过细
    "简述公司的发展历史" -> 检索到的可能是一段细节,而非整体概述
    你需要的是"宏观层次"的摘要信息,但检索到的只有"微观层次"的碎块

  问题 2:粒度过粗
    "公司2023年第3季度在北京的营收是多少?" -> 在整段概述中找不到
    你需要的是"微观层次"的具体数据

RAPTOR 的解法:
  构建不同粒度的索引层
  - 顶层:概括性摘要(回答宏观问题)
  - 中层:章节摘要(回答中等粒度问题)
  - 底层:原始块(回答具体细节问题)
  
  检索时:在多层中同时检索,根据问题自动匹配最合适的粒度

二、原理拆解

2.1 RAPTOR 树构建流程

+------------------------------------------------------------------+
|                    RAPTOR 树构建流程                               |
|                                                                   |
|  原始文档(假设是整个公司知识库)                                   |
|                                                                   |
|  步骤 1:分块(最底层)                                           |
|  将文档切成基础块(chunks)                                        |
|  [块1] [块2] [块3] [块4] [块5] [块6] ...                          |
|                                                                   |
|  步骤 2:聚类                                                    |
|  用 Embedding 对块进行聚类(相似内容的块分成一组)                   |
|  组1: [块1, 块2, 块3]    组2: [块4, 块5, 块6]                     |
|  组3: [块7, 块8]         ...                                     |
|                                                                   |
|  步骤 3:生成摘要                                                |
|  每组 -> LLM 生成摘要                                              |
|  组摘要1: "3个块的综合摘要..."                                     |
|  组摘要2: "3个块的综合摘要..."                                     |
|                                                                   |
|  步骤 4:递归                                                    |
|  把生成的摘要作为新一层的节点                                      |
|  对新层再次聚类+摘要 -> 更高层的摘要                                |
|                                                                   |
|  重复直到聚类结果只剩一组 -> 根节点(全书摘要)                    |
|                                                                   |
|  结果:一个多层次的树状结构                                         |
|  根节点:全书摘要                                                  |
|     ├ 中间层1: 章节摘要A            ├ 中间层B: 章节摘要B            |
|     ├ 底层1: [块1, 块2, 块3]        ├ 底层2: [块4, 块5, 块6]      |
+------------------------------------------------------------------+

2.2 RAPTOR 检索策略

RAPTOR 支持两种检索模式:

模式 1:自顶向下(Top-down)

从根节点开始检索:
  1. 在根节点层检索 -> 找到最相关的摘要
  2. 进入该摘要的子节点 -> 在子节点中检索
  3. 继续向下 -> 直到找到最具体的块

特点:
  - 先看宏观,再找微观
  - 适合先理解背景再深入的问题

模式 2:全层检索(All-layer)

同时在所有层检索:
  根节点检索 + 中间层检索 + 底层检索
  合并各层的结果 -> Top-K

特点:
  - 一次获得多个粒度的信息
  - 适合综合性问题

2.3 RAPTOR vs 传统分块对比

维度传统分块RAPTOR
知识粒度单一粒度多层粒度
宏观问题找不到摘要顶层摘要直接命中
微观问题精确命中底层块精确命中
构建成本低(一次分块)高(多次 LLM 摘要)
存储成本较高(多层)
检索延迟略高(多层检索)
上下文利用率底层可能信息过载层级自动匹配

三、图解全景

分层检索如何工作

用户提问:"简述公司的发展历史和主要业务"

传统检索:
  [块 xx: 公司成立于2010年...]  <- 只找到细节,没有整体观
  [块 yy: 主要业务包括AI和云...] <- 没有历史全貌

RAPTOR 分层检索:
                        [根节点:公司整体发展概述]
                        (找到了!综合了历史和业务)
                       /                      \
   [早期发展摘要]                     [业务转型摘要]     <- 中间层
      /          \                      /         \
  [2010成立] [2015融资]    [2020AI业务] [2023云业务]  <- 底层细节

  检索结果:
  顶层:公司整体概述(适合回答"简述")
  中层:发展阶段和业务线(补充细节)
  底层:具体事件(如果需要)

四、实战验证

4.1 RAPTOR 的简化实现思路

python
# RAPTOR 的简化实现:递归摘要树

from langchain_openai import ChatOpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
import numpy as np

class SimpleRAPTOR:
    def __init__(self, documents, embedding_model, llm):
        self.llm = llm
        self.embedding_model = embedding_model
        self.tree = self._build_tree(documents)

    def _summarize(self, texts):
        """生成摘要"""
        combined = "\n\n".join(texts)
        prompt = f"请对以下内容生成一段综合摘要(保留关键信息):\n\n{combined}"
        return self.llm.invoke(prompt).content

    def _cluster(self, texts, embeddings, n_clusters=3):
        """简化版:按内容相似度聚类"""
        # 实际实现可用 KMeans 或社区检测
        # 这里简化为固定大小分组
        if len(texts) <= n_clusters:
            return [texts]
        chunk_size = max(1, len(texts) // n_clusters)
        return [texts[i:i+chunk_size] for i in range(0, len(texts), chunk_size)]

    def _build_tree(self, texts, depth=0):
        """递归构建摘要树"""
        if len(texts) <= 3 or depth > 3:
            return {"level": depth, "nodes": texts, "summary": self._summarize(texts)}
        
        clusters = self._cluster(texts, None)
        children = []
        for cluster in clusters:
            child = self._build_tree(cluster, depth + 1)
            children.append(child)
        
        summaries = [c["summary"] for c in children]
        node_summary = self._summarize(summaries)
        
        return {
            "level": depth,
            "summary": node_summary,
            "children": children
        }

    def retrieve(self, query, top_k=3):
        """多层检索:同时检索所有层"""
        results = []
        query_emb = self.embedding_model.encode([query])[0]
        self._search_tree(self.tree, query_emb, results)
        results.sort(key=lambda x: x[1], reverse=True)
        return [r[0] for r in results[:top_k]]

    def _search_tree(self, node, query_emb, results):
        node_emb = self.embedding_model.encode([node["summary"]])[0]
        sim = np.dot(query_emb, node_emb)
        results.append((node["summary"], sim))
        if "children" in node:
            for child in node["children"]:
                self._search_tree(child, query_emb, results)

五、面试视角

问题答案要点
RAPTOR 解决了什么核心问题?传统 RAG 只有单一粒度(文档块),无法满足"宏观概览"和"微观细节"的不同需求。RAPTOR 通过多层树状结构,提供从全局到细节的多粒度知识
RAPTOR 的构建成本有多高?较高。每层需要 LLM 生成摘要,N 个文档构建深度为 d 的树需要约 (层节点数) 次 LLM 调用。对于大型知识库,构建成本可能是传统索引的 5-20 倍
RAPTOR 适合什么场景?文档结构清晰、内容有层次关系(如教科书、技术文档、公司制度)、问题粒度多样化(从概况到细节都可能被问到)。不适合:碎片化知识、简短文档集合
RAPTOR 和 Graph RAG 的区别?RAPTOR 用树状结构组织文本摘要(层次化压缩)。Graph RAG 用图结构组织实体关系(结构化推理)。两者可结合使用

📚 相关链接

  • **文本分块策略** — 分块是 RAPTOR 的基础
  • **GraphRAG** — 另一种结构化增强方案
  • **上下文窗口管理** — 分层摘要也是窗口管理的高级策略
  • <- 返回 **进阶RAG索引**

Knowledge4J — Java 知识库