Blog
Technische Deep Dives

Ein hybrides RAG-Pipeline mit Reciprocal Rank Fusion bauen

Wie Vektorähnlichkeit und PostgreSQL-Volltextsuche parallel laufen und durch Reciprocal Rank Fusion zu Antworten mit Zitaten und Relevanzwerten fusioniert werden.

Simmetric Team7 Min. Lesezeit12/06/2026

Warum eine einzige Retrieval-Strategie nie genug ist

Retrieval-augmented generation steht und fällt mit dem, was der Retriever dem Modell übergibt. Stellen Sie einer Wissensbasis eine Frage, und die Antwort ist nur so gut wie die Chunks davor - und enterprise-Fragen kommen in zwei Formen, die keine einzelne Suchstrategie gut beherrscht.

Semantische Fragen - "wie handhabt die Abrechnung die Pro-Rata-Berechnung?", "was haben wir zu Vendor-Lock-in entschieden?" - betreffen Bedeutung. Vektorsuche glänzt hier: Sie bettet die Abfrage und die Dokument-Chunks in denselben Raum ein und ruft die nächsten Nachbarn ab, sodass auch ein in ganz anderen Worten geschriebener Chunk auftauchen kann. Aber reine Vektorsuche ist unzuverlässig für die andere Frageform: exakte Identifikatoren. Produktcodes, Fehlerstrings, Regulierungsnummern, Personennamen - Embeddings verwischen sie, und der nächste Nachbar eines obskuren Fehlercodes ist oft ein anderer, nicht verwandter Code.

Stichwortfragen sind das Spiegelbild. PostgreSQL-Volltextsuche trifft exakte Tokens und seltene Begriffe, verfehlt aber Paraphrasen völlig: Fragen Sie nach "Personalaufstockung", und das Dokument mit "Vertragspersonal-Beschaffung" wird nicht gefunden.

Echte Unternehmensdokumente ziehen beide Fragearten an, oft in derselben Sitzung. Simmetric Chat weigert sich daher zu wählen. Jeder Retrieval läuft zwei Beine parallel - Vektorähnlichkeit und PostgreSQL-Volltextsuche - und fusioniert die Ergebnisse mit Reciprocal Rank Fusion (RRF), bevor irgendetwas das Modell erreicht. Dieser Artikel führt durch das Pipeline: die beiden Beine, die Fusions-Mathematik, den Ingestionspfad, der sie speist, und die Zitationsschicht, die Antworten überprüfbar macht.

Zwei Beine, eine Abfrage

Wenn ein Chat Wissen braucht, ruft der ReAct-Agent seine rag_search-Skill auf, und die hybride Suche startet zwei unabhängige Retrievals gleichzeitig:

  • Das Vektorbein verlässt den Server und ruft den Collector, den Dienst, dem der Vektorspeicher gehört. Der Collector bettet die Abfrage mit demselben Embedding-Modell wie bei der Ingestion ein und gibt die nächsten Chunks aus der Sammlung des Workspace zurück. Der Vektorspeicher selbst ist steckbar - LanceDB standardmäßig (dateibasiert, lokal, air-gap-freundlich), oder Qdrant, pgvector oder Chroma für Deployments, die einen serverseitigen Index bevorzugen.
  • Das Volltextbein verlässt den Server nie. Es fragt PostgreSQL direkt ab und gleicht die Abfrage mit einer verketteten Volltext-Vektorspalte auf der Chunk-Tabelle ab, gestützt durch einen GIN-Index und nach lexikalischer Relevanz sortiert. Die Tokenisierung ist sprachbewusst über sieben Sprachen, sodass italienische und deutsche Dokumente mit ihren eigenen Wortregeln durchsuchbar sind statt mit englischen Annäherungen.

Sammlungen sind pro Workspace, und genau das hält Wissen abgeschottet: Ein Chat in Workspace A ruft die Chunks von Workspace A ab und sonst nichts. Beide Beine bei jeder Abfrage laufen zu lassen kostet einen zusätzlichen Roundtrip und kauft Abdeckung, die kein Bein allein hat.

