传统 RAG 的困境

如果你用过 RAG(检索增强生成),应该熟悉这套流程:

  1. 文档切片(chunking)
  2. 向量化(embedding)
  3. 存入向量数据库
  4. 查询时检索 Top-K 相似片段
  5. 喂给 LLM 生成答案

这套方案有个致命问题:切片粒度很难把握

切太小,语义不完整;切太大,噪音太多。更麻烦的是,向量相似度检索本质上是模糊匹配——它能找到相关的内容,但不一定能找到精确的内容。

比如你问项目预算在第几章?,向量检索可能返回一堆提到预算的片段,却无法告诉你精确的章节位置。

PageIndex 的思路:给 AI 一张地图

PageIndex 的核心理念很简单:不用向量,用结构。

它把文档解析成一棵层级树:

文档
├── 第一章 概述
│   ├── 1.1 项目背景
│   └── 1.2 目标与范围
├── 第二章 技术方案
│   ├── 2.1 架构设计
│   └── 2.2 技术选型
└── 第三章 实施计划

这棵树直接放在 LLM 的上下文窗口里。检索时,LLM 像人一样读目录找答案:

  • 问题:架构设计在哪? → LLM 定位到 第二章 > 2.1 架构设计
  • 问题:项目总体目标是什么? → LLM 定位到 第一章 > 1.2 目标与范围

这就是 推理即检索(Reasoning-based Retrieval)。

技术实现:从文档到树状索引

PageIndex 支持 PDF 和 Markdown 两种文档格式。

PDF 处理流程

PDF 是最难处理的格式,因为它的结构往往藏在排版里,而不是代码里。

PageIndex 的处理逻辑:

PDF 输入
Step 1: PDF 解析(提取每页文本,计算 token 数)
Step 2: 目录检测(扫描前 N 页,判断是否有目录)
Step 3: 结构生成
    ├── 有目录 + 有页码 → 直接解析
    ├── 有目录 + 无页码 → LLM 匹配章节位置
    └── 无目录 → LLM 从文本推断结构
Step 4: 标题验证(检查章节是否真的出现在对应页)
Step 5: 后处理(生成树结构、节点 ID、摘要)
输出 JSON 结构

三种目录场景的智能处理是亮点:

场景处理方式
有目录 + 有页码直接解析,计算物理页码偏移
有目录 + 无页码LLM 遍历文档匹配章节起始位置
无目录将页面分组,LLM 逐组提取结构

Markdown 处理流程

Markdown 天然有层级结构(#######),处理起来简单得多:

Markdown 输入
Step 1: 读取文件,按行分割
Step 2: 正则提取标题节点(跳过代码块内的标题)
Step 3: 提取每个标题下的文本范围
Step 4: 树瘦身(可选,合并过于细碎的节点)
Step 5: 构建树结构
Step 6: 并发生成节点摘要
输出 JSON 结构

树瘦身(Tree Thinning)

对于层级过深的 Markdown 文档,PageIndex 提供了瘦身功能:

  • 计算每个节点的 token 数
  • 如果节点 token 数小于阈值,将子节点合并到父节点
  • 减少细碎节点,优化检索效果

检索阶段:无向量 RAG 的实现

索引构建完成后,检索就很简单了:

用户提问
Step 1: 加载文档树结构 JSON
Step 2: 构建节点摘要列表
Step 3: LLM 推理,选择最相关的节点(返回 node_id)
Step 4: 提取选中节点的完整文本
Step 5: 基于上下文生成答案

检索 Prompt 示例

你是一个文档检索助手。根据问题,从以下节点中找出最可能包含答案的节点。

问题: {用户的问题}

可用节点:
- 0001: 第一章 概述 - 本文档介绍了项目的整体背景和目标...
- 0002: 第二章 技术方案 - 详细描述了系统架构和技术选型...
- 0003: 第三章 实施计划 - 包含项目的时间节点和里程碑...

请只返回一个 JSON 数组,包含最相关的 node_id(最多3个)

LLM 返回 ["0002"],系统就去提取节点 0002 的完整内容。

与传统向量 RAG 的对比

维度传统向量 RAGPageIndex
依赖组件向量数据库(Pinecone、Milvus 等)无需额外组件
切片策略需要精心设计自动结构化
检索方式向量相似度匹配LLM 语义推理
可解释性较差(返回相似片段,但不知道来自哪)好(返回具体节点 ID 和位置)
上下文质量可能包含噪音精准章节定位
适用场景通用问答结构化文档、专业领域

核心优势

1. 降低系统复杂度

不需要部署向量数据库,不需要调切片参数,不需要维护索引。一个 JSON 文件搞定。

2. 精准定位

传统 RAG 返回的是相似片段,PageIndex 返回的是具体章节。后者更接近人类的检索方式。

3. 可解释

每个答案都能追溯到具体的节点 ID。用户可以验证:哦,答案来自第三章 3.2 节。

4. 层级灵活

可以回答概览级问题(这份报告讲什么?),也可以回答细节问题(第三章的实施步骤是什么?)。

快速上手

安装

git clone https://github.com/VectifyAI/PageIndex.git
cd PageIndex
pip install -r requirements.txt

处理 PDF

python run_pageindex.py \
    --pdf_path ./documents/report.pdf \
    --model qwen3-max \
    --if-add-node-summary yes

处理 Markdown

python run_pageindex.py \
    --md_path ./documents/readme.md \
    --model qwen3-max \
    --if-thinning yes

执行 RAG 查询

python pageindex_rag_simple.py \
    --structure ./results/doc_structure.json \
    --query "文档主要内容是什么?"

局限性

PageIndex 不是银弹:

  1. 依赖文档结构:如果文档本身没有清晰的结构(比如小说、散文),效果会打折扣
  2. LLM 成本:构建索引和检索都需要调用 LLM,成本比纯向量检索高
  3. 语言限制:目录检测和结构推断对中文 PDF 的效果可能不如英文
  4. 超长文档:如果文档结构树太大,超出上下文窗口,需要额外的分片策略

总结

PageIndex 代表了一种新的 RAG 范式:用结构化索引替代向量切片,用 LLM 推理替代相似度匹配

它不是要取代向量 RAG,而是提供了一个更适合结构化文档的方案。如果你的场景是处理技术文档、研究报告、法律合同这类有清晰层级的内容,PageIndex 值得一试。

GitHub: https://github.com/VectifyAI/PageIndex


参考资源: