Logisches Arbeiten an einem Dokumentbaum anstelle der Suche in Vektoren
PageIndex erstellt einen hierarchischen Index, der es einem LLM ermöglicht, ihn zu durchqueren, wobei das Aufteilen in Blöcke sowie die Verwendung von Embeddings übersprungen werden. Wie es funktioniert, das Ergebnis von FinanceBench sowie wann es eingesetzt werden sollte.
Quellen: I Threw Out My Vector Database. RAG Got Way Better With PageIndex
Es gibt kaum etwas Peinlicheres, als wenn ein Modell mitten in einer Live-Demo selbstbewusst den falschen Abschnitt eines 200-seitigen Jahresberichts zitiert. Es folgt dann das übliche Szenario: Das Team „behebt“ das Problem durch bessere Aufteilung der Daten, intelligentere Überlappungen sowie ein sorgfältiger abgestimmtes Embedding-Modell – der übliche Verbesserungskreislauf, den jeder RAG-Entwickler durchläuft, in der Überzeugung, dass die nächste Anpassung endlich funktionieren wird. Doch dann antwortet das System auf eine Frage zu den Umsatzzahlenprognosen für 2023 mit einem Absatz aus dem Kapitalausgabenplan von 2021. Da die beiden Abschnitte ähnliche finanzielle Begriffe verwendeten, betrachteten die Embeddings sie als verwandt – tatsächlich waren sie es jedoch nicht.
Ein solcher Fehler wirft die berechtigte Frage auf, ob der gesamte Ansatz von Grund auf fehlerhaft ist.
Warum Ähnlichkeit nicht ausreicht
Jedes RAG-Tutorial vermittelt dasselbe Verfahren: Das Dokument wird in 500-Wort-Abschnitte unterteilt, diese eingebettet, für jede Frage die nächstgelegenen Vektoren gefunden und diese Abschnitte an ein LLM übergeben. Es klingt elegant – semantische Suche in Kombination mit Sprachgenerierung.
Was dieses Verfahren außer Acht lässt, ist, dass Ähnlichkeit nicht gleichbedeutend mit Relevanz ist. Eine Vektordatenbank findet Texte, die semantisch der Frage nahekommen, aber nicht unbedingt solche, die sie beantworten. Ein Absatz über die Risikofaktoren eines Medikaments und ein anderer über seine Wirksamkeit liegen im Embedding-Raum nah beieinander, doch nur einer von ihnen beantwortet eine Frage zu den finanziellen Risiken des Unternehmens.
Das Aufteilen in Blöcke erzeugt ein weiteres Problem. Wenn ein 200-seitiges Rechtsdokument in Fenster mit 500 Tokenn aufgeteilt wird, verschwindet alles, was sein Verfasser sorgfältig aufgebaut hat: Abschnitte, Verweise, logischer Ablauf. Was übrig bleibt, ist ein Haufen von Fragmenten, bei denen unklar ist, woher sie stammen und wie sie miteinander verbunden sind. Eine bessere Aufteilung in Blöcke erleichtert die Sache etwas, löst aber das zugrundeliegende Problem nie, da eine weggeworfene Struktur nicht wiederhergestellt werden kann.
Ein menschlicher Analytiker würde niemals so lesen. Er würde den Inhaltstext überfliegen, direkt zum richtigen Abschnitt springen, diesen im Zusammenhang mit den umliegenden Kapiteln lesen und die Fußnoten prüfen. Er navigiert im Dokument als Ganzes.
Ein Baum anstelle von Vektoren
Das VectifyAI-Team fragte sich, wie ein RAG-System aussehen würde, wenn es auf diese Weise funktionieren würde, und entwickelte PageIndex. Sobald die Kernidee ausgesprochen wird, erscheint sie fast unangenehm offensichtlich: Man verzichtet darauf, Dokumente in Vektoren umzuwandeln und nach Ähnlichkeit zu suchen. Stattdessen wird ein hierarchischer Baumindex des Dokuments erstellt – im Grunde eine maschinenlesbare Inhaltsübersicht – und ein LLM wird dabei helfen, entlang dieses Baums zum relevanten Material vorzudringen.
Das bedeutet keinen Vektordatenspeicher, kein Chunking und keine Ähnlichkeitswerte – nur strukturiertes Indexieren und intelligente Navigation.
Schritt eins: Erstellung des Indexes
PageIndex zerlegt das ihm übergebene Dokument nicht in Fragmente. Er analysiert die natürliche Struktur – also Abschnitte, Unterabschnitte, Überschriften sowie logische Gruppierungen – und erstellt eine Hierarchie, die der Art entspricht, wie ein Experte den Inhalt organisieren würde. Stellen Sie sich ein automatisch generiertes Inhaltsverzeichnis vor, nur umfangreicher. Jeder Knoten enthält mehr als nur einen Titel: eine Zusammenfassung dessen, was seine Unterabteilung umfasst, die Fragen, die er plausibel beantworten kann, sowie seine Beziehung zu den Nachbar- und Überknoten.
Eine 100-seitige technische Spezifikation könnte eine drei- oder vierstellige Hierarchie erzeugen, wobei die wichtigsten Funktionsbereiche an der Spitze und die spezifischeren Themen in den darunterliegenden Unterknoten stehen. Die logische Hierarchie des Dokuments bleibt so, wie der Autor sie angeordnet hat. Der Vorgang wird einmal pro Dokument zu Beginn durchgeführt, und der Index wird gespeichert, während der ursprüngliche Inhalt unverändert und weiterhin zugänglich bleibt.
Zweiter Schritt: Durchquerung der Hierarchie
Wenn eine Anfrage eintrifft, fügt PageIndex sie nicht ein und führt auch keine Suche nach dem nächstgelegenen Knoten durch. Stattdessen navigiert ein LLM durch den Indexbaum. Es liest die Knoten der obersten Ebene und überlegt, welche Abzweigung am ehesten die Antwort enthält, folgt dieser Abzweigung, liest die nächste Ebene und überlegt erneut. Es geht so weiter nach unten, bis die relevanten Abschnitte ermittelt sind.
Das ist der Punkt, der alles verändert. Anschließend lädt es diese vollständigen Abschnitte ohne Fragmentierung aus dem ursprünglichen Dokument herunter und verwendet sie als Kontext für die Antwort.
Die Informationsabrufung ist von vornherein erklärbar. Es ist möglich, genau zu sehen, welche Knoten das LLM durchlaufen hat und auf welche Seiten des Originaldokuments es gelangt ist. Es gibt keinen „Black-Box“-Cosinus-Score, und die Überlegungsabfolge ist sichtbar.
Outfit ausprobieren
Die Einrichtung ist einfach. Beginnen Sie damit, das Repository zu klonen und seine Abhängigkeiten zu installieren:
git clone https://github.com/VectifyAI/PageIndex.git
cd PageIndex
pip3 install --upgrade -r requirements.txt
Erstellen Sie anschließend eine .env-Datei im Wurzelverzeichnis, die den API-Schlüssel enthält:
CHATGPT_API_KEY=your_openai_api_key_here
Um einen PDF zu indizieren, muss der Script darauf verweisen. Ein Finanzbericht ist ein gutes Beispiel, da dort das Tool besonders gut funktioniert:
python3 run_pageindex.py --pdf_path /path/to/annual_report.pdf
Markdown-Dokumente verwenden eine andere Flagge:
python3 run_pageindex.py --md_path /path/to/technical_spec.md
Dadurch ist die Einrichtung abgeschlossen. Es muss keine Vektordatenbank konfiguriert werden, kein Embedding-Modell ausgewählt und es gibt keine Chunking-Parameter, über die man sich den Kopf zerbrechen muss.
Die Verarbeitung eines Dokuments erzeugt eine Indexstruktur, die in etwa so aussieht – hier vereinfacht dargestellt:
{
"document": "Apple Inc. Annual Report 2023",
"index": {
"title": "Apple Inc. Annual Report 2023",
"summary": "Comprehensive financial and operational report covering revenue, product segments, risks, and strategic outlook",
"children": [
{
"title": "Business Overview",
"summary": "Company description, product lines, and market position",
"pages": [1, 8],
"children": [...]
},
{
"title": "Financial Results",
"summary": "Revenue, operating income, EPS, and segment performance for fiscal 2023",
"pages": [45, 72],
"children": [
{
"title": "Revenue by Product Category",
"summary": "iPhone, Mac, iPad, Wearables, and Services revenue breakdown",
"pages": [46, 52]
},
{
"title": "Geographic Revenue Distribution",
"summary": "Americas, Europe, Greater China, Japan, Rest of Asia Pacific",
"pages": [53, 58]
}
]
},
{
"title": "Risk Factors",
"summary": "Operational, market, regulatory, and competitive risks",
"pages": [89, 110]
}
]
}
}
Stellen Sie sich vor, ein Analyst fragt nach den Einnahmen aus iPhones im Haushaltsjahr 2023. Anstatt nach ähnlichen Textfragmenten zu suchen, liest das LLM den Index, kommt zu dem Schluss, dass „Finanzielle Ergebnisse > Einnahmen nach Produktkategorie“ der zu durchsuchende Bereich ist, geht dorthin und holt die Seiten 46 bis 52 vollständig ab. Die Antwort enthält eine genaue Seitenangabe, und da das Modell den Abschnitt zu den Risikofaktoren nie gesehen hat, stört nichts Unwesentliches die Genauigkeit.
Eine vereinfachte Version der auf logischem Denken beruhenden Informationsabrufung sieht im Code so aus:
import json
from openai import OpenAI
client = OpenAI()
def navigate_index(query: str, index_node: dict, depth: int = 0) -> list[dict]:
"""
Recursively navigate the document index using LLM reasoning.
Returns list of relevant leaf nodes with page references.
"""
children = index_node.get("children", [])
if not children:
# Leaf node: return this section as relevant
return [index_node]
# Ask the LLM which branches are relevant to the query
children_summary = "\n".join([
f"[{i}] {child['title']}: {child['summary']}"
for i, child in enumerate(children)
])
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"You are navigating a document index to find sections relevant "
"to a query. Select the index numbers of sections that are likely "
"to contain the answer. Return a JSON array of selected indices."
)
},
{
"role": "user",
"content": (
f"Query: {query}\n\n"
f"Available sections:\n{children_summary}\n\n"
f"Which sections should I look into? Return JSON array of indices only."
)
}
],
temperature=0,
response_format={"type": "json_object"}
)
selected = json.loads(response.choices[0].message.content).get("indices", [])
relevant_nodes = []
for idx in selected:
if idx # Recurse into selected branches
relevant_nodes.extend(
navigate_index(query, children[idx], depth + 1)
)
return relevant_nodes
def answer_with_pageindex(query: str, index: dict, document_pages: dict) -> str:
"""
Full PageIndex retrieval and answer generation.
"""
# Navigate the index to find relevant sections
relevant_nodes = navigate_index(query, index)
# Retrieve full text from identified pages
context_parts = []
citations = []
for node in relevant_nodes:
pages = node.get("pages", [])
if pages:
page_start, page_end = pages[0], pages[1]
for page_num in range(page_start, page_end + 1):
if page_num in document_pages:
context_parts.append(document_pages[page_num])
citations.append(f"p.{page_num}")
context = "\n\n".join(context_parts)
# Generate answer with full, unchunked context
answer_response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"Answer the question based on the provided document sections. "
"Be precise. If the answer involves numbers or dates, quote them exactly."
)
},
{
"role": "user",
"content": f"Document sections:\n{context}\n\nQuestion: {query}"
}
],
temperature=0
)
answer = answer_response.choices[0].message.content
citation_str = ", ".join(set(citations))
return f"{answer}\n\n**Source:** {citation_str}"
Betrachten Sie, was fehlt: Embeddings, Kosinusähnlichkeit, Vektordatenbanken sowie Logik zur Aufteilung in Abschnitte. Strukturiertes Reasoning über einen Dokumentindex ersetzt den gesamten Abrufprozess.
Beweise aus einem Finanz-Benchmark
FinanceBench sammelt Fragen zu echten Finanzdokumenten wie SEC-Unterlagen, Jahresberichten und Gewinnmitteilungen. Die Antworten müssen numerisch präzise sein, die Abschnitte müssen genau zugeordnet werden und Fußnoten sorgfältig gelesen werden. RAG-basierte Ansätze haben hier oft Schwierigkeiten, da Finanzdokumente voller ähnlich klingender Formulierungen zu unterschiedlichen Themen sind.
Mafin 2.5, der auf PageIndex basiert, erreichte auf FinanceBench eine Genauigkeit von 98,7 %. Typische Vektor-RAG-Systeme bei vergleichbaren Finanzbenchmarks erzielen je nach Konfiguration Werte zwischen 65 und 80 %. Dieser Unterschied ist keineswegs gering – er unterscheidet ein Werkzeug, dem ein Investmentanalyst tatsächlich vertrauen kann, von einem, das plausibel klingendes Unsinn erzeugt, das Zeile für Zeile überprüft werden muss.
Die Struktur erklärt das. In Finanzdokumenten ist gerade die Hierarchie von größter Bedeutung. Ein konsolidierter Bilanzplan, die Anhangangaben sowie die MD&A folgen alle einem klaren, durchdachten Aufbau, auf den Analysten ständig angewiesen sind. PageIndex bewahrt und nutzt diesen Aufbau, während das Vektor-Chunking ihn zerstört.
Wann welches wählen?
PageIndex ersetzt Vektor-RAG nicht universell. Die richtige Wahl hängt vom Projekt ab.
Er eignet sich besonders gut, wenn:
- Die Dokumente weisen eine klare Hierarchie auf, wie bei Berichten, Handbüchern, Verträgen und Spezifikationen.
- Genauigkeit und korrekte Zitierungen sind unverzichtbar.
- Es handelt sich um ein spezialisiertes Gebiet, wie Finanzen, Recht, Medizin oder regulatorische Tätigkeiten.
- Fragen erfordern Verweise auf mehrere Abschnitte desselben Dokuments.
- Erklärbarkeit ist wichtig, und das System muss zeigen, warum es das getan hat, was es getan hat.
Traditionelle vektorbasierte RAG-Lösungen sind weiterhin sinnvoll, wenn:
- Das Korpus aus Tausenden kurzer, unabhängiger Dokumente besteht, wie z. B. Support-Tickets oder Produktbewertungen.
- Die Dokumente keine einheitliche Struktur aufweisen.
- Das Ziel eine annähernde semantische Suche in einem umfangreichen Korpus ist.
- Die Latenz die Hauptbeschwerde ist und das Chunking bereits optimiert wurde.
Die meisten Anwendungsfälle für Unternehmensdokumente, bei denen ein System wirklich nützlich sein muss und nicht nur in einer Demo beeindruckend wirken soll, ähneln viel mehr der ersten Liste als der zweiten.
Für den Produktivbetrieb ohne die Belastung durch Infrastruktur bietet PageIndex außerdem eine REST API sowie MCP-Integration. Die Einrichtung für Entwickler sieht wie folgt aus:
import requests
PAGEINDEX_API_KEY = "your_api_key"
BASE_URL = "https://api.pageindex.ai/v1"
def upload_document(file_path: str) -> str:
"""Upload a document and get back a document_id."""
with open(file_path, "rb") as f:
response = requests.post(
f"{BASE_URL}/documents",
headers={"Authorization": f"Bearer {PAGEINDEX_API_KEY}"},
files={"file": f}
)
return response.json()["document_id"]
def query_document(document_id: str, question: str) -> dict:
"""Query an indexed document and get a cited answer."""
response = requests.post(
f"{BASE_URL}/query",
headers={
"Authorization": f"Bearer {PAGEINDEX_API_KEY}",
"Content-Type": "application/json"
},
json={
"document_id": document_id,
"question": question
}
)
return response.json()
# Example usage
doc_id = upload_document("q3_earnings_report.pdf")
result = query_document(doc_id, "What was total revenue in Q3?")
print(result["answer"])
print(f"Sources: {result['citations']}")
Beim Hochladen erstellt die API automatisch den Index, und bei einer Abfrage liefert sie strukturierte Antworten mit nachvollziehbaren Seitenverweisen.
Die größere Idee
Hinter den Benchmark-Werten geht etwas Tieferes vor sich. Herkömmliche Vektor-RAG-Systeme betrachten ein Dokument als einen Satz zusammenhängender Textfragmente und ignorieren die von dessen Autor geschaffene Struktur. Jeder Überschrift, Absatzbruch und Verweis ist ein Signal – die Art und Weise, wie der Autor den Lesern zeigt, wohin sie gehen sollen –, doch das Zerlegen in Blöcke vernichtet all das, bevor versucht wird, Relevanz aus dem Nichts wiederherzustellen. PageIndex behandelt ein Dokument genau so, wie es ist: als strukturiertes Werkzeug, das für die Navigation durch einen kompetenten Leser konzipiert ist.
Ein leitender Analyst, der einen Jahresbericht durchliest, beginnt nicht bei Seite eins. Er schaut sich den Inhaltstext an, springt direkt zu dem Teil, der ihn interessiert, überprüft eine Zahl anhand der Anmerkungen und kehrt anschließend zum MD&A zurück. Das LLM in PageIndex macht genau dasselbe.
Deshalb gilt das auch für spezialisierte Bereiche. Ein Bericht über eine pharmazeutische Studie hat eine andere Hierarchie als ein Rechtsvertrag oder eine technische Spezifikation – doch in jedem Fall folgt der Autor einer internen Logik, die erfahrene Leser nutzen können. PageIndex erfasst diese Logik und ermöglicht so die Suche entsprechend.
Eine andere Diagnose
Die ernüchternde Schlussfolgerung ist, dass jahrelange Bemühungen vielleicht das falsche Problem anvisiert haben. Der Fokus lag auf Chunking-Strategien, obwohl der eigentliche Fehler bereits zu Beginn die Struktur zerstörte. Embedding-Modelle wurden angepasst, obwohl semantische Ähnlichkeit niemals das richtige Signal für die Suche war. Reranker wurden hinzugefügt, um die Suchqualität zu retten, obwohl die Suchmethode selbst das Engpassproblem darstellte.
Das RAG-Ökosystem entwickelte komplexe Mechanismen, um den ursprünglichen Fehler des Chunkings auszugleichen. PageIndex schlägt eine Alternative vor: Keine Chunks, keine Embeddings, keine Ähnlichkeitssuche. Man sollte einen Index erstellen, der die tatsächliche Struktur des Dokuments widerspiegelt, und sich durch ihn mithilfe von Schlussfolgerungen bewegen.
Es beantwortet nicht alles. Bei semantischer Suche in Millionen kurzer, unstrukturierter Dokumente bleibt die Vektorsuche weiterhin überlegen. Für die breite Palette von Fragen zu langen, strukturierten Dokumenten, die den größten Teil der Unternehmensanforderungen abdeckt, verdient ein hierarchisches Baumstrukturmodell jedoch ernsthafte Aufmerksamkeit. Führen Sie die zweimal fehlgeschlagene Demo erneut durch, indem Sie nach Umsatzzahlenprognosen für 2023 fragen – das System weist Sie nun auf den richtigen Abschnitt hin, lädt die richtigen Seiten und antwortet mit genauen Quellenangaben. Kein falsches Jahr, kein falscher Abschnitt, keine fehlerhafte Zuversicht.
PageIndex ist Open Source und kann auf GitHub selbst gehostet werden. Zudem stehen eine gehostete Chat-Schnittstelle sowie API-Dokumentation mit Referenzen zu REST und MCP zur Verfügung, um es mit Ihren eigenen Dokumenten auszuprobieren.
Verwandte Artikel
- 30 RAG- und Vektordatenbank-Interviewfragen mit prägnanten Antworten — Dreißig Interviewfragen zu RAG und Vektorsuche mit kurzen Antworten: hybride Suche, HNSW gegenüber IVF, Chunking, Neubewertung, Bewertungsmetriken und Sicherheit für mehrere Nutzer.
- Vektorlose RAG: Wie PageIndex Dokumente ohne Embeddings liest — Die Vektorsuche teilt lange Dokumente in Blöcke auf und verliert dabei den Kontext. Erfahren Sie, wie ein auf Schlussfolgerungen basierender Baumindex Antworten in komplexen Berichten mithilfe von Code findet.