Jenseits der Kosinus-Ähnlichkeit: Vergleich von fünf RAG-Suchtechniken
Kosinus, BM25, hybrider RRF, Cross-Encoder-Reranking und MMR – erläutert mit Code, Abwägungen sowie einem auf die Anfrage ausgerichteten Ansatz zur Entscheidung, welche Suchtechnik Ihr RAG benötigt.
Quellen: **Beyond Cosine Similarity: The 5 RAG Retrieval Techniques That Actually Move the Needle**
Zwei Sätze, „Die Katze saß auf dem Teppich“ und „Ein Kater ruhte sich auf der Matte aus“, teilen überhaupt keine Wörter, doch ein Embedding-Modell bewertet sie mit etwa 0,85. So erlangt die Kosinusähnlichkeit ihren Ruf – und genau hier enden auch die meisten RAG-Tutorials: Kosinus zeigen, einen Auszug einfügen und weitermachen.
collection.query(query_embeddings=embedding, n_results=5)
Diese Methode funktioniert. Sie ist außerdem nur eine von fünf Suchtechniken, wobei jede für einen anderen Problemtyp entwickelt wurde. Wenn man sich ausschließlich auf den Kosinus verlässt, versagen ganze Kategorien von Abfragen stillschweigend ohne Fehlermeldung, und die Nutzer erhalten einfach falsche Antworten. Hier wird erklärt, was der Kosinus tatsächlich misst, wo er versagt, sowie die vier anderen Techniken und eine Methode, um zu entscheiden, welche man anwenden soll.
Was der Kosinus misst
Ein Embedding-Modell wandelt Text in einen Vektor um, also eine Liste aus Hunderten oder Tausenden von Zahlen. Texte, die ähnliche Bedeutungen haben, ergeben Vektoren, die in dieselbe Richtung zeigen. Die Kosinusähnlichkeit vergleicht den Winkel zwischen zwei Vektoren statt deren räumliche Entfernung.
Das ist der entscheidende Punkt. Ein einzeiliger Satz und ein vollständiger Absatz können dieselbe Bedeutung haben. Wenn ihre Vektoren in dieselbe Richtung zeigen, gibt der Kosinus eine hohe Wertung an. Die Länge, die als Betrag angegeben wird, stellt Rauschen dar, während die Richtung die Bedeutung ausmacht.
Typische Ergebnisse sehen so aus:
| Paar | Ergebnis |
|---|---|
| "Die Katze saß auf der Matte" und "Ein Katzenartiger ruhte auf dem Teppich" | 0.85 |
| "Wie funktioniert Aufmerksamkeit?" und ">Erklären Sie das Transformer-Prinzip" | 0.79 |
| "Die Programmiersprache Python" und ">Python, die Schlangenart" | 0.38 |
| ">Ich liebe Morgenkaffee" und ">Die Theorie der Quantenverschränkung" | 0.03 |
Die erste Zeile zeigt, warum Kosinus beeindruckend ist: Es gibt keine gemeinsamen Wörter, doch das Ergebnis liegt bei 0,85. Das Modell hat gelernt, dass „Katze“ und „Katzenartiger“ in benachbarten Bereichen des semantischen Raums liegen, und Kosinus erkennt das ohne jegliche Schlüsselwortübereinstimmung.
Warum nicht die euklidische Distanz
Die offensichtliche Alternative ist die euklidische Distanz – buchstäblich die Entfernung zwischen zwei Vektoren. Das Problem: Wenn man ein Dokument zehn Mal wiederholt, wird sein Vektor zehnmal größer, sodass er vom Original weit entfernt erscheint, obwohl sich die Bedeutung nicht geändert hat. Der Kosinus ignoriert das – nur die Richtung zählt.
Eine Warnung bezüglich der Scores
Kosinus-Scores sind nicht universell. Ein Wert von 0,7 aus all-MiniLM-L6-v2 signalisiert etwas anderes als ein Wert von 0,7 aus text-embedding-3-large, denn jedes Modell verfügt über seinen eigenen Embedding-Raum mit seiner eigenen Dichte. Kalibrieren Sie die Schwellenwerte für die Scores an Ihrem eigenen Bewertungssatz und kopieren Sie keine Werte aus einem Tutorial, das ein anderes Modell verwendet hat.
Eine Festival-Analogie für Nicht-Ingenieure
Vor dem Code ein mentales Modell der fünf Techniken. Sie befinden sich auf einem Musikfestival und suchen dort in der Menge nach einem Freund – mit drei verfügbaren Strategien.
- Nach Richtung (Kosinus). Ihr einigt euch beide darauf, dem Podium zuzuwenden. Derselbe Richtung bedeutet dieselbe Person – egal wie weit ihr voneinander entfernt steht. Der Winkel, in den Sie zeigen, ist wichtig, die Entfernung zwischen Ihnen nicht.
- Durch Namensschilder (Schlüsselwortsuche, BM25). Sie rufen „Ist jemand namens Alex da?“. Dies funktioniert perfekt, wenn das Namensschild exakt übereinstimmt, ignoriert aber alle Personen mit Namen wie Alexis, Al oder Sandy, die dieselbe Person unter einem anderen Namen sind.
- Durch Gesicht und Namensschild (Hybrid). Sie überprüfen beides. Wer bei beiden Kriterien übereinstimmt, rückt an die Spitze, und wer nur bei einem Kriterium übereinstimmt, wird dennoch bemerkt. So wird die breiteste Abdeckung erreicht.
Die Lektion, die die meisten Anleitungen verschweigen: Keine einzige Methode findet alle Personen. Die von Ihnen gewählte Technik bestimmt, welche Antworten sowie welche Personen Sie dauerhaft übersehen werden.
Fünf Techniken, nacheinander
1. Kosinusähnlichkeit, die Standardmethode
Was sie leistet. Sie vergleicht die semantische Richtung der Abfragen- und Dokumentvektoren.
Wann sie verwendet werden sollte. Bei Abfragen in natürlicher Sprache, wenn keine exakten Begriffe erforderlich sind: allgemeiner RAG, Fragebeantwortung anhand von Dokumenten, alles, bei dem viel Paraphrasierung stattfindet.
Wo sie versagt. Bei wörtlichen Zeichenfolgen. Ein Produktnummer, eine Rechnungsnummer oder ein Personenname, der kaum in den Trainingsdaten vorkommt, kann dazu führen, dass die Kosinusähnlichkeit völlig versagt. Die Vektoren für „GPT-4o“ und „GPT-4“ können so nah beieinander liegen, dass nur Rauschen statt Signal entsteht.
In Code:
collection.query(
query_embeddings=query_embedding,
n_results=5
)
Kompromiss. Die Bedeutung hat Vorrang vor der genauen Formulierung. Es ist schnell, recht genau und erfordert keine zusätzliche Einrichtung.
2. BM25-Suchfunktion nach Schlüsselwörtern – das Präzisionswerkzeug
Was es tut. Es bewertet Dokumente danach, wie oft Suchbegriffe darin vorkommen, wobei dieser Wert durch die Häufigkeit dieser Wörter im gesamten Korpus abgemildert wird. Es verwendet keine Embeddings, nur Zählungen.
Wann man es verwenden sollte. Wenn die Suche von einem exakten Identifikator abhängt, der Zeichen für Zeichen übereinstimmen muss – wie beispielsweise eine Rechnungsnummer, ein Modellname mit Erscheinungsdatum oder eine CVE-Referenz.
Was es übersieht. Jeden Sinn für Bedeutung. „Feline“ stimmt nicht mit Dokumenten überein, in denen „Katze“ steht. Synonyme und Paraphrasen sind für dieses Werkzeug unsichtbar.
Ein aussagekräftiges Ergebnis. In einem kleinen Projekt von Grund auf erhöhte die Verwendung von BM25 neben Cosine die Trefferquote von 0,25 auf 0,75. Der Grund dafür war, dass die tatsächlichen Suchanfragen genaue Produktnamen enthielten, die Cosine in nahezu ähnliche Ergebnisse verwischte, anstatt direkte Treffer zu liefern. Betrachten Sie dies als einen einzelnen Datensatz, nicht als allgemeingültige Zahl.
Kompromiss. Präzision bei exakten Treffern auf Kosten einer vollständigen semantischen Generalisierung.
3. Hybrides Suchverfahren – die Standardlösung in der Praxis
Wie es funktioniert. Cosine und BM25 werden nebeneinander ausgeführt, und die beiden sortierten Ergebnislisten werden mithilfe von Reciprocal Rank Fusion (RRF) zusammengeführt. Keine der Methoden allein deckt alle Arten von Suchanfragen ab.
Wann verwenden Sie es? Abfragen kombinieren Natursprache mit spezifischen Begriffen, was nahezu jedes Produktionsystem beschreibt. Ein Benutzer, der fragt „Wie sieht die Rückerstattungspolitik für Bestellung #8821 aus?“, verwendet sowohl einen semantischen Begriff (Rückerstattungspolitik) als auch eine exakte Übereinstimmung (#8821).
Der Fusionsschritt. Jede Technik liefert ihre eigene gerankte Liste. RRF vergibt jedem Dokument eine Punktzahl, die sich aus seiner Position in jeder Liste berechnet – 1 geteilt durch (k plus Rang), wobei k eine Konstante ist, meist 60 – und fügt anschließend die Punktzahlen aller Techniken zusammen. Dokumente, die in beiden Listen hoch gerankt sind, rücken an die Spitze.
# Pseudocode for RRF merge
def rrf_score(rank, k=60):
return 1 / (k + rank)
def merge_results(cosine_results, bm25_results):
scores = {}
for rank, doc in enumerate(cosine_results):
scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
for rank, doc in enumerate(bm25_results):
scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
Auf AWS unterstützt OpenSearch dies nativ: Man konfiguriert eine hybride Abfrage mit einem Gewichtsparameter, und das System kümmert sich intern um die Fusion.
Kompromiss. Die beste Gesamtrekall-Rate, allerdings zu etwa doppelt so hohen Suchkosten – was in der Regel gerechtfertigt ist.
4. Neubewertung mit einem Cross-Encoder
Funktion. Ein zweistufiger Ansatz. In der ersten Stufe werden die 20 besten Kandidaten über kosinusbasierte oder hybride Suche ermittelt. In der zweiten Stufe werden jeder Kandidat zusammen mit der Abfrage in einen Cross-Encoder eingegeben, der die Relevanz durch gleichzeitige Betrachtung beider Elemente bewertet.
Wann man ihn verwendet. Wenn die besten Ergebnisse relevant sind, aber in der falschen Reihenfolge liegen und Präzision wichtiger ist als Latenz. Er gehört in die zweite Stufe und niemals in den ersten Durchlauf.
Warum zwei Phasen? Ein Cross-Encoder beurteilt die Relevanz weitaus besser als Cosine, doch man kann ihn nicht auf eine ganze Datenbank anwenden. Zwanzig Modellaufrufe anstelle von einem sind akzeptabel – zehntausend zum Zeitpunkt der Abfrage hingegen nicht.
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')# Stage 1: retrieve candidates
candidates = collection.query(query_embeddings=embedding, n_results=20)# Stage 2: rerank
pairs = [(query, chunk) for chunk in candidates['documents'][0]]
scores = reranker.predict(pairs)
top_5 = sorted(zip(scores, candidates['documents'][0]), reverse=True)[:5]
Eine ernste Warnung. Verwenden Sie Reranking nicht als erste Schrittweise. Die Latenzkosten sind hoch, da man einen Embedding-Aufruf durch zwanzig vollständige Modellberechnungen ersetzt.
Kompromiss. Höchste Präzision, aber auch höchste Kosten – daher sollte es nur in einer zweiten Phase eingesetzt werden.
5. Maximal marginal relevance (MMR) für Vielfalt
Was es bewirkt. Es findet einen Kompromiss zwischen der Ähnlichkeit zur Anfrage und der Übereinstimmung mit bereits ausgewählten Teilen. Jeder neue Auswahl muss relevant sein und sich von dem Unterschieden, was bereits ausgewählt wurde.
Wann es verwendet werden sollte. Wenn alle oberen Ergebnisse dasselbe besagen, beispielsweise bei einer allgemeinen Zusammenfassungsfrage, bei der jedes Ergebnis nur eine Tatsache wiederholt.
Die Lambda-Einstellung.
lambda = 1.0bedeutet reine Relevanz, genauso wie bei dem Standard-Cosinus-Verfahren.
lambda = 0.0 bedeutet reine Vielfalt, wobei die Relevanz völlig ignoriert wirdlambda = 0.5 ist ein ausgewogener Ausgangspunkt, von dem aus angepasst werden kanndef mmr_select(query_embedding, candidates, lambda_param=0.5, k=5):
selected = []
remaining = list(candidates)
while len(selected) < k and remaining:
mmr_scores = []
for doc in remaining:
relevance = cosine_similarity(query_embedding, doc.embedding)
if selected:
redundancy = max(cosine_similarity(doc.embedding, s.embedding)
for s in selected)
else:
redundancy = 0
mmr_scores.append(lambda_param * relevance - (1 - lambda_param) * redundancy)
best = remaining[mmr_scores.index(max(mmr_scores))]
selected.append(best)
remaining.remove(best)
return selected
Wo es hervorsticht. Zusammenfassungen, Forschungsfragen sowie alle Fälle, in denen der Leser eine umfassende Darstellung verschiedener Ideen statt einer tiefgehenden Behandlung eines Themas wünscht.
Kompromiss. Es beseitigt Redundanzen, doch Lambda muss angepasst werden.
Auswahl: Lassen Sie Ihre Abfragen entscheiden
Bevor Sie eine Technik wählen, untersuchen Sie 20 echte Abfragen von Ihren tatsächlichen Nutzern oder aus Ihrem Bereich. Hypothetische Abfragen zählen nicht.
- 80 % oder mehr sind reine Natursprache. Cosine ist Ihre Standardmethode. Beginnen Sie damit, da sie schnell und präzise ist und keine zusätzliche Infrastruktur erfordert.
- 30 % oder mehr enthalten genaue Begriffe, Codes, IDs oder Eigennamen. Fügen Sie BM25 hinzu. Sobald dieses Muster erkennbar wird, wird die hybride Suche zur Standardlösung – implementieren Sie daher eine RRF-Fusion. Der Gewinn an Trefferquote ist in der Regel schnell und erheblich.
Was Schulungen weglassen
Techniken können sich gegenseitig beeinträchtigen, anstatt sich zu ergänzen. In einem Experiment schien es eine sichere Lösung zu sein, die hybride Abfragemethode durch die Erweiterung der Abfrage – bei der mehrere Varianten der Abfrage erzeugt und für jede einzeln gesucht wird – zu ergänzen. Mehr Abfragemöglichkeiten sollten doch bessere Ergebnisse liefern. Doch die Bewertungswerte sanken von 0,807 auf 0,702. Mehr Abfrissignale verstärken sowohl das Signal als auch den Rausch, und die zusätzlichen Varianten holten benachbarte, aber falsche Datenblöcke heran. Die hybride Abfragemethode funktionierte bereits gut, und die Erweiterung fügte nur Störungen hinzu. Fügen Sie jeweils nur eine Technik hinzu, messen Sie jede für sich, bevor Sie sie kombinieren, und denken Sie daran, dass die Reihenfolge wichtig ist – denn das, was für sich genommen nützlich ist, kann in Kombination schädlich sein.
Das Skalarprodukt ist nicht Kosinus. Einige Vektordatenbanken verwenden standardmäßig das Skalarprodukt. Beide Methoden stimmen nur dann überein, wenn die Vektoren einheitlich normalisiert sind. Wenn Ihr Embedding-Modell seine Ausgabe nicht normalisiert, können die Skalarprodukt-Werte nicht zwischen verschiedenen Abfragen verglichen werden – daher bedeuten 0,9 für eine Abfrage und 0,9 für eine andere etwas anderes. Überprüfen Sie, was Ihre Datenbank tatsächlich berechnet. ChromaDB wird beispielsweise im Allgemeinen als verwendet beschrieben, die eine andere Standardmetrik als Qdrant hat; überprüfen Sie daher beide in der aktuellen Dokumentation.
Die Abfragen bestimmen die Technik, nicht die Dokumente. Ingenieure verbringen oft Zeit damit, ihr Korpus als technisch oder konversationell, lang oder kurz einzuordnen. Das ist wichtig für das Chunking. Bei der Auswahl einer Suchtechnik spielt die Analyse der Abfragen weitaus größere Rolle. Ein technisches Korpus, das mit Fragen in natürlicher Sprache durchsucht wird, stellt ein Kosinus-Problem dar, während derselbe Korpus, der nach Teilenummern durchsucht wird, ein hybrides Problem darstellt.
Der gesamte Prozessablauf
So sieht das schichtweise Design aus, wie es viele produktive RAG-Systeme letztendlich aufweisen:
User Query
↓
[Optional: HyDE — if query is vague]
↓
Stage 1 Retrieval: Hybrid (Cosine + BM25 → RRF merge)
→ Top 20 candidates
↓
[Optional: Cross-encoder reranking — if precision matters]
→ Top 5 candidates
↓
[Optional: MMR — if results are redundant]
→ Final k candidates
↓
LLM Context Assembly + Generation
Nicht jedes System benötigt alle Schichten. Beginnen Sie mit Kosinus, fügen Sie einen hybriden Ansatz hinzu, wenn es zu Fehlern bei exakten Übereinstimmungen kommt, fügen Sie eine Neubewertung der Ergebnisse hinzu, wenn die Reihenfolge falsch ist, und fügen Sie MMR hinzu, wenn sich die Ergebnisse wiederholen. Messen Sie bei jedem Schritt, denn was einem System hilft, kann einem anderen schaden.
Die wichtige Zahl
Berichte aus Suchexperimenten zeigen oft eine Lücke in der Erinnerungsrate zwischen reinem Kosinus-Verfahren und hybrider Suche bei gemischten Abfragesätzen – bei einem kleinen Projekt stieg diese von 0,25 auf 0,75. Wenn das auch nur ungefähr für Ihre Daten gilt, bedeutet das, dass etwa dreimal so viele richtige Antworten das Sprachmodell erreichen, bevor es ein Wort schreibt – ohne Prompt-Engineering, ohne Modulupdate und ohne Infrastrukturumstellung. Es kommt darauf an, die Wahl der Suchmethode gut zu treffen.