进阶 📋 6 个步骤 第 504 / 505 篇

用 PageIndex 把长文档 RAG 换成推理式目录检索:无向量库、无切块、带页码引用实操

官方仓库与 SDK 双路线:给长 PDF 建树形目录索引、调节点颗粒度、vLLM 兼容与 token 预算、SDK 三步问答与页码引用、agentic 示例接进 Agent,附与向量 RAG 的选型边界。

2026.10.05· 8 分钟上手· 约 2474 字· 📄 PageIndex / 🔍 RAG 检索

向量 RAG 在一类文档上始终别扭:结构严谨的长文档——财务报告、法律合同、监管文件、技术手册。切块加相似度检索常常「相似但不相关」:问「2023 年经营利润率是多少、在哪一节说的」,向量库捞回来几段提到利润率的散碎文本,而不是「经营利润率分析」那一节。2025 年 9 月开源的 PageIndex 换了条路:干脆不要向量库、不要切块,把文档解析成一棵带页码范围的树形目录(像人翻目录页),检索时让 LLM 在树上推理定位——像领域专家那样「翻到正确的那一节再读」。开源仓库在 FinanceBench(SEC 财报问答基准)上给出 98.7% 的检索准确率,同批文档上的向量 RAG 对照只有约五成。

本篇走两条路线:用开源仓库给一份长 PDF 建树索引并学会调参;再用官方 SDK 把「建索引、提问、带页码引用回答」三步跑通;最后把它作为检索工具接进你自己的 Agent。全部命令与代码来自官方仓库 README 与官网文档原文或其直接改写。

前置准备:Python 3 与 pip;一个 OpenAI 或任意 OpenAI 兼容接口的 API Key(vLLM、Ollama 都可以,仓库自带兼容层与 token 计数回退);一份实验用长 PDF——几十页以上效果才明显,财报是最合适的素材。

索引阶段要把整份文档发给所配置的模型服务:长文档是实打实的 token 消耗,也意味着文档内容会离开你的机器。涉密或敏感文档配本地模型(vLLM/Ollama)走本地路线,不要图省事填公有云 Key——数据边界先想清楚再动手。

Step 1:装环境:开源仓库路线起步

1 装环境:开源仓库路线起步

仓库路线能看清中间产物,适合理解原理与调参;跑通后再切 SDK 路线做工程化。按官方 README:

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

# 在仓库根目录建 .env(OpenAI 或任意 OpenAI 兼容服务)
# OPENAI_BASE_URL=http://your-llm-server/v1
# OPENAI_API_KEY=your_api_key
# CHAT_MODEL_NAME=your_model_name

官方 README 对模型分工给了明确建议,这句话直接决定你的索引成本:建索引用的是从文档版面直接抽取的结构再加一层摘要润色,基础模型足够胜任;树上检索与问答才吃模型的推理能力,把好模型留给 chat。一句话:索引省钱、问答花钱,别配反了。

用 vLLM 自建服务时保持 OPENAI_BASE_URL 指向你的服务地址。自定义模型名让 tiktoken 不认识时,仓库会按官方说明先尝试服务的 /tokenize 端点计数,失败再回退本地 cl100k_base——报 tokenizer 错误时先查这一层。

Step 2:给一份 PDF 生成树形索引

2 给一份 PDF 生成树形索引

一条命令把长 PDF 变成树:

python3 run_pageindex.py --pdf_path /path/to/your/document.pdf

跑完得到一个 JSON 树,每个节点带标题、起止页码、可选的节点摘要与节点 ID。官方默认参数:目录探测扫前 20 页、每节点最多 10 页或 2 万 token。以一份年报为例,树的骨架大致长这样(结构示意):

{
  "title": "Financial Results",
  "start_page": 25,
  "end_page": 78,
  "nodes": [
    { "title": "Revenue and Cost of Sales",
      "start_page": 26, "end_page": 40 },
    { "title": "Operating Margin Analysis",
      "start_page": 41, "end_page": 52 }
  ]
}

这一步的产物就是「给机器看的目录」:后面所有检索都发生在这棵树上,而不是对原文做相似度匹配。页码范围让每个答案都能溯源到原文位置——这是向量 RAG 天生给不了的可审计性。

建完先人肉审查树的颗粒度:打开 JSON 抽查三五个节点,「Operating Margin Analysis」是不是真的圈住了利润率分析那几页。树错了后面全错,这里花两分钟最划算。

Step 3:调参:颗粒度、Flash 预览与小上下文模型

3 调参:颗粒度、Flash 预览与小上下文模型

三个最有用的旋钮:--max-pages-per-node 控制节点颗粒度(财报调小、手册可调大);--toc-check-pages 调目录探测的扫描范围;--if-add-node-summary 决定节点是否带摘要——带摘要检索更准、索引更贵。组合示例:

python3 run_pageindex.py --pdf_path report.pdf \
  --max-pages-per-node 6 \
  --if-add-node-summary yes

官方还提供 --flash 预览模式:启发式直接抽取版面结构、不过 LLM 润色,加 --optimize 可以补一轮 LLM 扩展。省钱的用法是先 flash 快速看结构对不对,满意了再跑完整索引,把试错成本压在零 token 那一档。

