PageIndex 项目检索实现
记录 PageIndex 项目检索从索引构建到查询召回的实现思路与工程取舍。
疑问清单
- PageIndex 是什么?它想证明什么?它主要做什么?
- 不走 RAG,Embedding 走的是什么?先说 RAG、Embedding、混合检索是啥,然后说现在的项目是怎么实现的?
- 看着像是映射 B-Tree,数学原理是什么?
- 这个树形索引是什么?是二分法做的树吗?是中序遍历?红黑树?B-Tree?
- 树搜索检索是什么?
- MCTS(蒙特卡洛树搜索)是什么?
- PageIndex 的核心创新的数学原理是啥?本质不就是数据库那一套做成 B-Tree?
- MCTS 不就是启发式打分吗?
- 当前项目用了 MCTS 吗?现在是神经网络还是 B-Tree 那种手写规则?
- 本质的数学原理是什么?
一、结论
1. 项目是什么
PageIndex 它先把 PDF 解析成一棵带页码范围的层次树,再让 LLM 基于这棵树做推理式检索。
- 输入:长 PDF 文档,如财报、法律文件、论文
- 中间产物:文档的层次化树形索引,通常是 JSON Tree
- 输出:与用户问题相关的节点范围,再进一步定位到具体页面内容
- 项目背景:公开资料里通常把它描述为 Vectify AI 推出的长文档检索方案
它证明的是:
- 文档检索不一定要依赖向量数据库
- 长文档更适合先结构化,再做推理式定位
- 专业文档中的“相关性”,有时比“相似性”更重要
2. 主要做什么
它解决的是:长文档里,怎么快速缩小查找范围。
传统方案通常是:
- 把文档切 chunk
- 做 embedding
- 用向量相似度检索
PageIndex 的方案是:
- 先生成文档结构树
- 再让 LLM 在树上做路由决策
- 最后只读取相关节点对应的页面内容
一句话概括:
PageIndex = 文档结构化索引 + 基于 LLM 的树搜索检索。
如果再用一句更偏技术原理的话概括:
PageIndex 的骨架借鉴了 B-Tree 那类“层次索引 + 区间分割 + 逐层定位”的思想,但它不是靠传统的数值比较来决定“该走哪个区间”,而是把原来类似“是否小于 50”这类确定性判断,替换成 LLM 对标题、摘要、页码范围的语义推理,用于建树和路由;如果进一步叠加商业版猜测中的 MCTS,那么它也不是单纯的启发式打分,而是“启发式打分 + 多轮搜索 + 回传更新”的推理时搜索框架。
二、先看整体流程图
如果只想先抓住全貌,可以先看这张图:
flowchart TD
A[长 PDF 文档] --> B[逐页解析文本与 token]
B --> C{是否检测到 TOC 目录?}
C -->|有目录且有页码| D[抽取目录并结构化<br/>计算目录页码与物理页码偏移]
C -->|有目录但页码不可靠| E[抽取目录结构<br/>用标题去正文里匹配位置]
C -->|没有目录| F[直接从正文生成层次结构]
D --> G[验证标题和页码是否匹配]
E --> G
F --> G
G --> H[扁平结构转为树]
H --> I{节点是否过大?}
I -->|是| J[递归细分子结构]
I -->|否| K[得到 PageIndex 树]
J --> K
K --> L{检索模式}
L -->|开源版| M[一次性 LLM Tree Search]
L -->|商业版猜测| N[MCTS 加价值函数]
M --> O[返回相关节点与页码范围]
N --> O
O --> P[读取页面正文并生成答案]
这张图对应了整个系统最核心的两段:
- 前半段:先构建树
- 后半段:再在树上检索
三、先看三组关键对比
这一节的目的不是讲细节,而是先把 PageIndex 放到一个正确的位置上。
1. 传统 RAG、混合检索、PageIndex 的区别
| 维度 | 传统 RAG | 混合检索 | PageIndex |
|---|---|---|---|
| 基本思路 | chunk 后做向量召回 | 关键词 + 向量融合 | 先建文档树,再做树搜索 |
| 索引对象 | 文本块 | 文本块 | 章节节点 |
| 核心依赖 | embedding | BM25 + embedding | LLM + 树结构 |
| 优点 | 工程成熟、快 | 兼顾关键词和语义 | 对长文档结构更友好 |
| 风险 | 相似不等于相关 | 融合逻辑复杂 | 高度依赖结构质量和 LLM 路由 |
一句话理解:
RAG先把文档打散再召回混合检索在关键词和向量之间做折中PageIndex先把文档还原成结构,再顺着结构找
2. B-Tree 和 PageIndex 的区别
| 维度 | B-Tree | PageIndex |
|---|---|---|
| 结构形态 | 多叉平衡树 | 多叉语义树 |
| 路由方式 | 数值比较 | LLM 语义判断 |
| 构建方式 | 插入、分裂、平衡 | 提取目录、校准页码、递归细分 |
| 节点内容 | 可排序 key | 标题、摘要、页码范围 |
| 本质定位 | 数据库索引 | 文档语义索引 |
一句话理解:
PageIndex 借了 B-Tree “多叉 + 逐层缩小范围”的外形,但没有 B-Tree 的排序和平衡机制。
先看 B-Tree 自己的技术实现图:
flowchart TD
Q["查询 key = 18"] --> R["根页<br/>keys: [10 | 20]<br/>ptr: P1 P2 P3"]
R -->|10 <= key < 20| M["中间页 P2<br/>keys: [12 | 16 | 19]<br/>ptr: L1 L2 L3 L4"]
M -->|16 <= key < 19| L["叶子页 L3<br/>records: (16,v16) (17,v17) (18,v18)"]
L --> V["返回 value / record pointer"]
S["磁盘页 / 内存页"] -. 组织形式 .-> R
S -. 组织形式 .-> M
S -. 组织形式 .-> L
这张图想表达的是:
B-Tree的内部节点存的是 可排序 key + 子指针- 查询时靠
key大小比较,一层层决定该走哪个子页 - 叶子节点存实际记录,或者指向实际记录的位置
- 它本质上是一种很典型的 页式存储索引结构
再看 B-Tree 和 PageIndex 的结构对比图:
flowchart TD
subgraph BT[B-Tree]
B1["根节点<br/>[10 | 20]"]
B2["子节点<br/>< 10"]
B3["子节点<br/>10 - 20"]
B4["子节点<br/>> 20"]
B1 --> B2
B1 --> B3
B1 --> B4
end
subgraph PI[PageIndex Tree]
P1["Document"]
P2["章节 1<br/>pages 1-10"]
P3["章节 2<br/>pages 11-20"]
P4["章节 3<br/>pages 21-30"]
P11["1.1<br/>pages 1-3"]
P12["1.2<br/>pages 4-7"]
P13["1.3<br/>pages 8-10"]
P1 --> P2
P1 --> P3
P1 --> P4
P2 --> P11
P2 --> P12
P2 --> P13
end
这张图想表达的是:
- B-Tree 按可排序 key 切分范围
- PageIndex 按文档语义章节 切分页码范围
- 两者都在逐层缩小搜索空间,但路由依据完全不同
再看存储架构图,就更容易理解两者为什么只是“像”,而不是“一样”:
flowchart LR
subgraph DB["B-Tree 存储架构"]
D1["原始记录表"]
D2["B-Tree 内部节点<br/>key + child pointer"]
D3["B-Tree 叶子节点<br/>key + record pointer"]
D2 --> D3
D3 --> D1
end
subgraph PG["PageIndex 存储架构"]
P0["PDF / 原始页面"]
P1["page_list<br/>逐页文本 + token"]
P2["PageIndex Tree(JSON)<br/>title + summary + page_range + children"]
P3["节点定位结果<br/>node_id / page_range"]
P0 --> P1
P1 --> P2
P2 --> P3
P3 --> P0
end
这张存储架构图想表达的是:
B-Tree的索引目标是结构化记录PageIndex的索引目标是原始文档页面B-Tree存的是key和指针PageIndex存的是标题/摘要/页码范围/子节点B-Tree查到的是某条记录或记录指针PageIndex查到的是某个文档节点和对应页码范围
3. 开源版 Tree Search 和商业版猜测 MCTS 的区别
| 维度 | 开源版 Tree Search | 商业版猜测 MCTS |
|---|---|---|
| 决策方式 | 一次性让 LLM 选节点 | 多轮搜索、多轮评分 |
| LLM 调用次数 | 少 | 多 |
| 成本 | 低 | 高 |
| 稳定性 | 更依赖单次判断 | 更依赖统计收敛 |
| 工程复杂度 | 低 | 高 |
一句话理解:
- 开源版更像“一次问模型,你觉得答案在哪”
- MCTS 更像“反复试探、打分、回传,再决定哪里最值得看”
四、理解本文必须先知道的术语
为了让后面的内容更容易读,这些术语先快速解释一遍。
1. RAG
RAG 是 Retrieval-Augmented Generation。先检索,再把检索结果交给 LLM 回答。
2. Embedding
Embedding 是把文本映射成向量的技术。之后可以用向量距离衡量“语义有多近”。
3. 混合检索
混合检索通常是:
- 一部分靠关键词匹配
- 一部分靠 embedding 相似度
- 最后把两边结果融合排序
4. TOC
TOC 是 Table of Contents,也就是目录页。
5. Tree Search
Tree Search 是在树结构里逐层缩小范围,而不是平铺扫描所有文本。
6. MCTS
MCTS 是 Monte Carlo Tree Search。它不是一次决策,而是多轮搜索、多轮评分、多轮更新。
7. Value Function
Value Function 是“打分器”,负责评估一个节点对当前 query 值不值得继续探索。
8. UCB1
UCB1 是 MCTS 常用的选路公式,用来平衡“继续走高分路径”和“试一试新路径”。
9. 后训练、强化学习、推理时搜索
这三个东西不是一回事:
后训练是训练模型强化学习是训练模型的一类方法推理时搜索是模型参数不动,只在回答问题时增加搜索计算
五、项目本质实现
整个系统可以拆成两个阶段:
- 构建树形索引
- 基于树做检索
1. 阶段一:构建树形索引
核心链路在 page_index_main -> tree_parser -> meta_processor。
整体过程可以概括为:
- 逐页解析 PDF 文本,并统计 token 数
- 检测文档前几页是否存在目录(TOC)
- 根据目录情况走不同分支
- 校验目录标题与实际页面是否匹配
- 把扁平结构转成层次树
- 对过大的节点继续递归切分
有目录时
如果文档有目录,系统会优先利用目录:
- 先提取目录文本
- 让 LLM 把目录转成结构化层级
- 如果目录里有页码,再把目录页码映射为 PDF 物理页码
- 然后检查标题是否真的出现在对应页面
这里的关键难点是:
- 目录页码不一定等于 PDF 物理页码
- 前言、封面、罗马数字页码会造成偏移
所以它会通过正文中的标题匹配,估算一个页码偏移量,再统一修正。
无目录时
如果没有目录,就直接让 LLM 读正文,生成层次结构:
- 给每页加物理页标签
- 按 token 上限分组
- 第一组先生成初始结构
- 后续组继续增量补齐结构
这相当于让 LLM 从正文中“归纳出目录”。
后处理
树生成后还会做几件事:
- 计算每个节点的
start_index和end_index - 用层级编号或结构字段建立父子关系
- 对过大的节点继续递归细分
- 生成摘要、说明等元数据
2. 源码对应的实现流程说明
整体主链路
如果按函数调用顺序来看,主链路大致是:
page_index_main -> get_page_tokens -> tree_parser -> check_toc -> meta_processor -> post_processing -> process_large_node_recursively
可以把它理解为 7 个动作:
- 读取 PDF,逐页抽文本并计算 token 数
- 判断前几页里有没有目录页
- 根据目录情况选择处理分支
- 把目录或正文转换成扁平结构列表
- 校验页码和标题是否真的匹配
- 把扁平结构转成树,并补足页码区间
- 对过大的节点继续递归细分
阶段 1:PDF 解析
对应职责主要在 get_page_tokens 一类函数里。
这一层做的事很朴素:
- 逐页提取文本
- 记录每一页的 token 长度
- 形成
page_list
这里的 page_list 可以理解成整个系统的“原材料仓库”。后面的目录识别、层级生成、节点切分,都是围绕它展开。
阶段 2:TOC 检测
这一步的核心职责通常由 check_toc、find_toc_pages、toc_detector_single_page 这一组函数完成。
目的不是直接生成树,而是先回答三个判断题:
- 文档前几页里有没有目录
- 连续哪些页是目录页
- 目录里有没有显式页码
这一步非常关键,因为它直接决定后续走哪条构建路线。
阶段 3:三条构建分支
meta_processor 可以理解成分发器。它根据 TOC 检测结果,把任务派给不同分支。
第一条分支:有目录,而且目录里有页码。
- 先抽取目录文本
- 再把目录文本转换成层级条目
- 然后根据目录页码和物理页码的差异估计偏移量
- 最后把目录页码统一修正成 PDF 物理页码
第二条分支:有目录,但目录里没有可靠页码。
- 还是先抽目录结构
- 但不能直接靠页码定位
- 只能用标题在正文中的出现位置去做匹配
- 这种路径更依赖 LLM 对标题和正文的对应关系判断
第三条分支:没有目录。
- 直接把正文分组
- 让 LLM 从正文里“归纳目录”
- 第一组生成初始结构
- 后续组在已有结构上继续补充
阶段 4:验证与修复
这一层主要是 verify_toc、check_title_appearance、fix_incorrect_toc_with_retries 这类职责。
它做的不是重新建树,而是做“质检”:
- 抽样检查标题是否真的落在对应页面
- 检查页码映射是不是明显错位
- 如果错误较少,就局部修正
- 如果错误太多,就回退到更保守的分支
这一步很像工程上的“自动校验和容错回退”。
阶段 5:扁平结构转树
这一层通常由 post_processing 和 list_to_tree 完成。
它会把前面得到的扁平条目列表整理成真正的树:
- 计算每个条目的起止页
- 根据
structure之类的层级编号判断父子关系 - 把兄弟节点和子节点组织起来
这里的重点不是“搜索”,而是把结构真正落成一个可导航的数据结构。
阶段 6:递归细分大节点
这一层由 process_large_node_recursively 负责。
如果某个节点太大,比如:
- 页数太多
- token 太多
- 内部信息过于密集
那就不能把它当成一个粗粒度节点直接使用,而要把它覆盖的页重新拿出来,再跑一轮“从正文中生成子结构”的流程。
这意味着 PageIndex 不是只做一次静态目录抽取,而是会对“大块内容”进一步拆分,直到结构粒度适合检索。
阶段 7:结果产物
最后得到的不是“向量索引”,而是带有这些属性的树节点:
- 标题
- 层级关系
- 起止页码
- 摘要或描述
- 子节点列表
这棵树才是后续树搜索检索真正使用的索引。
这一整套流程的工程本质
如果只用一句话概括源码流程:
先用目录或正文生成候选结构,再用校验和递归细分把它打磨成可检索的层次化页码索引。
它和传统数据库索引最大的区别不在最终树形态,而在于构建时高度依赖 LLM 做结构提取和页码对齐。
它和经典 B-Tree 在“构建方式”上的差异
这一步很值得单独强调,因为很多人一看到树结构就会直接联想到 B-Tree。
经典 B-Tree 的构建方式通常是:
- 插入 key
- 节点满了就分裂
- 自底向上维持平衡
PageIndex 的构建方式则是:
- 先提取或生成大纲
- 再映射页码
- 再做校验和修正
- 最后对过大的节点继续递归细分
所以二者虽然最后都长得像“多叉树”,但构建机制其实完全不同:
- B-Tree 是数据结构驱动的确定性构建
- PageIndex 是LLM 驱动的语义结构构建
3. 阶段二:树搜索检索
检索阶段不是做向量相似度,而是:
- 把用户 query 和文档树一起给 LLM
- 让 LLM 判断哪些节点最可能包含答案
- 拿到节点对应的页码范围
- 再去读取这些页的正文内容回答问题
这和人查长文档非常像:
- 先看目录
- 判断大概在哪个章节
- 进入章节再看子标题
- 最后定位到少量页面精读
所以它本质上是:LLM 代替人做“目录导航 + 章节定位”。
六、它和 RAG、Embedding、混合检索的关系
1. 传统 RAG 是什么
传统 RAG(Retrieval-Augmented Generation)一般流程是:
- 文档切块
- 每个 chunk 做 embedding
- 存进向量数据库
- query 也做 embedding
- 通过余弦相似度或内积取 top-K
- 把召回结果交给 LLM 回答
2. Embedding 是什么
Embedding 本质上是一个映射函数:
f(text) -> R^d
也就是把文本映射成一个高维向量。检索时通常比较 query 向量和文档向量的距离,比如余弦相似度:
similarity(q, d) = (q · d) / (||q|| ||d||)
它依赖一个假设:
语义相近的文本,在向量空间里也更接近。
3. 混合检索是什么
混合检索通常是:
- 稀疏检索:BM25、TF-IDF 这类关键词匹配
- 稠密检索:embedding 向量相似度
- 两者融合排序
4. PageIndex 和它们的区别
PageIndex 不是这条路线。它更像是另一种范式:
| 维度 | 传统 RAG | PageIndex |
|---|---|---|
| 索引对象 | chunk | 章节/节点 |
| 索引结构 | 向量库 | 树形结构 |
| 检索依据 | 向量相似度 | LLM 语义推理 |
| 切分方式 | 固定长度切块 | 按文档自然结构切分 |
| 核心依赖 | embedding 模型 | LLM |
PageIndex 的核心观点可以概括成一句话:
Similarity 不等于 Relevance。
向量检索找到的是“语义相似”的内容;PageIndex 更想找到“结构上、逻辑上真正相关”的内容。
七、这个树到底是什么树
1. 它不是什么
它不是:
- 二叉搜索树
- 红黑树
- 中序遍历意义上的有序树
- 严格意义上的 B-Tree
原因很简单:
- 它不是二叉的,一个节点可以有多个子节点
- 节点 key 不是数值,也没有全序关系
- 没有左小右大的比较规则
- 没有红黑树那种平衡约束
- 没有 B-Tree 那种严格的分裂/合并规则
2. 它更接近什么
它更接近:
- 文档驱动的 N 叉树
- 层次化区间索引
- 带页码范围的语义目录树
可以把它理解成:
Document
├── Section 1 pages 1-10
│ ├── 1.1 pages 1-3
│ ├── 1.2 pages 4-7
│ └── 1.3 pages 8-10
├── Section 2 pages 11-20
└── Section 3 pages 21-30
每个节点至少包含两类信息:
- 语义信息:标题、摘要、描述
- 索引信息:
start_index、end_index、子节点列表
3. 它和 B-Tree 的关系
它借鉴了 B-Tree 的一些思想,但不是 B-Tree 本身。
相似点:
- 都是多叉结构
- 都能逐层缩小搜索范围
- 都带有“区间”含义
不同点:
- B-Tree 的 key 可以排序;PageIndex 的标题不能严格排序
- B-Tree 靠数值比较路由;PageIndex 靠 LLM 语义判断路由
- B-Tree 有平衡规则;PageIndex 没有
- B-Tree 由插入/分裂构建;PageIndex 由 LLM 提取文档结构构建
准确说法更应该是:
PageIndex 是一棵以文档语义结构为骨架、以页码区间为索引的 N 叉树。
八、看着像 B-Tree,本质数学原理是什么
1. 为什么会让人联想到 B-Tree
你会觉得它像 B-Tree,主要是因为它也具备这几个特征:
- 都是多叉结构
- 都会逐层缩小搜索范围
- 节点都带有“范围”含义
- 都是在用树索引替代平铺扫描
但它又不是标准 B-Tree,因为它缺少 B-Tree 的几个核心前提:
- 没有严格可排序的 key
- 没有插入、分裂、合并、自平衡那套规则
- 没有确定性的数值比较路由
- 路由决策依赖 LLM 的语义判断
所以更准确的说法应该是:
它像 B-Tree 的地方在“多叉索引”和“逐层缩小范围”,不像的地方在“排序规则、平衡规则、路由方式”。
2. 三层数学原理
第一层:分治
树搜索的基本思想是分治。
如果每层把搜索空间缩小到原来的 1/b,复杂度可写成:
T(n) = T(n/b) + O(1) = O(log_b n)
这部分和数据库索引、B-Tree、目录导航的思想一致。
第二层:区间覆盖
每个节点对应一个页码区间 [s_i, e_i],一般满足:
- 兄弟节点区间基本不重叠
- 子节点区间被父节点区间包含
- 多个节点区间合起来覆盖全文
这部分本质上是层次化区间管理。
第三层:路由函数替换
真正不同的地方在这里。
传统数据库索引是:
route(query, node) = compare(query_key, node_keys)
PageIndex 变成:
route(query, node) = LLM(query_text, child_titles, child_summaries)
也就是说:
- 传统索引靠确定性的数值比较
- PageIndex 靠概率性的语义推理
3. 所以它本质是什么
一句话总结:
PageIndex 的本质 = 区间树式的层次索引 + LLM 语义路由。
如果你要用最工程化的语言描述,可以写成:
这不是标准 B-Tree,而是一个面向长文档的层次化区间索引系统。
九、树搜索检索是什么
树搜索检索就是:
- 从根节点开始
- 看当前层有哪些章节
- 判断 query 更应该进入哪个分支
- 一层层往下缩小范围
- 最终定位到少量相关节点
它模拟的是人类专家查文档的过程,而不是“把所有段落都算一遍相似度”。
1. 为什么比平铺扫描更合理
如果文档是 300 页:
- 平铺扫描意味着你要面对大量 chunk
- 树搜索意味着你先在大章节之间做判断,再进小章节
这相当于先压缩搜索空间,再做细定位。
2. 开源版是怎么做的
开源版的思路非常直接:
- 把 query 和整棵树结构给 LLM
- 让 LLM 直接返回相关
node_id
这属于一次性树路由,还不是严格意义上的 MCTS。
十、MCTS 是什么
MCTS 是 Monte Carlo Tree Search,蒙特卡洛树搜索。
它最经典的应用是 AlphaGo 一类博弈系统。核心思想不是一次选路,而是:
- 多轮搜索
- 多轮打分
- 多轮统计更新
- 在探索和利用之间做平衡
先看一张最直观的流程图:
flowchart TD
A[开始于根节点] --> B[Selection<br/>按 UCB1 选择路径]
B --> C[Expansion<br/>展开新节点]
C --> D[Simulation<br/>调用价值函数评分]
D --> E[Backpropagation<br/>把分数回传到路径]
E --> F{达到预算或轮数上限?}
F -->|否| B
F -->|是| G[输出统计上最优的节点]
1. MCTS 四步
Selection
从根节点往下选子节点,常见公式是 UCB1:
UCB1 = Q / N + C * sqrt(ln(N_parent) / N)
含义:
Q / N:平均收益高的节点优先- 第二项:访问少的节点也要适当探索
Expansion
如果走到还没展开完的节点,就展开它的子节点。
Simulation
对新节点做一次评估。
在棋类里是模拟对局,在 PageIndex 场景下通常可以理解为:
- 让模型评估“这个节点和 query 的相关度”
Backpropagation
把这次评估分数沿路径往上回传,更新每个节点的统计值。
2. MCTS 不就是启发式打分吗
可以说是,但不止是。
“启发式打分”只说对了一半。MCTS 的关键不只是评分,而是:
- 如何反复搜索
- 如何在多个分支之间分配搜索预算
- 如何利用历史分数更新后续决策
所以更准确地说:
MCTS = 启发式评分 + 系统化树搜索框架。
十一、当前开源项目用了 MCTS 吗
1. 开源代码里没有
当前仓库的开源代码里,没有真正的 MCTS 实现,也没有看到:
- UCB1 搜索循环
- 多轮 rollout / simulation
- 反向传播统计更新
- 显式的 value function
开源版更像是:
- 构建树
- 一次把树和 query 交给 LLM
- 让 LLM 直接选节点
2. 文档里提到过商业版
文档说明里提到他们在商业产品中使用了:
- LLM tree search
- value function based MCTS
所以当前可以下结论:
- 开源版:没有 MCTS
- 商业版:据文档描述有 MCTS,但实现未开源
3. 现在到底是神经网络还是手写规则
更准确的表述是:
- 树结构本身:普通数据结构
- 路由和结构提取:依赖 LLM
- 不是手写规则系统
- 也不是它自己训练的专用神经网络
也就是说:
PageIndex 自己不训练模型,它是把现成 LLM 当成“结构理解器”和“语义路由器”来用。
十二、PageIndex 的核心创新到底是什么
如果说得严格一点,它的创新不是发明了新的底层数学公式,而是把已有两类能力组合起来:
- 文档层次化索引
- LLM 语义推理
传统系统里:
- 索引结构来自数据库思想
- 文本语义理解来自神经网络
PageIndex 做的是把两者接起来,让 LLM 不只是回答问题,还参与“路由决策”。
所以可以分成两部分看:
1. 旧的部分
- 分治
- 区间覆盖
- 多叉索引结构
- 层次化缩小搜索空间
这些都不是新的。
2. 新的部分
- 用 LLM 自动提取文档层次结构
- 用 LLM 替代数值比较做路由
- 在长文档检索中强调“先结构化,再推理定位”
所以更客观的表述应该是:
PageIndex 的创新主要是产品范式创新,不是基础数学创新。
十三、MCTS 放到 PageIndex 里到底怎么工作
上面已经解释了 MCTS 的定义,这一节专门讲它如果落到 PageIndex 上,流程到底会变成什么样。
1. 开源版和 MCTS 版的根本区别
开源版更像是:
- 把 query 和整棵树一次性交给 LLM
- 让 LLM 直接说哪些节点相关
- 一次决策完成
如果换成 MCTS 版,则会变成:
- 先从根节点开始
- 每一轮只走一条路径
- 走到一个位置就评估一次
- 把分数回传
- 再继续下一轮
所以两者最本质的区别是:
- 开源版:单次全局判断
- MCTS 版:多轮局部探索 + 统计收敛
2. UCB1 在这里扮演什么角色
UCB1 是 MCTS 在 Selection 阶段的“选路公式”。它解决的是一个经典矛盾:
- 只选高分路径,可能错过隐藏的好分支
- 只探索新路径,又会浪费预算
所以它会平衡两种倾向:
exploitation:优先走历史平均分更高的节点exploration:优先试一试访问次数少的节点
放到 PageIndex 里,含义可以理解成:
- 哪个章节看起来已经很相关,就多给它一些机会
- 哪个章节还没怎么看过,也要偶尔试一下,避免漏掉答案
3. 多轮模拟在 PageIndex 里是什么
这里的“模拟”不是棋类游戏里的随机对局,而更接近:
- 选择一个节点
- 让模型评估它和 query 的相关性
- 把评估值记下来
反复做很多轮之后,就能得到比“一次直觉判断”更稳定的统计结果。
4. 反向传播在这里是什么
这里的反向传播不是神经网络训练中的梯度反传,而是:
- 某条路径这次得了一个高分
- 那么路径上的祖先节点也应该被视为“值得继续探索”
- 于是把这次得分沿着路径往上累积
所以在 PageIndex 场景里,“反向传播”更适合理解成:
把叶子节点的相关性反馈给上层章节。
5. 如果真的按流程跑,会是什么顺序
可以把一个查询过程想成下面这样:
- 从根节点开始
- 按 UCB1 选择一个子节点
- 如果这个子节点还没展开,就展开它的孩子
- 选一个叶子或近叶子节点做相关性评估
- 把这次评估结果回传到整条路径
- 重复很多轮
- 最后选统计上最优的一批节点
这套流程的意义在于:
- 不依赖一次 prompt 的偶然性
- 能探索多个备选章节
- 对长文档和复杂问题更稳
6. 它的代价是什么
MCTS 不是白送的优化,它的代价很明确:
- LLM 调用次数显著增加
- 延迟更高
- 成本更高
- 工程实现更复杂
所以它适合:
- 高价值查询
- 文档很长、结构很深的情况
- 对召回质量要求特别高的产品化场景
十四、价值函数是什么,为什么它很关键
1. 什么是价值函数
在 MCTS 的语境里,价值函数可以简单理解成一句话:
给定 query 和某个节点,输出“这个节点值不值得继续搜”的分数。
这就是 MCTS 的“评委”或“打分器”。
在 AlphaGo 里,这个东西通常是专门训练出来的神经网络。
在 PageIndex 里,更合理的理解是:
- 直接调用 LLM
- 让它对节点相关性做评分
- 把这个评分作为搜索依据
2. 在 PageIndex 场景里,价值函数一般看什么
它通常会综合判断这些信息:
- query 的意图
- 节点标题
- 节点摘要
- 节点页码范围
- 必要时还会看节点覆盖的原文内容
也就是说,价值函数不是只看关键词,而是在问:
- 这个节点是不是在讨论用户关心的话题
- 这个节点是不是答案最可能出现的位置
- 这个节点是不是比同层其他节点更相关
3. 价值函数可以做成哪几种强度
第一种,轻量评分。
- 只看标题和摘要
- 让模型返回一个 0 到 1 的分数
- 成本低,速度快
第二种,同层对比评分。
- 不只评估一个节点
- 而是让模型同时比较一组兄弟节点
- 看谁更值得深入
第三种,深度内容评分。
- 直接读取节点覆盖的正文内容
- 再判断它与 query 的匹配度
- 成本最高,但通常最准确
4. 为什么开源版的 tree search prompt 不能直接当完整价值函数
因为开源版的做法是:
- 一次性看完整棵树
- 直接输出节点列表
它的问题在于:
- 没有显式分数
- 没有可重复调用的标准接口
- 没法稳定地接进 MCTS 主循环
所以“让 LLM 一次性选节点”和“有一个可反复调用的价值函数”不是一回事。
5. 价值函数、UCB1、MCTS 三者的关系
这三个概念经常混在一起,其实分工很清楚:
- 价值函数:负责打分
- UCB1:负责选路
- MCTS 主循环:负责反复搜索、统计、更新
少了价值函数,MCTS 就不知道怎么判断叶子节点。
少了 UCB1,MCTS 就不知道怎么平衡探索和利用。
少了多轮循环,MCTS 就退化成一次性判断。
十五、开源版、商业版猜测、后训练、强化学习与 AlphaGo
这一块最容易混淆,必须单独拆开讲。
1. 先看开源版、商业版猜测、AlphaGo 的并排定位
| 维度 | 开源版 PageIndex | 商业版猜测 | AlphaGo |
|---|---|---|---|
| 是否公开实现 | 是 | 否 | 是 |
| 核心检索/搜索 | 一次性 LLM Tree Search | MCTS + Value Function | MCTS + Policy/Value Network |
| 是否训练专用网络 | 否 | 大概率没有专用检索网络公开证据 | 是 |
| 推理时是否多轮搜索 | 否 | 是 | 是 |
| 训练阶段是否有 RL | 否 | 没有公开证据 | 是 |
一句话理解:
- 开源版:先建树,再一次性选节点
- 商业版猜测:先建树,再多轮搜索节点
- AlphaGo:先训练专用网络,再用 MCTS 搜索走子
2. AlphaGo 的设计为什么总被拿来类比
因为它的架构很容易让人联想到“模型负责打分,搜索负责选路”。
flowchart TD
A[人类棋谱 与 Self-play 数据] --> B[训练 Policy Network]
A --> C[训练 Value Network]
B --> D[推理时 MCTS]
C --> D
D --> E[选择最终落子]
如果把这个思路拿来类比 PageIndex,可以这样理解:
flowchart TD
A[长文档] --> B[构建 PageIndex 树]
Q[用户 Query] --> C[冻结的 LLM 评分/路由]
B --> D[推理时树搜索]
C --> D
D --> E[返回最相关节点]
3. MCTS 不是训练
MCTS 是推理时搜索,不是训练。
训练阶段通常意味着:
- 更新模型参数
- 调整模型权重
- 通过样本和损失函数去优化模型
而 MCTS 做的事情是:
- 模型权重不动
- 每次查询时多跑几轮搜索
- 用更多计算换更好的决策
所以它属于:
inference-time search / test-time compute
而不是:
training / fine-tuning / reinforcement learning
4. 那 AlphaGo 为什么总和 MCTS 一起提
因为 AlphaGo 同时用了两类东西:
- 训练出来的策略网络和价值网络
- 推理时使用的 MCTS
这两者不是一回事,而是分工合作。
策略网络负责回答:
- 下一步大概哪些动作更值得考虑
价值网络负责回答:
- 当前局面最终获胜概率大概是多少
MCTS 负责:
- 在搜索树里反复探索
- 调用上面这些网络做指导
- 最终选出更好的路径
所以准确说法是:
- 强化学习训练了网络
- MCTS 在推理时消费这些网络
5. PageIndex 的 MCTS 算不算强化学习
严格说,不算。
因为在 PageIndex 这个设定里:
- 没有 self-play
- 没有 reward 驱动的参数更新
- 没有 policy/value 网络训练过程
- 只是拿一个现成 LLM 当评估器
所以它更像是:
- 冻结模型
- 推理时搜索
- 用搜索增强检索质量
6. 这更接近哪个技术范畴
更接近现在常说的:
- test-time compute scaling
- inference-time reasoning
- search-based reasoning
也就是:
- 不改模型
- 不训模型
- 只是在推理时增加搜索和评估次数
这和 Beam Search、Tree of Thought、Best-of-N 在思想上更接近,而不是和 RLHF、PPO、DPO 这类训练方法更接近。
十六、附录:术语速查
这一节专门保留术语解释,避免读者因为概念太密而看不懂。
1. TOC
TOC 是 Table of Contents,也就是目录页。
2. Chunking
Chunking 是把长文档切成很多小块。传统 RAG 很依赖这一步,因为 embedding 和向量检索通常是按块进行的。
3. Embedding
Embedding 是把文本映射成向量表示的方法。它让“语义相近”这件事可以在向量空间里通过距离来衡量。
4. 向量数据库
向量数据库是专门存储向量并支持相似度检索的系统,例如根据余弦相似度找最近邻。
5. Tree Search
Tree Search 就是在树结构中逐层缩小搜索范围,而不是平铺扫描全部内容。
6. Node
Node 就是树里的节点。在 PageIndex 里,一个节点通常对应一个章节、一个标题段或者一个页码范围。
7. Page Range
Page Range 是节点覆盖的页码区间,比如从第 15 页到第 23 页。
8. Value Function
Value Function 是一个评分器,用来判断某个节点对当前 query 有多大价值。
9. UCB1
UCB1 是 MCTS 在选路时常用的公式,用来平衡“继续走高分老路”和“尝试访问少的新路”。
10. Selection / Expansion / Simulation / Backpropagation
这是 MCTS 的四个标准步骤:
- Selection:选路径
- Expansion:展开新节点
- Simulation:评估节点
- Backpropagation:把评估结果回传
11. Policy Network
Policy Network 是在博弈系统里用来预测“下一步更可能选什么动作”的模型。
12. Value Network
Value Network 是在博弈系统里用来预测“当前局面最后值多少钱、胜率多高”的模型。
13. Self-play
Self-play 是自己和自己对弈,通过不断对抗生成训练数据的方法。AlphaGo 这类系统会大量用到。
14. Inference-time Compute / Test-time Compute
这表示模型参数不变,只是在推理阶段投入更多计算预算,比如多搜索几轮、多采样几次,以换取更好的输出。
15. Reasoning-based Retrieval
Reasoning-based Retrieval 指的不是靠向量最近邻去找内容,而是靠模型理解文档结构和问题意图后,再做推理式定位。
十七、最终总结
如果压缩成最核心的几句话:
- PageIndex 先把长文档变成树,再在树上检索。
- 它的索引骨架像层次化区间树,不是标准 B-Tree 或红黑树。
- 它不走 embedding 检索主路线,而是让 LLM 做语义路由。
- 开源版没有 MCTS,商业版据称用了 MCTS。
- 源码实现上,重点不是某段复杂代码,而是“目录检测 -> 结构生成 -> 页码校准 -> 验证修复 -> 递归细分”这条流程。
- 如果引入 MCTS,本质上是在推理阶段增加搜索,而不是训练新模型。
- 它的核心价值不在于新数学公式,而在于“结构化索引 + LLM 推理检索”这套组合。
如果要用一句最准确的话概括:
PageIndex = 面向长文档的层次化区间索引系统,利用 LLM 完成结构提取与树路由检索。
如果再用一句更偏技术原理的话概括:
PageIndex 的骨架借鉴了 B-Tree 那类“层次索引 + 区间分割 + 逐层定位”的思想,但它不是靠传统的数值比较来决定“该走哪个区间”,而是把原来类似“是否小于 50”这类确定性判断,替换成 LLM 对标题、摘要、页码范围的语义推理,用于建树和路由;如果进一步叠加商业版猜测中的 MCTS,那么它也不是单纯的启发式打分,而是“启发式打分 + 多轮搜索 + 回传更新”的推理时搜索框架。