摘要:本文深入剖析 PageIndex 的核心技术细节,详解 PDF/Markdown 文档的结构化索引构建流程、目录智能检测算法、LLM 驱动的树搜索检索机制,以及无向量 RAG 的完整实现原理。无论你是 RAG 技术研究者还是工程实践者,这篇技术解析都将为你揭示一种全新的文档检索范式。
⭐ GitHub 14K Stars |
🔗 https://github.com/VectifyAI/PageIndex
🔍 什么是 PageIndex?
在 AI 时代,如何让大模型更好地理解和检索长文档一直是一个挑战。传统的 RAG(检索增强生成)方案依赖向量数据库,需要将文档切片、向量化、存储,流程复杂且效果受限于切片策略。
PageIndex 提供了一种全新的思路:基于推理的无向量 RAG 框架。
它的核心理念是:
-
📖 结构化索引:将文档解析为树状层级结构 -
🧠 AI 推理检索:用大模型的语义理解能力替代向量相似度匹配 -
🎯 精准定位:直接定位到文档的具体章节,而非模糊的文本片段
📄 支持的文档类型
PageIndex 目前支持两种主流文档格式的处理:
|
|
|
|---|---|
|
|
|
| Markdown |
|
一、PDF 文档处理流程
PDF 是最常见的文档格式,但也是结构化难度最高的。PageIndex 通过多阶段处理,智能提取 PDF 的层级结构。
核心处理步骤
📥 PDF 输入↓📑 Step 1: PDF 解析提取每页文本,计算 token 数量↓📋 Step 2: 目录检测扫描前 N 页,判断是否存在目录↓🌳 Step 3: 结构生成├── 有目录有页码 → 直接解析目录结构├── 有目录无页码 → LLM 匹配章节位置└── 无目录 → LLM 从文本推断结构↓✅ Step 4: 标题验证验证章节标题是否出现在对应页面↓🔧 Step 5: 后处理生成树结构、节点 ID、摘要↓💾 Step 6: 输出 JSON
三种目录场景的智能处理
PageIndex 能够自动识别并处理三种不同的目录情况:
场景 A:有目录且有页码
-
直接解析目录内容为 JSON 结构 -
计算逻辑页码与物理页码的偏移量 -
自动转换为准确的物理页码
场景 B:有目录但无页码
-
解析目录获取章节标题 -
使用 LLM 遍历文档页面,匹配章节起始位置 -
智能填充物理页码索引
场景 C:无目录
-
将页面按 token 限制分组 -
使用 LLM 从文本中提取层级结构 -
逐组生成并合并结构
关键配置参数
|
|
|
|
|---|---|---|
--model |
qwen3-max |
|
--toc-check-pages |
20 |
|
--max-pages-per-node |
10 |
|
--if-add-node-summary |
yes |
|
二、Markdown 文档处理流程
Markdown 天然具有层级结构(# 到 ######),处理起来更加高效。
核心处理步骤
📥 Markdown 输入↓📖 Step 1: 读取文件按行分割文档内容↓🔍 Step 2: 提取标题节点正则匹配 # ~ ###### 标题跳过代码块内的标题↓📝 Step 3: 提取节点文本确定每个标题的文本范围计算标题层级↓✂️ Step 4: 树瘦身 [可选]合并过于细碎的节点↓🌳 Step 5: 构建树结构根据层级关系建立父子关系↓📋 Step 6: 生成摘要并发调用 LLM 生成节点摘要↓💾 Step 7: 输出 JSON
树瘦身功能
对于层级过深、节点过于细碎的 Markdown 文档,PageIndex 提供了树瘦身功能:
-
计算每个节点的 token 数量 -
如果节点 token 数小于阈值,将子节点合并到父节点 -
减少过于细碎的节点,优化检索效果
关键配置参数
|
|
|
|
|---|---|---|
--if-thinning |
no |
|
--thinning-threshold |
5000 |
|
--summary-token-threshold |
200 |
|
三、PDF vs Markdown 处理对比
|
|
|
|
|---|---|---|
| 结构识别 |
|
|
| 复杂度 |
|
|
| LLM 调用 |
|
|
| 处理时间 |
|
|
| 树瘦身 |
|
|
四、查询阶段:无向量 RAG 检索
索引构建完成后,PageIndex 提供了基于 LLM 推理的检索能力。
RAG 检索流程
❓ 用户提问↓📂 Step 1: 加载文档结构读取 JSON 结构文件创建节点映射↓🔍 Step 2: 树搜索检索├── 构建节点摘要信息├── 构建检索 Prompt├── LLM 推理选择最相关节点└── 解析返回的节点 ID↓📄 Step 3: 提取上下文从选中节点提取完整文本↓💬 Step 4: 生成答案基于上下文调用 LLM 生成答案↓✅ 输出结果
检索 Prompt 示例
你是一个文档检索助手。根据问题,从以下节点中找出最可能包含答案的节点。问题: {用户的问题}可用节点:- 0001: 第一章 概述 - 本文档介绍了项目的整体背景和目标...- 0002: 第二章 技术方案 - 详细描述了系统架构和技术选型...- 0003: 第三章 实施计划 - 包含项目的时间节点和里程碑...请只返回一个 JSON 数组,包含最相关的 node_id(最多3个)
子节点检索的优势
PageIndex 的树状结构支持多层级检索,LLM 可以根据问题精确定位到最合适的层级:
|
|
|
|---|---|
| 精确定位 |
|
| 减少噪音 |
|
| 层级灵活 |
|
| 上下文优化 |
|
五、输出结构示例
JSON 格式
{"doc_name": "文档名称","structure": {"title": "文档标题","node_id": "0000","summary": "节点摘要","text": "节点文本内容","start_index": 1,"end_index": 10,"nodes": [{"title": "第一章","node_id": "0001","summary": "章节摘要","nodes": [...]}]}}
字段说明
|
|
|
|---|---|
title |
|
node_id |
|
summary |
|
prefix_summary |
|
text |
|
start_index
end_index |
|
六、快速上手
处理 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 查询
ounter(lineounter(lineounter(linepython pageindex_rag_simple.py --structure ./results/doc_structure.json --query "文档主要内容是什么?"
七、PageIndex 的核心优势
|
|
|
|
|---|---|---|
| 依赖组件 |
|
|
| 切片策略 |
|
|
| 检索方式 |
|
|
| 可解释性 |
|
|
| 上下文质量 |
|
|
总结
PageIndex 通过智能化的文档结构提取,将非结构化的 PDF 和 Markdown 文档转换为层级化的树状结构。这种结构化表示使得后续的 RAG 检索可以基于语义推理而非向量相似度,实现更精准、更可解释的文档检索。
核心价值:
-
🚀 无需向量数据库,降低系统复杂度 -
🎯 精准章节定位,提升检索质量 -
🔍 可解释的检索结果,便于追溯答案来源 -
📊 灵活的层级检索,适应不同粒度的问题


