Addresses items 9-13 and a/b/c/f from the max-effort review of PR #272. - pdf.py: image colorspace check was `pix.n > 4`, which treats CMYK-without- alpha (n==4, same as RGBA) as not needing RGB conversion; pix.save() as .png then raises "unsupported colorspace", silently dropped by the surrounding except. Fixed to `pix.n - pix.alpha >= 4` (correctly converts CMYK, leaves RGBA untouched). - pipeline.py: detect_strategy([]) (an empty/whitespace-only source file) returned "content_based", routing into the PDF-oriented TOC-detection pipeline -- wasting a real LLM call before raising IndexingError. Empty node lists now route to level_based, whose build_tree_from_levels([]) returns an empty structure instantly with zero LLM calls. - page_index.py (shim): pageindex/__init__.py binds the canonical `page_index` function as the package attribute, but this file is ALSO a real submodule of the same name -- importing it anywhere (import machinery, unconditional) overwrites that attribute with the module object, breaking `from pageindex import page_index; page_index(x)` for the rest of the process. Made the shim module itself callable (delegates to the real function via a ModuleType subclass), so whichever object ends up in that slot is callable regardless of import order. - storage/sqlite.py: create_collection let a raw sqlite3.IntegrityError escape on a duplicate name (new CollectionAlreadyExistsError); the collections table's CHECK constraint only validated the name's first character (GLOB '*' is a wildcard, not a regex quantifier over the preceding class) -- fixed to validate the whole string, and SQLiteStorage now also validates in Python (it's a public StorageEngine usable directly, bypassing LocalBackend's own check). - tests/test_review_fixes_2.py: two tests used a ContentNode with no `level` set, so build_index took the content_based path and made real (retried, slow, and -- with a valid key -- billable) LLM calls instead of testing the text-stripping logic they claimed to. Mocked out _content_based_pipeline. - retrieve.py: _parse_pages/_get_pdf_page_content were independent copies of the canonical parse_pages/get_pdf_page_content that had already drifted (missing the p>=1 filter and 1000-page DoS cap) -- delegate to canonical now, so the legacy pageindex.get_page_content path can't silently regress again. - parser/markdown.py: a leading UTF-8 BOM broke first-header detection (not whitespace, .strip() doesn't remove it) -- decode utf-8-sig. Only backtick fences were recognized as code blocks, so a '#'-prefixed line inside a ~~~-fenced block (valid CommonMark) was misparsed as a heading -- recognize both fence styles. - run_pageindex.py: --if-thinning wasn't migrated to the bare-flag + legacy-yes/no convention the other four --if-add-* flags got; bare usage raised an argparse error and it never went through the shared coercion. - types.py: DocumentDetail's `structure` field was inside the class's total=False body, so TypedDict rules made it optional even though every backend always populates it. Split into a required base class. Adds regression tests for all of the above. Full suite: 244 passed, 2 skipped (one pre-existing, unrelated flaky cloud-streaming test). Claude-Session: https://claude.ai/code/session_01Kx5DgKbhK1N8autqXH8SmS |
||
|---|---|---|
| .claude/commands | ||
| .github | ||
| cookbook | ||
| examples | ||
| pageindex | ||
| tests | ||
| .gitattributes | ||
| .gitignore | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
| run_pageindex.py | ||
PageIndex: Vectorless, Reasoning-based RAG
Reasoning-based RAG ◦ No Vector DB, No Chunking ◦ Context-Aware Retrieval ◦ Reads Like a Human
🌐 Website • 🖥️ Chat Platform • 🔌 MCP & API • 📖 Docs • 💬 Discord • ✉️ Contact
📢 Updates
- 🔥 Agentic Vectorless RAG — A simple agentic, vectorless RAG example with self-hosted PageIndex, using OpenAI Agents SDK.
- Scale PageIndex to Millions of Documents — PageIndex File System is a file-level tree indexing layer that lets PageIndex reason over an entire corpus, not just a single document, enabling massive-scale document search.
- PageIndex Chat — Human-like document analysis agent platform for professional long documents. Also available via MCP or API.
- PageIndex Framework — Deep dive into PageIndex: an agentic, in-context tree index that enables LLMs to perform reasoning-based, context-aware retrieval over long documents.
📑 Introduction to PageIndex
Are 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 contextual understanding, domain expertise, and multi-step reasoning, similarity search often falls short — missing what's relevant but not similar, and returning what's similar yet not relevant.
Inspired by AlphaGo, we propose PageIndex — a vectorless, reasoning-based RAG system that builds a hierarchical tree index from long documents, and uses LLMs to reason over that index for agentic, context-aware retrieval. The retrieval is traceable and explainable, with no vector DBs or chunking. PageIndex simulates how human experts navigate and extract knowledge from complex documents through tree search, enabling LLMs to think and reason their way to the most relevant document sections. It performs retrieval in two steps:
- Generate a “Table-of-Contents” tree structure index of documents
- Perform (agentic) reasoning-based retrieval through tree search
🎯 Core Features
PageIndex is a vectorless, reasoning-based RAG engine that mirrors how humans read, delivering traceable, explainable, and context-aware retrieval, without vector databases or chunking.
Compared to traditional vector-based RAG, PageIndex features:
- No Vector DB: Uses document structure and LLM reasoning for retrieval, instead of vector similarity search.
- No Chunking: Documents are organized into natural sections, not artificial chunks.
- Better Traceability & Explainability: Retrieval is reasoning-driven and grounded in explicit page and section references, making every result traceable and interpretable — no more “vibe retrieval” with opaque, approximate vector search.
- Context-Aware Retrieval: Retrieval depends on your full context (e.g., conversation history and domain knowledge), and easily incorporates new context.
- Human-like Retrieval: Mirrors how human experts navigate and extract knowledge from complex documents.
PageIndex achieved state-of-the-art 98.7% accuracy on FinanceBench (financial document QA benchmark), vastly outperforming vector RAG solutions on professional document analysis (blog post).
📍 Explore PageIndex
To learn more, please see a detailed introduction to the PageIndex framework. Check out our GitHub for open-source code, and the cookbooks, tutorials, and blog for more usage guides and examples.
The PageIndex service is available as a ChatGPT-style chat platform, or can be integrated via MCP or API, with enterprise deployment available.
🛠️ Deployment Options
- Self-host — run locally with this open-source repo (using standard PDF parsing).
- Cloud Service — production-grade pipeline with enhanced OCR, tree building, and retrieval for best results. Try instantly on our Chat Platform, or integrate via MCP or API.
- Enterprise — dedicated or private deployment (VPC, on-prem). Contact us or book a demo to learn more.
🧪 Quick Hands-on
- 🔥 Agentic Vectorless RAG (latest) — a simple but complete agentic vectorless RAG example with self-hosted PageIndex, using OpenAI Agents SDK.
- Try the Vectorless RAG notebook — a minimal, hands-on example of reasoning-based RAG using PageIndex.
- Check out Vision-based Vectorless RAG — no OCR; a minimal, vision-based & reasoning-native RAG pipeline that works directly over page images.
🌲 PageIndex Tree Structure
PageIndex can transform lengthy PDF documents into a semantic tree structure, similar to a “table of contents” but optimized for use with LLMs and AI agents. It's ideal for: financial reports, legal documents, regulatory filings, technical manuals, medical literature, academic textbooks, and any long, complex professional documents.
Below is an example PageIndex tree structure. Also see more example documents and generated tree structures.
...
{
"title": "Financial Stability",
"node_id": "0006",
"start_index": 21,
"end_index": 22,
"summary": "The Federal Reserve ...",
"nodes": [
{
"title": "Monitoring Financial Vulnerabilities",
"node_id": "0007",
"start_index": 22,
"end_index": 28,
"summary": "The Federal Reserve's monitoring ..."
},
{
"title": "Domestic and International Cooperation and Coordination",
"node_id": "0008",
"start_index": 28,
"end_index": 31,
"summary": "In 2023, the Federal Reserve collaborated ..."
}
]
}
...
You can generate PageIndex tree structures with this open-source repo. Or use our API for higher-quality results powered by our enhanced OCR and tree building pipeline.
🚀 SDK Usage
A unified PageIndexClient powers both local self-hosted and cloud-managed modes. Mode is auto-detected by whether you pass an api_key.
Install
pip install pageindex
Quick start
from pageindex import PageIndexClient
# Local mode — uses your LLM key (e.g. OPENAI_API_KEY in env).
client = PageIndexClient(model="gpt-4o-2024-11-20")
col = client.collection()
doc_id = col.add("path/to/your.pdf")
print(col.query("What is the main contribution?", doc_ids=doc_id))
# Cloud mode — fully managed, no LLM key needed:
# client = PageIndexClient(api_key="your-pageindex-api-key")
col.query(...) returns the answer string by default. Always pass doc_ids for reliable single-document QA — omitting it queries the entire collection, which is experimental (see below).
Streaming queries
import asyncio
async def main():
async for ev in col.query("Explain multi-head attention", doc_ids=doc_id, stream=True):
if ev.type == "answer_delta":
print(ev.data, end="", flush=True)
elif ev.type == "tool_call":
print(f"\n[tool] {ev.data['name']}")
asyncio.run(main())
ev.type is one of: tool_call, tool_result, answer_delta, answer_done.
Multi-document collections (experimental)
Passing doc_ids scopes the query to a specific subset of documents — this is the recommended path. doc_ids accepts a single id (str) or a list:
col.query("What does this paper say?", doc_ids=doc1) # single
col.query("Compare these two papers", doc_ids=[doc1, doc2]) # multi
Omitting doc_ids queries the entire collection and lets the agent pick which docs to read. This is an experimental feature with a naive first implementation — we're actively working on better cross-document retrieval. A UserWarning is emitted; set PAGEINDEX_EXPERIMENTAL_MULTIDOC=1 to silence it.
⚙️ Package Usage
Note: This package uses standard PDF parsing. For use cases with complex PDFs, our cloud service (via MCP and API) offers enhanced OCR, tree building, and retrieval.
You can follow these steps to generate a PageIndex tree from a PDF document.
1. Install dependencies
pip3 install --upgrade -r requirements.txt
2. Set your LLM API key
Create a .env file in the root directory with your LLM API key. Multi-LLM is supported via LiteLLM:
OPENAI_API_KEY=your_openai_key_here
3. Generate PageIndex structure for your PDF
python3 run_pageindex.py --pdf_path /path/to/your/document.pdf
Optional parameters
You can customize the processing with additional optional arguments:
--model LLM model to use (default: gpt-4o-2024-11-20)
--toc-check-pages Pages to check for table of contents (default: 20)
--max-pages-per-node Max pages per node (default: 10)
--max-tokens-per-node Max tokens per node (default: 20000)
--if-add-node-id Add node IDs (on by default; disable with: --if-add-node-id no)
--if-add-node-summary Add node summaries (on by default; disable with: --if-add-node-summary no)
--if-add-doc-description Add a document description (on by default; disable with: --if-add-doc-description no)
--if-add-node-text Add raw text to nodes (off by default; enable with: --if-add-node-text)
These flags take no value by default (a bare --if-add-node-id turns it on); the
legacy --if-add-node-id no form still works for turning an option off.
Markdown support
We also provide markdown support for PageIndex. You can use the `--md_path` flag to generate a tree structure for a markdown file.
python3 run_pageindex.py --md_path /path/to/your/document.md
Note: in this mode, we use "#" to determine node headings and their levels. For example, "##" is level 2, "###" is level 3, etc. Make sure your markdown file is formatted correctly. If your Markdown file was converted from a PDF or HTML, we don't recommend using this mode, since most existing conversion tools cannot preserve the original hierarchy. Instead, use our PageIndex OCR, which is designed to preserve it, to convert the PDF to a markdown file and then use this mode.
🚀 Agentic Vectorless RAG: An Example
For a simple, end-to-end agentic vectorless RAG example using self-hosted PageIndex (with OpenAI Agents SDK), see examples/agentic_vectorless_rag_demo.py.
# Install optional dependency
pip3 install openai-agents
# Run the demo
python3 examples/agentic_vectorless_rag_demo.py
📈 Case Study: PageIndex Leads Finance QA Benchmark
Mafin 2.5 is a reasoning-based RAG system for financial document analysis, powered by PageIndex. It achieved a state-of-the-art 98.7% accuracy on FinanceBench (financial document QA benchmark), significantly outperforming traditional vector-based RAG systems.
PageIndex's hierarchical indexing and reasoning-driven retrieval enable precise navigation and extraction of relevant context from complex financial reports, such as SEC filings and earnings disclosures.
Explore the full benchmark results and our blog post for detailed comparisons and performance metrics.
🧭 Resources
- 📝 Blog: technical articles, research insights, and product updates.
- 🔧 Developer: MCP setup, API docs, and integration guides.
- 🧪 Cookbooks: hands-on, runnable examples and advanced use cases.
- 📖 Tutorials: practical guides and strategies, including Document Search and Tree Search.
⭐ Support Us
Leave us a star 🌟 if you like our project. Thank you!
Please cite this work as:
Mingtian Zhang, Yu Tang and PageIndex Team,
"PageIndex: Next-Generation Vectorless, Reasoning-based RAG",
PageIndex Blog, Sep 2025.
Or use the BibTeX citation.
@article{zhang2025pageindex,
author = {Mingtian Zhang and Yu Tang and PageIndex Team},
title = {PageIndex: Next-Generation Vectorless, Reasoning-based RAG},
journal = {PageIndex Blog},
year = {2025},
month = {September},
note = {https://pageindex.ai/blog/pageindex-intro},
}
🌐 Open-Source Ecosystem
PageIndex anchors a growing open-source ecosystem of long-context AI infra — OpenKB is an LLM knowledge base that compiles documents into an interlinked wiki. ChatIndex provides tree indexing and retrieval for long conversational histories and memory. ConDB is a KV-cache native context database for tree-based retrieval at scale. PageIndex MCP is PageIndex's MCP server.
Connect with Us
© 2026 Vectify AI