Auch das Fehlermodus ist bewusst redundant. Ein Guard vergleicht das heute konfigurierte Embedding-Modell mit dem, mit dem die Dokumente des Workspace eingebettet wurden. Bei einer Abweichung - etwa nach einem Modellwechsel - wird das Vektorbein komplett übersprungen und der Retrieval degradiert auf Volltext, statt Ähnlichkeitswerte aus unvergleichbaren Embedding-Räumen zu liefern. Der Chat funktioniert weiter, und der Operator bekommt einen expliziten Re-Index-Pfad im Admin-Panel statt einer stillen Qualitätsregression.

Reciprocal Rank Fusion, konkret

Die beiden Beine liefern Ranglisten, die auf unvergleichbaren Skalen gemessen werden: Kosinusähnlichkeit auf der einen Seite, lexikalische Relevanz auf der anderen. Die Rohwerte zu mitteln hieße, diese Skalen gegeneinander zu kalibrieren - fragil und anders für jedes Embedding-Modell und jeden Korpus. Simmetric Chat fusioniert Ränge statt Werte, mit Reciprocal Rank Fusion:

text
fused(chunk) = sum over legs of 1 / (k + rank),  with k = 60

Jeder Chunk akkumuliert einen Beitrag pro Bein, in dem er erscheint, sodass ein auf beiden Beinen erstplatzierter Chunk etwa doppelt so viel erzielt wie ein nur auf einem Bein erstplatzierter. Die Konstante k dämpft den Einfluss der Spitzenränge - mit k = 60 ist der Unterschied zwischen Rang eins und Rang fünf auf einem Bein ein kleines Delta, und Konsens über Beine hinweg ist es, der einen Chunk in der fusionierten Liste wirklich nach oben bringt.

Zwei technische Details machen die Fusion produktionsreif statt lehrbuchhaft:

  • Ein Quellsatz pro Chunk protokolliert, ob er vom Vektorbein, vom Volltextbein oder von beiden gefunden wurde. Ein von beiden Beinen abgerufener Chunk ist die stärkste Bestätigung, die das Pipeline produzieren kann, und die nachgelagerte Formatierung bewahrt dieses Signal, statt es zu einebnen.
  • Ein deterministischer Tiebreaker - fusionierter Wert absteigend, dann Dokument-ID, dann Chunk-Position - garantiert, dass dieselbe Abfrage auf jeder Replik denselben Rang liefert. Wenn jemand fragt "warum hat es diesen Absatz zitiert?", muss die Antwort reproduzierbar sein; nichtdeterministische Fusion würde die Frage unbeantwortbar machen.

Von Dokumenten zu durchsuchbaren Chunks

Fusion ist nur die halbe Pipeline; die andere Hälfte passiert bei der Ingestion, wenn ein hochgeladenes Dokument zu Chunks wird, die beide Beine durchsuchen können. Der Collector parst PDF-, Word-, Excel-, PowerPoint-, Markdown-, CSV-Dateien und YouTube-Transkripte, teilt den Text mit einem rekursiven Zeichen-Splitter (1.000 Zeichen pro Chunk, 200 Zeichen Überlappung, damit Sätze, die eine Grenze überschreiten, nicht verloren gehen), bettet jeden Chunk ein und schreibt die Vektoren in die Sammlung des Workspace.

Entscheidend: Der Chunk-Text landet auch in PostgreSQL, wo der Server den Volltext-Suchvektor pflegt, den das FTS-Bein abfragt. Der Collector fasst die relationale Datenbank nie an - eine harte Servicegrenze, die die Parse-und-Embed-Pipeline austauschbar hält und den Suchindex im Besitz des Servers lässt, der ihn abfragt.

