Startseite / Artikel / Vergleich von RAG, vektorlosem RAG und GraphRAG

Vergleich von RAG, vektorlosem RAG und GraphRAG

Klassischer Vektor-RAG, lexikalische vektorlose Suche und GraphRAG: Chunking, Embeddings, BM25, Mehrschritt-Graphen – und wann sich jeder Ansatz lohnt.

1834 Wörter

Wie heutige Sprachmodelle auf Material antworten, das nie im Training vorkam.

RAG in einem Satz

Retrieval Augmented Generation bedeutet genau das, was der Akronym ausdrückt. Zuerst werden Materialien abgerufen, die mit der Frage des Benutzers zusammenhängen. Anschließend erstellt ein Modell eine Antwort unter Verwendung dieses Materials sowie der Eingabeanweisung. Das Muster lautet: Zuerst Abruf, dann Erstellung.

Warum die Mühe?

Modelle kennen nur das, was in ihrem Trainingsdatensatz enthalten war. Alles andere bleibt unsichtbar.

Stellen Sie sich ein seltenes 3.000-seitiges Buch vor, das kaum online zu finden ist und niemals in irgendein Trainingskorpus aufgenommen wurde. Wenn Sie ein Modell danach fragen, erhalten Sie leere Antworten. Auch mit Scrapern kommt man nicht weiter – es gibt nichts zu extrahieren.

RAG schließt diese Lücke. Laden Sie das PDF in den Pipeline-Prozess. Zum Zeitpunkt der Abfrage werden die relevantesten Abschnitte abgerufen und als Kontext hinzugefügt. Die Aufgabe des Modells reduziert sich darauf, aus diesem Text zu antworten und dabei sprachliche Fähigkeiten gezielt einzusetzen.

Keine Feinabstimmung erforderlich. Einfach der richtige Kontext zur richtigen Zeit.

Skelett des Pipelines

Zuerst kommt das Indexieren, und dieses beginnt mit dem Aufteilen in Blöcke.

Strategien zum Aufteilen

Ein mehrtausendseitiges PDF gehört nicht als ein einziger Datensatz in einen Vektor-Speicher. Teilen Sie es so auf, dass jeder Teil separat eingebettet und abgerufen werden kann.

Gängige Aufteilungsweisen:

Pro Seite. Eine Seite → ein Block (3.000 Seiten → 3.000 Blöcke). Geeignet, wenn präzise und genaue Ergebnisse gewünscht sind.

Pro Absatz. Feinere Trennungen an den Absatzgrenzen. Kann ein präziseres Ergebnis liefern, doch die Größen schwanken stark (200 Token neben 2.000). Ungleichmäßige Längen führen zu ungleichmäßigen Embeddings und schädigen indirekt die Suchfunktion.

Feste Fenster. Konstante Token-Budgets – oft 512 – unabhängig davon, wo die Trennung erfolgt. Einheitliche Größen ergeben vergleichbarere Embeddings. Wenn man unsicher ist, wenden die meisten Teams diese Methode standardmäßig an.

from langchain_text_splitters import CharacterTextSplitter
from langchain_core.documents import Document

