Embedding 和 Vector DB 是现在做 RAG 的默认选项。但 Vixhal 做了个反着来的实验:不用 Embedding,不用 Vector DB,用文档树做层级检索。
核心类比
你找课本里的某个内容,不会从第一页逐字读到最后。你翻目录,找章节,再看小节,直接定位。
PageIndex 就是这个思路的数字版本。
工作原理
建索引(Index Time,一次性)
Step 1:把文档切成树形结构
LLM 读文档,先按顶级章节切开。任何超过 300 词的子节,再递归切一次。短章节留在叶子,长章节变成有子节点的内节点。
Step 2:从叶子往上生成摘要
从树底开始——叶子生成自己的摘要,内节点用子节点的摘要合成自己的摘要。顺序是 post-order(先子后父),保证每个子节点有摘要了父节点才生成。
Step 3:存成 JSON
一次构建,反复使用。
检索(Query Time,每次查询)
从根节点开始。LLM 读取所有子节点的摘要,选最相关的那个。如果选中的还是内节点(有更深子节),重复。直到命中叶子。
叶子节点里的原始文本,就是检索到的上下文。
Step 5:生成回答
把上下文 + 问题一起发给 LLM,得到答案。
为什么值得注意
传统 Vector RAG 的问题:Embedding 模型有表达能力上限,向量相似度不等于语义相关性,而且不同文档的向量空间没有对齐。
PageIndex 的前提假设:LLM 自己就能判断相关性,不需要 Embedding 代理。树结构让 LLM 有层级导航能力,不需要暴力遍历全文档。
常见问题
LLM 一直选错分支 → 摘要太模糊,换更强模型,或在 prompt 加更多细节
切分切在了段落中间 → max_tokens 设大,或者预先把文档切成 ~3000 词的块再处理
叶子内容太长 → 降低 SUBSECTION_THRESHOLD,让更多节继续拆分
和普通 RAG 的取舍
PageIndex 适合:文档结构清晰(章节、小节分明),查询是定向的信息查找而非模糊匹配。
不适合:没有明显结构的零散文档,或者需要跨章节综合推理的复杂查询。
结构化文档用层级导航比向量相似度检索更精准,这个判断没问题。但你的语料一旦是非结构化文本堆,这个方案直接失效。选检索架构之前,先搞清楚你的数据长什么样。