PageIndex 的核心目标是解决一个问题如何让 LLM 高质量理解长文档并实现精准搜索。传统 RAG 的问题文档 chunk 切得很碎结构信息丢失搜索结果上下文不完整LLM 容易产生幻觉PageIndex 的思路是先理解文档结构 → 再建立树状索引 → 再做向量搜索而不是直接 chunk。整个系统可以拆成两个阶段离线阶段Indexing文档解析 → 结构提取 → 索引构建 → 向量存储在线阶段Query用户问题 → 向量搜索 → 结构补全 → LLM回答一、文档解析流程Document Parsing文档解析的目标是把 PDF / Word / Markdown 转换成可理解的结构化数据典型输入PDFWordMarkdownHTML解析流程如下。1 文档加载首先系统加载原始文档。核心任务读取文档转换为文本保留基础结构可能用到的工具pdf parserdocx parserhtml parser输出类似{pages:[{text:...,layout:...}]}此时仍然是原始文本。2 文档结构解析接下来需要识别文档结构。系统会识别标题H1 / H2 / H3段落列表表格代码块例如原文1. Introduction This paper introduces... 2. Method会被解析成[{type:heading,level:1,text:Introduction},{type:paragraph,text:This paper introduces...},{type:heading,level:1,text:Method}]这一步的意义是恢复文档逻辑结构。3 LLM 推理生成初始目录如果文档结构不明显很多 PDF 都这样系统会调用 LLM。让 LLM根据文本推断文档目录结构例如输入大量文本输出1 Introduction 2 Background 3 Method 4 Experiment这一步得到Document Outline也就是初始目录线索。4 构建文档树Document Tree有了标题信息之后就可以生成 文档树结构。例如Document ├── Introduction │ ├── paragraph │ └── paragraph │ ├── Method │ ├── subsection │ └── subsection │ └── Experiment内部结构通常是Node { title level content children }这样每一段文本都有父节点子节点层级关系这就是 PageIndex 的核心结构。5 文档 Chunk 切分接下来系统会生成检索单元。但和传统 RAG 不同不是固定长度切分而是按结构切分例如Section Subsection Paragraph形成 chunkchunk_1 Introduction section chunk_2 Method subsection chunk_3 Experiment subsection同时保留parent section path例如path Introduction Background这对于搜索非常重要。6 Embedding 向量化然后系统会对每个 chunk 生成向量存入向量库7 构建索引最终索引包含textembeddingtree pathnode idparent id例如{text:...,vector:[...],path:Method Architecture,node_id:123}到这里离线阶段完成。二、搜索流程Query Pipeline当用户提问时系统开始在线搜索流程。1 Query 解析用户输入How does the method work?系统会清洗 query生成 embedding得到query vector2 向量搜索在向量数据库中查找 TopK 相似 chunk返回Method section Architecture subsection Algorithm description这是 第一层召回。3 结构补全如果只返回 chunkLLM 很可能缺上下文。所以 PageIndex 会补充父节点补充兄弟节点补充上下文例如原始 chunkAlgorithm Step 2系统会扩展为Method └ Algorithm ├ Step1 ├ Step2 └ Step3这样上下文完整。4 上下文重排序如果 chunk 很多需要排序。排序依据embedding 相似度文档结构距离LLM rerank最终选择Top N context5 构造 LLM Prompt系统构造 PromptContext: [document chunks] Question: user query例如Answer based on the following document.6 LLM 生成答案最后调用 LLM 输出final answer同时可能附带引用来源section path例如Source: Method Architecture三、核心算法1. 文档树生成算法核心思想把文档转换成类似 HTML DOM 的树结构结构示意Document ├── Section │ ├── Subsection │ │ ├── Paragraph │ │ └── Paragraph │ └── Subsection └── Section每个节点都保存Node ├ id ├ title ├ content ├ level ├ parent └ children构建流程通常是 三阶段。1 结构元素检测首先解析文本块类型headingparagraphlisttablecode例如1 Introduction This paper proposes...解析结果Heading(level1) Paragraph在 PDF 场景下通常还会利用字体大小字体粗细行距版面布局来识别标题。例如FontSize 18 → H1 FontSize 14 → H2这样可以初步恢复文档结构。2 层级推断如果文档本身没有明确层级很多 PDF 都是这样就需要推断。典型方法方法1规则推断例如1 1.1 1.1.1直接转换成level1 level2 level3方法2LLM 推断当结构不清晰时让 LLM 推理输入大量文本片段输出Possible outline: 1 Introduction 2 Background 3 Method但注意不会把整个文档给 LLM。而是抽样片段 标题候选这样 token 很小。3 树结构构建当拿到标题层级之后构建树结构。伪代码stack [] for element in elements: if element is heading: while stack.top.level element.level: stack.pop() stack.top.children.append(element) stack.push(element) else: stack.top.children.append(element)最终得到Document Tree优势结构清晰支持父子检索支持上下文扩展搜索时的结构扩展策略普通 RAG 的最大问题chunk 太碎例如Algorithm Step 2LLM 根本不知道Step1 Step3PageIndex 的解决办法是结构扩展Structure Expansion流程如下。1 初始向量召回首先正常向量搜索query embedding ↓ vector search ↓ topK chunks例如Chunk A Chunk B Chunk C但这些 chunk 只是局部。2 向上扩展Parent Expansion系统会找父节点例如原始结果Algorithm Step 2扩展后Method └ Algorithm └ Step 2这样 LLM 就知道这是 Method 章节里的算法3 向下扩展Child Expansion如果 chunk 是一个标题节点Algorithm系统会补充Algorithm ├ Step1 ├ Step2 └ Step3这样内容更完整。4 兄弟节点扩展Sibling Expansion有时需要增加相邻信息Step1 Step2 Step3而不是只给Step2这样能明显提高回答质量。5 Token Budget 控制扩展不是无限的。系统会控制max_tokens例如4000 tokens context策略优先保留最相关 chunk逐层扩展直到 token 满类似relevance-first expansionLLM 生成目录为什么不会超上下文很多人看到 PageIndex 的一个步骤LLM 推理生成文档目录会有疑问文档几百页LLM 怎么可能读完实际上它用了 分层策略。1 文档分段首先文档会被切成块chunk size ≈ 500 tokens例如chunk1 chunk2 chunk3 ...每个 chunk 单独分析。2 局部目录生成LLM 对每一小段生成local outline例如chunk1 → Introduction chunk2 → Method chunk3 → Experiment3 Outline 合并系统再把这些 outline 合并merge outlines类似map-reduce过程local outline ↓ merge ↓ global outline4 层级压缩如果目录太长还会压缩例如原始1 Introduction 1.1 Motivation 1.2 Background 2 Method 2.1 Architecture 2.2 Training压缩为Introduction Method Experiment这样 token 极小