Sie sind wegen RAG hier? Dann laden Sie doch unseren kostenlosen RAG-Primer herunter.
Die Aufgabe
In unserem Projekt geht es darum, eine Fachbibliothek von über 33000 Seiten aus 3900 PDF-Dokumenten in einem AI-Assistenten zugänglich zu machen. Bei solchen Mengen muss man RAG betreiben, es geht nicht anders. Man soll fachliche Fragen stellen können und auf ein bis zwei Bildschirmseiten eine detaillierte Ausarbeitung erhalten in akzeptabler Zeit. Seitengenaue Referenzen zu den PDFs öffnen das Dokument zum Nachschlagen.
Blitzeinführung Vektorsuche
Für jede Seite berechnen wir einen Embedding-Vektor mit einem Embedding-Modell[1] und stecken ihn in einen speziellen Datenbank-Index (Vektor-Index). Der Vektor besteht in unserem Fall[2] aus 1536 Fließkommazahlen und repräsentiert die semantische Bedeutung der Seite in 1536 Dimensionen. Das sprengt jede Intuition, aber mit diesem mathematischen Konstrukt können wir Texte semantisch vergleichen, indem wir die Ähnlichkeit ihrer Vektoren berechnen [3]. Theoretisch ergibt sich ein Wert zwischen -1 (das Gegenteil) und 1 (100% identisch), praktisch jedoch meist zwischen 0.5 und 0.87.
Unsere Embeddings kodieren die ganze Welt in nur 1536 Dimensionen! Das muss man kurz sacken lassen. Aus dieser Tatsache erkennt der gesunde Menschenverstand, dass hier natürliche Grenzen gesetzt sein müssen.
Wenn jetzt jemand dem Assistent eine Frage stellt, wird sie in einen Vektor umgewandelt und wir suchen in dem Vektor-Index nach den am ähnlichsten Seiten, um sie später dem Large Language Model (der AI) zur Auswertung zu geben. Man spricht auch von semantischer Suche. Es wird nicht nach Begriffen gesucht, sondern nach Bedeutung.
Erstes Problem: Die Nadel im Heuhaufen
Wenn jemand zum Beispiel nach einem ganz bestimmten Gerichtsurteil in den Dokumenten sucht mit der Frage “Was sind die Inhalte des BGH, Entscheidung vom 12.01.2001 V ZR 420/99”, wird die Vektorsuche versagen. Sie kann in 1536 Dimensionen nicht ein solches Detail aus 33000 Seiten punktgenau kodieren. Sie wird alles aufgreifen, was irgendwie mit Gerichtsurteilen zu tun hat, also semantisch in der Nähe ist. Das reicht uns nicht. Wir wollen präzise die Seite wissen, wo es steht.
Lösung: Volltextsuche
Volltextsuche ist ein gelöstes Problem und es gibt seit Jahren bewährte Implementierungen, wie z.B. Lucene. Wenn man die oben genannte Frage als Ganzes in die Volltextsuche gibt, wird zielgenau mit einem sehr hohen Score (Bewertung der Relevanz des Ergebnisses) die Seite gefunden, wo das Gerichtsurteil erwähnt wird.
Eine Volltextsuche hat wiederum Schwierigkeiten damit, eine sinngemäß ähnliche Formulierung mit anderen Worten zu finden. Wenn man mit der Volltextsuche gar keine Treffer bekommt, ist allerdings klar anzunehmen, dass die Frage nicht zum Thema passt.
Zweites Problem: Die Performance
Darüber scheint überhaupt niemand zu reden und in den Spielzeugbeispielen ist Performance sowieso kein Thema.
Wir benutzen MongoDB Atlas, weil es Vektorsuche und Lucene-Volltextsuche integriert hat und alles andere kann, was man von einer Datenbank erwartet. Alles unter einem Dach zu haben erleichtert das Design einer RAG-Anwendung erheblich.
Auf einem M10 Cluster dauert die Vektorsuche über 33000 Seiten ca. 3 Sekunden. Lucene gönnt sich nur ca. 0.3 Sekunden. Man hat in der Vektorsuche einen Parameter, der die Anzahl der Kandidaten einschränkt. Anders ausgedrückt kann die Breite der Suche eingestellt werden. Dieser Parameter hat erheblichen Einfluss auf die Laufzeit.
Eine weitere relevante Größe ist übrigens die Länge der Vektoren. Wir experimentierten mit Vektoren der doppelten Größe, in der Hoffnung, genauere Suchergebnisse zu bekommen. Das traf leider nicht ein, aber dafür dauerte alles doppelt so lange.
Das Dilemma
Wir stecken in einem Dilemma. Es gibt auch abstraktere Fragen, die keine Suche nach der Nadel im Heuhaufen sind, sondern eine breite Suche erfordern, um die besten Quellen zu finden. Man kann sich bei der Vektorsuche in einer interaktiven Anwendung jedoch nicht beliebig viel Gründlichkeit leisten [4]. Den Fragen ist es schwer anzusehen[5], ob sie eine breite oder schmale Suche brauchen, und eine Optimierung der Parameter, abhängig von der Frage, ist schwierig.
Lösung: Hybride Suche
Die Kombination aus Volltextsuche und Vektorsuche ermöglicht es, die Schwächen auszugleichen und die Stärken zu ergänzen. Die Textsuche wird zur führenden Suche, weil wenn hier überhaupt nichts passt, sparen wir uns die Vektorsuche. Die Vektorsuche ergänzt mit moderat eingestellter Suchbreite die Textsuche.
Die Ergebnisse der Suchen werden mit Reciprocal Rank Fusion[6] zusammengemischt und davon die besten K (topK)[7] Seiten zum LLM gegeben.
Fazit
RAG würde sowohl alleine mit Volltextsuche als auch mit Vektorsuche grundsätzlich funktionieren, aber die Ergebnisse wären deutlich schlechter als mit hybrider Suche, die viel besser unterschiedliche Fragen abdeckt.
Das Retrieval in RAG ist ein fein ausbalancierter Kompromiss, der auf den Verwendungszweck abgestimmt wird. Für einen interaktiven Assistenten gelten andere Regeln als für ein System, das im Hintergrund arbeitet und nach quasi beliebig langer Zeit ein Ergebnis berechnet.
Mein Ratschlag: Lassen Sie sich diesen wichtigen Teil von RAG nicht aus der Hand nehmen mit unflexiblen Standardmechanismen. Niemand kennt Ihre Daten, und welche Erkenntnisse Sie daraus gewinnen wollen, so gut wie Sie selbst. Fertige Implementierungen und Services werden es schwer haben, sich fein auf individuelle Gegebenheiten einzustellen.
Es geht immer weiter
Weil es zu RAG für große Dokumentensammlungen keine Alternative gibt, werde ich weiter mit der dynamischen Optimierung der hybriden Suche experimentieren. Bessere LLMs öffnen vielleicht mehr Möglichkeiten. Einige Ideen sind:
- An der Erkennung arbeiten, welche Art von Frage es ist und danach die Suchparameter einstellen. Bislang sind die Experimente dazu nicht zuverlässig gewesen.
- Die Vektorsuche breiter machen, wenn die Textsuche eher dünn war. Das könnte auf eine allgemeine Frage hindeuten.
- Das LLM alle Suchparameter entscheiden lassen.
-
Emdedding–Modelle sind ein Nebenprodukt von Language Models. Es gab sie schon vor der LLM–Ära. Sie werden mit Machine Learning berechnet. ↩
-
OpenAI text–embedding–3–small ↩
-
Mit dem Skalarprodukt (dot product) oder Cosinusähnlichkeit (cosine similarity) ↩
-
Das Contextual Retrieval von Anthropic zum Beispiel verdoppelt die Anzahl der Vektorsuchen. Kann man sich das wirklich immer leisten? Muss man die Breite der beiden Suchen dafür kleiner ansetzen und bringt das in Summe einen Fortschritt? ↩
-
“Anzusehen” im Sinne von berechenbar. ↩
-
Wie das funktioniert, können Sie leicht recherchieren oder in unserem RAG–Primer nachlesen. ↩
-
Top–20 Seiten funktioniert sehr gut. Dieser Parameter ist relevant für die Laufzeit des LLM. Das ist die einzige Stellschraube, die wir dafür haben. ↩