用 16k 级小上下文模型时,按官方 README 设置 PAGEINDEX_PROMPT_MAX_TOKENS(如 12000)控制分页聚合的激进程度,避免 maximum context length 报错;数值按你模型的实际窗口调。另外 Markdown 路线(--md_path)只适合本身层级规范的 md 文件——官方明确提醒从 PDF/HTML 转换来的 markdown 层级通常已损坏,别用这条路线,优先直读 PDF。

Step 4:SDK 路线:三步问答与页码引用

4 SDK 路线:三步问答与页码引用

工程化用官方 SDK,pip 一装、三步走完:

pip install -U pageindex
from pageindex import PageIndexClient
import os

os.environ["OPENAI_API_KEY"] = "your-openai-key"

client = PageIndexClient(
    index_model="...",   # 建索引:基础模型即可
    chat_model="...",    # 检索问答:用你负担得起的好模型
    storage_path=".pageindex",
)
doc_id = client.submit_document("report.pdf")["doc_id"]
answer = client.chat(
    "What was the 2023 operating margin, and where is it stated?",
    doc_id=doc_id,
)
print(answer)

本地客户端把索引与文档存在 storage_path 指定的目录里(默认 .pageindex),数据不出本机。要带页码引用的答案,按官方文档传一段 system message 约束模型只引用工具输出支持的陈述,模型会在答案里填上文档名与页码:

messages = [
    {"role": "system",
     "content": "Cite only statements supported by tool outputs."},
    {"role": "user", "content": "Summarize the document."},
]
answer = client.chat(messages, doc_id=doc_id)

SDK 的参数名在版本间有演进:官网示例里 index=/chat= 与 index_model=/chat_model= 两种拼法都出现过,本地客户端还有 storage_path 等配置项。跑不通先查你所装版本的官方 SDK 文档,不要硬抄网上的旧示例。

Step 5:接进你自己的 Agent

5 接进你自己的 Agent

官方仓库 examples 目录里有现成的 agentic_vectorless_rag_demo.py——用 OpenAI Agents SDK 把 PageIndex 当工具调用的完整示例;仓库还提供 MCP 接入与 API 文档。装依赖、跑示例:

pip install openai-agents
python3 examples/agentic_vectorless_rag_demo.py

工程化的分工建议:把「建索引」放进文档入库流水线,作为一次性成本;把「树上检索」作为 Agent 的检索工具暴露出去。同一份文档体系里,语料级组织可以用官方 README 提到的 PageIndex File System 做库级索引,单篇文档一棵树、一个语料库一个索引层。

给 Agent 的系统提示里写明「答案必须带页码引用,页码来自工具输出」。引用约束放在提示层比事后校验省事——模型照格式填页码,你抽检页码对应的原文即可。

Step 6:选型边界:它替代不了向量 RAG 的全部

6 选型边界:它替代不了向量 RAG 的全部

官方对比页把边界写得很清楚:PageIndex 强在领域专业文档——财报、监管文件、合同、技术手册、医学文献;向量 RAG 强在泛化与探索性场景——推荐、创意检索、短内容问答。它还有两个固有代价:检索要走 LLM 推理(有延迟、有 token 成本),检索质量跟着模型走——模型升级,检索跟着升级。

务实的架构是双轨并存:结构化长文档走树检索(可溯源、页码可审计,合规场景是硬加分),碎片化知识与闲聊检索走向量库;两边都挂在 Agent 的工具列表里,按查询类型路由。与向量库有关的自建方案可对照本站教程 436(Haystack RAG)与 470(Cloudflare Vectorize),知识图谱路线见 452(GraphRAG)。

98.7% 是 FinanceBench(英文 SEC 财报)上的成绩,不要直接外推到你的中文扫描件或图表密集型文档:本地路线对纯文本 PDF 最稳,扫描件与图片重的文档要走 OCR(官方云版提供,本地路线需自行解决 OCR 前置)。数字是参照系,不是承诺。

预期效果自查:树 JSON 里抽查 3 个节点的页码范围与原 PDF 对得上;SDK 问答返回的数字能在引用页码处找到原文;agentic demo 能带着页码引用回答问题。三条全过,说明「建树、检索、溯源」的链路完整成立。

常见问题 FAQ

和 GraphRAG 是什么关系?会互相替代吗?不替代。GraphRAG 抽实体关系建图谱,强在跨文档多跳推理;PageIndex 在单文档内部按目录结构推理定位,强在长文档的可溯源检索。文档集合复杂就两个都要,按查询类型路由。

中文文档能用吗?仓库路线读 PDF 版面,中文纯文本 PDF 可用,检索质量取决于你配的 chat 模型对中文的理解力;扫描件先过 OCR。模型选择上中文场景把 chat_model 换成中文能力强的模型收益明显。

几百页的 PDF 索引要花多少时间与钱?官网给的数量级是 Flash 模式索引 1000 页「几分钟、约一美元」,完整索引随模型速度与节点颗粒度浮动。务实的做法:先拿 50 页试跑校准参数与成本,再上全量;索引是一次性成本,摊到每次问答上很薄。

← 返回教程中心