项目简介
PageIndex 是一个无向量、基于推理的 RAG 系统,从长文档构建分层树索引。它利用 LLM 进行上下文感知的类人检索,取代传统向量相似度搜索。在 FinanceBench 等专业文档分析基准上达到顶尖准确率。
README 预览
\n \n\n \n\n\n\n\n\n\n \n\n\n# PageIndex: Vectorless, Reasoning-based RAG\n\nReasoning-based RAG ◦ No Vector DB or Chunking ◦ Context-Aware ◦ Human-like Retrieval\n\n\n 🌐 Homepage • \n 🖥️ Chat Platform • \n 🔌 MCP & API • \n 📖 Docs • \n 💬 Discord • \n ✉️ Contact \n\n \n\n\n\n\n📢 Updates\n\n- 🔥 [**Agentic Vectorless RAG**](https://github.com/VectifyAI/PageIndex/blob/main/examples/agentic_vectorless_rag_demo.py) — A simple *agentic, vectorless RAG* [example](#agentic-vectorless-rag-an-example) with self-hosted PageIndex, using OpenAI Agents SDK.\n- [**Scale PageIndex to Millions of Documents**](https://pageindex.ai/blog/pageindex-filesystem) — *PageIndex File System* is a file-level tree layer that lets PageIndex reason over an entire corpus, not just a single document, enabling massive-scale document search.\n- [PageIndex Chat](https://chat.pageindex.ai) — Human-like document analysis agent [platform](https://chat.pageindex.ai) for professional long documents. Also available via [MCP](https://pageindex.ai/developer) or [API](https://pageindex.ai/developer).\n- [PageIndex Framework](https://pageindex.ai/blog/pageindex-intro) — Deep dive into PageIndex: an *agentic, in-context tree index* that enables LLMs to perform *reasoning-based, context-aware retrieval* over long documents.\n\n \n\n\n\n---\n\n# 📑 Introduction to PageIndex\n\nAre you frustrated with vector database retrieval accuracy for long professional documents? Traditional vector-based RAG relies on semantic *similarity* rather than true *relevance*. But **similarity ≠ relevance** — what we truly need in retrieval is **relevance**, and that requires **reasoning**. When working with professional documents that demand domain expertise and multi-step reasoning, similarity search often falls short.\n\nInspired by AlphaGo, we propose **[PageIndex](https://vectify.ai/pageindex)** — a **vectorless**,
常见问题 (5)
故障排除如何修复 TOC 处理过程中 process_none_page_numbers 出现的 "KeyError: 'page'" 错误?
将不安全的键删除操作替换为 pop() 并配合默认值使用。在 pageindex/page_index.py(或 pageindex/page_index_classic.py)中,将:
del item_copy['page']
del item['page']
修改为:
item_copy.pop('page', None)
item.pop('page', None)
这样会在键存在时将其移除,并且当 TOC 条目没有 page 字段时返回 None,而不是抛出 KeyError。升级到最新版本也可能解决此问题,因为旧的 TOC 路径已被替换,并增加了额外的验证、清理、重试和错误处理。
故障排除当 TOC 条目没有页码时,如何修复 process_none_page_numbers 中的 KeyError: 'page'?
对键的删除操作进行防护,而不是使用 del。在 pageindex/page_index.py 或 pageindex/page_index_classic.py 中,将以下代码:
del item['page']
del item_copy['page']
替换为:
item.pop('page', None)
item_copy.pop('page', None)
这样仅在 page 存在时才会安全地将其移除。如果运行的是已安装的发行版,请升级到最新版本;旧的 TOC 路径后来已被替换,或已被解析器校验与错误处理的改动所覆盖。如果错误仍然存在,请报告输入数据的结构、模型/提供商、包版本以及 traceback。
故障排除当 LLM 返回格式错误的 JSON 时,如何修复 AttributeError: 'str' object has no attribute 'get' 或 'dict' object has no attribute 'extend' 错误?
修复 JSON 回退逻辑并添加运行时类型校验。在 pageindex/utils.py 中,让 extract_json() 在解析失败时返回 [] 而不是 {},因为 ToC 的调用方期望得到一个由字典组成的列表:
def extract_json(text):
try:
data = json.loads(text)
except (json.JSONDecodeError, TypeError):
return []
return data if isinstance(data, list) else []
在使用 LLM 输出之前,先对其进行规范化处理:
def normalize_toc_items(data):
if not isinstance(data, list):
return []
return [item for item in data if isinstance(item, dict)]
在 meta_processor 中,调用 .get() 之前先过滤出字典类型的项:
toc_with_page_number = normalize_toc_items(toc_with_page_number)
toc_with_page_number = [
item for item in toc_with_page_number
if item.get("physical_index") is not None
]
在 process_no_toc 中,调用 .extend() 之前确保两个值都是列表:
toc_with_page_number = normalize_toc_items(
generate_toc_init(group_texts[0], model)
)
for group_text in group_texts[1:]:
additional = normalize_toc_items(
generate_toc_continue(toc_with_page_number, group_text, model)
)
toc_with_page_number.extend(additional)
或者,升级到包含 PR #210、#217 中针对畸形 JSON 的崩溃防护,或包含 issue #199 中提到的综合修复的版本。
故障排除如何修复运行 PageIndex 时 convert_physical_index_to_int 中出现的 KeyError: 'physical_index' 错误?
这是由早期版本的一个 bug 导致的:某些解析后的 PDF 条目缺少 physical_index 字段。请将 PageIndex 更新到最新版本,其中包含了该修复和回归测试:
cd PageIndex
git pull
pip install -r requirements.txt
然后重新运行你原来的 PageIndex 命令。Python 3.9 并未被确认为问题原因。如果在处理较旧或复杂的 PDF 时错误或识别问题仍然存在,可能是 PyPDF 无法可靠地解析该文件;作为变通方案,可以使用托管版 PageIndex API,它使用 OCR,可能会更好地处理此类 PDF。
故障排除如何修复在使用并发 LLM 请求生成树索引(tree index)时出现的 HTTP 429 速率限制错误以及随后引发的 KeyError 'toc_detected'?
升级到最新的 pageindex 版本,该版本新增了客户端速率限制、有界并发、Retry-After 处理、带抖动的指数退避,以及对格式错误的 LLM JSON 响应的验证:
python -m pip install -U pageindex litellm
升级后,并发调用不再通过 asyncio.gather 瞬间突发,并且对空的/失败的 LLM 响应进行了处理,而不会再直接访问 {}['toc_detected']。
如果无法立即升级,可采用以下临时解决方案:
1. 使用信号量限制 LLM 并发:
sem = asyncio.Semaphore(2) # 与你的提供商的 RPM/TPM 档位相匹配
async def guarded_llm_call(coro):
async with sem:
return await coro
await asyncio.gather(*(guarded_llm_call(task) for task in tasks))
2. 将固定的 1 秒重试替换为指数退避、抖动以及 Retry-After 支持:
import asyncio, random
delay = min(60, (2 ** attempt) + random.random())
retry_after = getattr(exc, "response", None)
if retry_after is not None:
delay = float(retry_after.headers.get("Retry-After", delay))
await asyncio.sleep(delay)
3. 在直接访问键之前,先验证解析后的 JSON:
json_content = extract_json(response)
if not json_content or "toc_detected" not in json_content:
raise RuntimeError("LLM returned an invalid or empty JSON response")
return json_content["toc_detected"]
对 TOC 完成检查中的 completed 等字段也应用相同的键存在性检查。