def perform_fixed_size_chunking(document, chunk_size=1000, chunk_overlap=200😞
    """
    Performs fixed-size chunking on a document with specified overlap.

    Args:
        document (str): The text document to process
        chunk_size (int): The target size of each chunk in characters
        chunk_overlap (int): The number of characters of overlap between chunks

    Returns:
        list: The chunked documents with metadata
    """
    # Create the text splitter with optimal parameters
    text_splitter = CharacterTextSplitter(
        separator="\n\n",
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        length_function=len
    )

    # Split the text into chunks
    chunks = text_splitter.split_text(document)
    print(f"Document split into {len(chunks)} chunks")

    # Convert to Document objects with metadata
    documents = []
    for i, chunk in enumerate(chunks):
        doc = Document(
            page_content=chunk,
            metadata={
                "chunk_id": i,
                "total_chunks": len(chunks),
                "chunk_size": len(chunk),
                "chunk_type": "fixed-size"
            }
        )
        documents.append(doc)

    return documents

# Example usage
if __name__ == "__main__":

    # Create the dummy document
    document = create_dummy_document()

    # Process with fixed-size chunking
    chunked_docs = perform_fixed_size_chunking(
        document,
        chunk_size=1000,
        chunk_overlap=200
    )

    # Display results
    print("\n----- CHUNKING RESULTS -----")
    print(f"Total chunks: {len(chunked_docs)}")

    # Print an example chunk
    print("\n----- EXAMPLE CHUNK -----")
    middle_chunk_idx = len(chunked_docs) // 2
    example_chunk = chunked_docs[middle_chunk_idx]
    print(f"Chunk {middle_chunk_idx} content ({len(example_chunk.page_content)} characters):")
    print("-" * 40)
    print(example_chunk.page_content)
    print("-" * 40)
    print(f"Metadata: {example_chunk.metadata}")

    # For integration with Databricks Vector Search
    print("\nThese documents are ready for embedding and storage in Databricks Vector Search")
    print("Example next steps:")
    print("1. Create embeddings using the Databricks embedding endpoint")
    print("2. Store documents and embeddings in Delta table")
    print("3. Create Vector Search index for retrieval")

Embeddings

Ein Embedding wandelt Text (Wort, Satz, Seite) in einen dichten, hochdimensionalen Vektor um, der die Bedeutung kodiert, sodass ähnliche Ideen zusammengefasst werden.

Vier Phasen innerhalb von RAG

  1. Seite des Korpus. Jedes Stück wird eingebettet; Index sowie Vektor werden gespeichert.
  2. Seite der Anfrage. Die Benutzereingabe wird eingebettet, damit die Anfrage einen semantischen Fingerabdruck erhält.
  3. Auswertung. Im Speicher werden die nächstgelegenen Elemente gesucht – typischerweise mithilfe der Kosinusähnlichkeit.
  • Erweiterung. Fügen Sie die abgerufenen Abschnitte als zusätzlichen Kontext hinzu; das Modell antwortet auf Basis von Prompt + Kontext.
  • Wo Vektoren gespeichert werden

    Es handelt sich um einen spezialisierten Speicher für Embeddings, nicht um eine allgemeine relationale oder Objektdatenbank. AlloyDB, Pinecone und Qdrant sind gängig; viele Teams verwenden pgvector in PostgreSQL.

    Wo herkömmliche Vektor-RAG-Lösungen Schwierigkeiten haben

    1. Abschnitte können die Bedeutung ignorieren. Verwandte Abschnitte können voneinander getrennt sein; ein größerer Überschneidungsbereich hilft manchmal, ist aber keine Allheilmethode.
    2. Ähnlichkeitsmessungen können Paraphrasen übersehen – „Umsätze sind gesunken“ und „Das Unternehmen befindet sich im Niedergang“ liegen möglicherweise nicht in der Nähe voneinander im Vektorraum.
    3. Mehrschrittige Zusammenhänge funktionieren nicht, wenn Ursache und Wirkung in unterschiedlichen Abschnitten liegen und nur einer abgerufen wird.
    4. Die Erstellung, Speicherung, Indizierung und Neuindizierung von Embeddings ist aufwändig.

    Daher: Eine Vektordatenbank ist kein Synonym für RAG. Sie ist lediglich ein Rückend für die Informationsabrufung. Vectorloses RAG beibehält das Verfahren „abrufen und dann generieren“, verzichtet jedoch auf die Suchfunktion mit Embeddings.

    Warum auf Vektoren verzichten? Die Kosten für den Aufbau bzw. die Neindekxisierung von Embeddings, das schwache Verhalten bei exakter Übereinstimmung für IDs/Zahlen/Fehlercodes sowie die zusätzliche Infrastruktur, die zum Betrieb benötigt wird.

    Vectorloses RAG ist eine Familie von Ansätzen, keine einheitliche Lösung:

    1. Lexikalische Suche. BM25, Postgres tsvector, Elasticsearch – exakte Begriffe sind besser geeignet als unscharfe semantische Analyse bei SKUs, Zitaten und Logzeilen.
    from rank_bm25 import BM25Okapi
    
    def vectorless_retrieve(query, corpus_chunks, top_k=3):
        """
        Lexical retrieval over raw text chunks - no embeddings, no vector DB.
        """
        tokenized_corpus = [chunk.lower().split() for chunk in corpus_chunks]
        bm25 = BM25Okapi(tokenized_corpus)
    
        tokenized_query = query.lower().split()
        scores = bm25.get_scores(tokenized_query)
    
        ranked = sorted(zip(corpus_chunks, scores), key=lambda x: x[1], reverse=True)
        return [chunk for chunk, score in ranked[:top_k]]
    
    1. Agentenbasierte / toolbasierte Informationsabrufung. Keine vorherige Indizierung; das Modell durchsucht selbst, ruft Such-APIs auf oder öffnet Abschnitte nach Bedarf, ähnlich wie ein Programmieragent in einem Repository vorgeht. Echtzeitige, auf Logik basierende Abfragen.
  • Langer Kontextinhalt. Durch enorme Kontextfenster können auch kleine Korpora im Prompt berücksichtigt werden. Es handelt sich nicht um klassische Abrufverfahren, doch die Ergebnisse sind für kleinere Korpora ähnlich.
  • Hybrider Neurangieren. Zuerst wird eine günstige lexikalische Kurzliste erstellt, anschließend ordnet ein Modell die Elemente nach Relevanz um – eine Kombination aus schnellen Schlüsselwortabfragen und gewissen semantischen Nuancen, ohne vorherige Erstellung eines vollständigen Embedding-Index.
  • Beschränkungen ohne Vektoren

    Schlüsselwörter übersehen weiterhin Paraphrasen – manchmal sogar schlimmer als Embeddings. Agentenbasierte Schleifen erhöhen die Latenz sowie die Anzahl der Tokens pro Abfrage. Auch große Korpora bevorzugen weiterhin einen gut aufgebauten Vektorindex. Methoden ohne Vektoren haben tendenziell Vorteile bei kleineren/mittleren Skalen oder dann, wenn Genauigkeit wichtiger ist als Unschärfe.

    GraphRAG

    Klassisches RAG kann Ursache und Wirkung in verschiedenen Datenblöcken voneinander trennen. GraphRAG ersetzt Embeddings durch Schlüsselwörter oder langen Kontextinhalt. Keines dieser Ansätze modelliert, wie Ideen miteinander verbunden sind. GraphRAG zielt genau auf diese Lücke ab.

    Anstatt zu fragen „Welcher Teil ist am nächsten?“, fragen Sie lieber: „Wie verbinden sich diese Konzepte?“ Die Antwort ist ein Wissensgraph.

    Indizierung – der Graph erweitern

    Überspringen Sie zunächst die Teilbereiche/Einbettungen. Lassen Sie das Dokument durch ein Modell laufen, das Entitäten und Beziehungen extrahiert. Das Ergebnis sind Knoten und Kanten.

    In einem solchen umfangreichen Theoriebuch könnten Knoten wie Marx, Engels, Kapital, Das Kommunistische Manifest, Mehrwert, dialektischer Materialismus entstehen, sowie Kanten wie „verfasst“, „mitverfasst“, „Konzept einführren“.

    Entitäten werden zu Knoten; Beziehungen zu Kanten. Sie kartieren Bedeutungen, nicht Seitenabschnitte.

    Klammern Sie eng miteinander verbundene Knoten zu Gemeinschaften zusammen (Leiden ist hier beliebt) und fassen Sie anschließend jede Gemeinschaft durch einen weiteren Modelllauf zusammen.

    Arbeiten Sie auf zwei Ebenen:

    • Knoten für spezifische Fakten und direkte Verbindungen
    • Gemeinschaften für Themen und Zusammenfassungen

    Kleine Fragen → Knoten. Umfassende Fragen zu „Kernideen“ → Zusammenfassungen der Gemeinschaft. Ein Index, zwei Abrufmodi.

    Absuchen – durch das Graphen wandern

    Frage: „Wer hat mit Marx gemeinsam geschrieben, und was haben sie zusammen verfasst?“

    Vanilla RAG hat Schwierigkeiten: Die Mitautorschaft befindet sich in einem Abschnitt, die Werke hingegen Hunderte Seiten entfernt – man hofft auf Übereinstimmung der Embeddings.

    Graph RAG wandert wie folgt voran:

    1. Marx als Anker erkennen
    2. Den Knoten und die Kanten von Marx laden
    3. Über „mit Marx gemeinsam geschrieben“ zu Engels folgen
    4. Über „von Engels verfasst“ zu Manifest, Zustand der Arbeiterklasse und verwandten Werken folgen

    Geschriebene, gerichtete Kanten bewahren die Beziehungen bei. Ursache und Wirkung, die beim klassischen RAG getrennt werden, werden zu verbundenen Knoten. Dieses Mehrschritt-Muster ist sowohl für einfaches als auch für vektorloses RAG schwierig sauber umzusetzen.

    Knoten, Kanten und Zusammenfassungen der Gemeinschaft zu einem Kontext zusammenfügen; wie üblich generieren.

    from graphrag import GraphRAGPipeline
    
    # Indexing — runs once
    pipeline = GraphRAGPipeline(llm="claude-3", graph_store="neo4j")
    pipeline.index(documents=["book.pdf"])
    # Under the hood: entity extraction → graph build → community detection → summaries
    
    # Querying
    result = pipeline.query(
        "Who co-wrote with Marx and what did they write together?",
        mode="global"   # uses community summaries for broad questions
        # mode="local"  # uses node-level traversal for specific facts
    )
    print(result.answer)
    print(result.sources)   # returns actual nodes + edges used, fully traceable
    

    mode ist nicht rein kosmetischer Natur. Implementierungen (einschließlich von Microsofts Open-Source-Stack) unterscheiden zwischen globaler und lokaler Verarbeitung, da es sich um unterschiedliche Strategien handelt.

    Kosten von GraphRAG

    Die Extraktion ist aufwändig. Das gesamte Dokument muss gelesen werden; lange Bücher verbrauchen viele Token; implizite Verweise (“wie bereits zuvor besprochen”) werden möglicherweise niemals zu Kanten.

    Die Qualität des Graphen begrenzt die Gesamtleistung. Schlechte Extraktion → schlechter Graph → schlechtere Suchergebnisse. Lösungen bedeuten oft das erneute Lesen aller Inhalte, was bei großen Datenmengen problematisch ist.

    In der Praxis sollte man den Suchmechanismus je nach Anfrageart auswählen, anstatt für jede Frage einen festen Weg zu verwenden.

    Zusammenfassung: Verwenden Sie klassisches RAG für semantische Abfragen, vectorbasierte Methoden, wenn Genauigkeit oder weniger Infrastruktur erforderlich sind, und Graph RAG, wenn Beziehungen im Vordergrund stehen.

    Entscheidung über den Suchstil ohne Dogmen

    Eine nützliche Entscheidungsabfolge sieht so aus.

    Beginnen Sie mit dem klassischen Vektor-RAG, wenn Ihr Korpus groß ist, die Sprachen stark variieren und Sie in der Regel annähernde semantische Nachbarn benötigen. Investieren Sie frühzeitig in die Qualität der Teilung des Korpus in Blöcke sowie in Prozesse zur Aktualisierung der Embeddings – das sind die Faktoren, die die Qualität bestimmen.

    wenden Sie vektorlose Techniken an, wenn genaue Identifikatoren wichtiger sind als Paraphrasen, wenn das Korpus klein genug ist für eine lexikalische Suche oder den Einsatz eines langen Kontexts, oder wenn Sie die Kosten für eine Embedding-Infrastruktur vermeiden möchten. BM25 und ähnliche Methoden sind nicht „veraltet“ – sie eignen sich hervorragend für SKUs, Zitate und Fehlermeldungen.

    wenden Sie Graph-RAG an, wenn die Produktfrage relationell ist: Wer steht mit wem in Verbindung, welches Konzept hat welche Idee eingeführt, welche Community fasst ein Thema zusammen. Rechnen Sie mit höheren Indexierungskosten und betrachten Sie die Qualität der Extraktion als eine entscheidende Voraussetzung.

    Viele Teams wählen letztendlich einen hybriden Ansatz: zunächst eine lexikalische Verarbeitung, anschließend eine vektorbasierte Verarbeitung sowie die Verwendung von Graphen für einen Teil der mehrstufigen Domänen. Es geht nicht darum, sich für eine bestimmte Methode zu entscheiden, sondern darum, den Retriever dem tatsächlich auftretenden Fehlermodus anzupassen.

    Operative Hinweise, die in den Demos weggelassen werden

    Die Schemata für das Neindeksieren sind wichtig. Veraltete Embeddings verschlechtern leise den Funktionsumfang von Vector RAG – selbst wenn das Modell unverändert bleibt. Die Einstellungen zur Überlappung sind relevant, wenn benachbarte Fenster ähnliche Bedeutungen haben. Metadatenfilter sind wichtig, wenn Mieter niemals auf die Daten anderer zugreifen dürfen. Bewertungssätze sind wichtig, wenn man ohne Labels von „besserer“ Leistung spricht.

    Für Graph RAG sollte man auf Wiederholungsversuche bei der Extraktion, teilweise Graph-Updates sowie erneute Zusammenfassung von Gemeinschaften bei Dokumentänderungen vorbereitet sein. Bei agiler Retrieval-Logik sind Budgets für Tools sowie Timeout-Einstellungen notwendig, damit ein neugieriges Modell nicht die Token-Börse durch eine einzige Abfrage aufbraucht.

    Niemand dieser Notizen ist besonders beeindruckend. Sie bilden den Unterschied zwischen einem Diagramm und einem System, das einen Monat lang echtem Verkehr standhält.