Version 0.22 machte den Retrieval in einer zweiten Dimension präzise: Metadaten-Filterung. Der Agent kann einen rag_search-Aufruf jetzt auf Dokumenttypen (PDF, Markdown, TXT, CSV, DOCX, XLSX) und Ingestions-Zeitfenster eingrenzen, was den klassischen "2023er-Dokumente beantworten 2025er-Fragen"-Fehler behebt. Filter laufen durch beide Beine - als echte Pre-Filter auf gestempelten Ingestions-Metadaten in den Vektorspeichern und als parametrisierte SQL-Prädikate auf der Volltextseite. Ein serverseitiger Metadaten-Backstop prüft dann jedes fusionierte Ergebnis gegen die maßgebliche Dokumententabelle, sodass die Filterkorrektheit nicht von der korrekten Prädikatimplementierung jedes Vektorproviders abhängt. Alte, vor dem Metadaten-Stempel eingelesene Vektoren fallen bei aktivem Filter einfach heraus und gewinnen ihre Filterbarkeit durch ein admin-ausgelöstes Re-Embed zurück.

Antworten, die ihre Arbeit zeigen

Retrievalqualität ist nur die halbe Geschichte; die andere Hälfte ist Ehrlichkeit darüber, worauf die Antwort gründet. Zitate fließen durch denselben Streaming-Kanal wie Tokens: Zitat-Badges erscheinen inline in der Antwort, jedes mit Quelldokument, Chunk und Relevanzwert, und jedes verlinkt zur Quelle, sodass ein Leser die Behauptung mit einem Klick verifizieren kann.

Auch die Frische-Disziplin lebt hier. Nach der Deduplikation der fusionierten Ergebnisse begrenzt ein Grounding-Filter Zitate pro Dokument auf die Top zwei nach Relevanzwert und verwirft Chunk-Zitate, deren Text keine signifikante lexikalische Überlappung mit der endgültigen Antwort hat. Die Schwelle ist bewusst konservativ - Wiki-Seiten, Archiv-Ergebnisse und sehr kurze Antworten werden immer behalten - aber sie beseitigt den Fehlermodus, in dem eine Antwort "keine weiteren Informationen" sagt, während sie "Quellen (5)" aus einem einzigen, marginal verwandten Dokument anzeigt. Der "keine Belege"-Hinweis wird gegen denselben gefilterten Satz bewertet, sodass Hinweis und Quellenliste immer dieselbe Realität beschreiben.

Die Stack-Auswahl und -Einstellung

Das Pipeline ist bewusst konfigurationsgetrieben, und die Defaults sind die datenschutzfreundlichen:

  • Vektorspeicher: LanceDB standardmäßig - dateibasiert, lokal gespeichert, kein externer Dienst erforderlich, vollständig air-gap-kompatibel. Qdrant, pgvector und Chroma sind eine Umgebungsänderung entfernt, wenn ein Deployment ihn überwächst; der Provider wird beim Boot ausgewählt.
  • Embeddings: lokale Transformer (384 Dimensionen, vollständig offline) standardmäßig, oder OpenAI-Embeddings, wenn ein Deployment den ausgehenden Aufruf akzeptiert. Der Wechsel des Embedding-Modells erfordert einen Re-Index, den das Admin-Panel steuert; der Abweichungs-Guard hält das System in der Zwischenzeit sicher.
  • Reranking: optional. Ein Reranker kann die fusionierten Ergebnisse überabrufen und neu ordnen, wenn Antwortqualität wichtiger ist als Latenz.
  • Fusionskonstante: k = 60 wird als Standard ausgeliefert; es ist eine einzelne Konstante im Hybrid-Suchdienst, wenn Ihre Rangverteilungen eine andere Dämpfung erfordern.

Der vollständige Datenfluss-Walkthrough - die Server-Collector-Grenze, das Speicherlayout hinter jedem Vektorprovider und die Streaming-Zitatereignisse - ist im Architektur-Leitfaden dokumentiert.

Lesen Sie den vollständigen Leitfaden in der Doku →

Ähnliche Artikel