Jedes RAG-Tutorial endet bei denselben zwei Schritten: einbetten und abfragen. Sie zerlegen Ihre Dokumente in Chunks, speichern (id, embedding), starten eine Nearest-Neighbor-Suche, und die Demo funktioniert. Dann setzen Sie das System echten Nutzern vor, und es fällt still auseinander. Der Vektor war nie der schwierige Teil. Was Sie daneben speichern, schon. Ein produktives Retrieval-System über echte Dokumente trifft mindestens sieben Speicherentscheidungen, bevor es zuverlässig ist, und die Tutorial-Voreinstellung wählt bei den meisten stillschweigend die falsche Seite. Das hier ist die Checkliste: was neben die Embeddings gehört, und welcher Trade-off hinter jeder Entscheidung steckt.
Die unbequeme Wahrheit: „einbetten und abfragen“ ist kein Startpunkt, den Sie später verbessern. Es ist eine Entscheidung, von der Sie nicht wussten, dass Sie sie treffen. Sobald echte Skalierung, echte Berechtigungen und echte Compliance ins Spiel kommen, ändert sich alles.
1. Der Vektor allein ist nutzlos
Eine v1, die nur (id, embedding) speichert, findet Nearest Neighbors und liefert deren IDs zurück. Mehr nicht. Ein LLM kann keinen 768-dimensionalen Float-Vektor lesen. Es braucht den eigentlichen Text, um einen Prompt zu bauen, und Sie brauchen genug Kontext um diesen Text herum, um einem Nutzer die Herkunft einer Antwort zu zeigen, ein Dokument sauber zu löschen oder zwei Mandanten getrennt zu halten.
Der Datensatz, den ein produktives System speichert, sieht eher so aus:
chunk = {
„embedding“: embed(text),
„text“: text, # das LLM liest Text, keine Vektoren
„doc_id“: „arxiv2205.14135“, # ein ganzes Dokument auf einmal aktualisieren oder loeschen
„source_uri“: „https://…“, # dem Nutzer die Herkunft zeigen
„page“: 4,
„content_hash“: sha256(text), # unveraenderte Chunks nicht neu einbetten
„embed_model“: „bge-large-v1.5“, # Vektorraeume nie mischen
„visibility“: „public“, # wer das sehen darf
}
Jedes Feld verdient seinen Platz. doc_id ist wichtig, weil Dokumente überarbeitet und zurückgezogen werden. Ohne sie müssten Sie den gesamten Index durchsuchen, um alle Chunks eines Papers zu finden. content_hash löst ein Kostenproblem: Zehntausende Chunks erneut gegen eine kostenpflichtige API einzubetten kostet Geld und Zeit. Ein Hash prüft, ob sich ein Chunk überhaupt geändert hat, bevor Sie für die Neuberechnung zahlen. embed_model verhindert einen subtileren Fehler: Ein neueres Embedding-Modell verändert den Vektorraum komplett. Alte und neue Vektoren sind dann nicht mehr vergleichbar, selbst bei gleicher Dimension, und ein Mix verschlechtert jede Suche, ganz ohne Fehlermeldung. visibility sorgt dafür, dass ein einziger Index öffentliche und private Dokumente oder mehrere Mandanten bedient, ohne dass Sie einen zweiten aufsetzen.
Stellen Sie sich ein bloßes Embedding als Garderobenmarke vor, auf der nur eine Nummer steht. Die Nummer passt schnell und lügt nie, aber sie verrät nicht, wie der Mantel aussieht, wem er gehört oder ob er überhaupt ins Haus darf. Jedes Feld oben ist etwas, das auf die Marke geschrieben wird, damit Sie nach dem Treffer tatsächlich etwas Brauchbares in der Hand haben.
Hier steckt eine zweite Entscheidung. Kopieren Sie diese Metadaten in jeden Chunk, oder halten Sie sie einmal in einer separaten Tabelle? Kopieren bedeutet: Ein Lesezugriff verlässt den Chunk nie, keine Joins, keine zusätzlichen Roundtrips, was zählt, wenn Lesezugriffe die Schreibzugriffe weit übertreffen. Der Preis fällt an, sobald sich Metadaten ändern: Die visibility eines Dokuments umzustellen heißt, jeden zugehörigen Chunk zu aktualisieren, manchmal Tausende Zeilen. Halten Sie die Metadaten normalisiert an einer Stelle, dreht sich der Trade um. Updates werden zu einem einzigen Schreibvorgang, aber jeder Lesezugriff zahlt jetzt einen Join. Keine Variante ist im luftleeren Raum richtig. Die Antwort hängt davon ab, wie oft sich Ihre Metadaten ändern und wie oft Sie lesen.
2. Große Dateien gehören nicht in den heißen Pfad
Eine Binärdatei als Base64 zu kodieren bläht sie um rund ein Drittel auf. Diesen String direkt in einen Chunk-Datensatz zu legen bedeutet, dass jeder Lesezugriff — auch einer, der nur den Vektor für einen Ähnlichkeitsvergleich braucht — Kilobyte an Bilddaten mitladen muss, die er gar nicht benötigt. Im großen Maßstab bläht das den Speicherbedarf der In-Memory-Indexstrukturen auf und verlangsamt jede Abfrage, nicht nur die mit Bildbezug.
Speichern Sie stattdessen einen Pointer:
figure = {
„embedding“: clip_embed(image),
„caption“: „Figure 2: memory hierarchy“,
„modality“: „image“,
„media_uri“: „s3://blob/2205.14135/fig2.png“, # ein Pointer, nicht die Datei
}
Ein Vektorindex ist für schnelle, leichtgewichtige Lookups gebaut, nicht zum Herumschleppen schwerer Dateien. Ein ganzes Bild hineinzuzwängen ist, als schöben Sie ein Sofa durch einen Briefkastenschlitz: Es blockiert alles andere. Ein Pointer, während die Datei im Object Storage liegt, hält den Index für jede Abfrage schnell, und der große Blob wird nur geholt, wenn er wirklich gebraucht wird.
3. Wo Ähnlichkeitssuche strukturell nicht weiterhilft
Dense Embeddings sind eine starke und zugleich enge Voreinstellung. Drei verbreitete Abfragetypen hebeln sie komplett aus, und jeder braucht einen eigenen Index neben den Vektoren.
Verschiedene Modalitäten brauchen Rang-Fusion, keinen Score-Vergleich
Ein Modell wie CLIP legt ein Bild und seine Bildunterschrift nah beieinander in einem gemeinsamen Raum ab, was einen einzigen Index möglich macht. Sein Textverständnis ist aber schwächer als das eines reinen Textmodells, weil es beim Training zwischen zwei Modalitäten Kompromisse eingeht. Trennen Sie in Indizes pro Modalität, bekommen Sie für jeden Typ das beste Modell, aber ein Cosine-Score aus einem Textmodell und einer aus CLIP liegen nicht auf derselben Skala. Sie können beide Listen nicht per Rohwert sortieren. Reciprocal Rank Fusion umgeht das, indem es die Scores wegwirft und stattdessen über die Rangposition fusioniert:
def rrf(rank, c=60): return 1 / (c + rank)
Die Rangposition ist über Systeme hinweg vergleichbar, auch wenn es die Zahlen darunter nicht sind.
Beziehungen leben in einem Graphen, nicht in Wortüberschneidung
Fragen Sie „Was hat FlashAttention verbessert?“, scheitert reine Ähnlichkeitssuche. Ein Paper, das ein anderes verbessert, beschreibt meist einen anderen Mechanismus mit anderen Worten. Es teilt vielleicht ein, zwei Sätze Vokabular mit dem Original. Es antwortet auf dieses Paper, indem es zitiert, nicht indem es wiederholt. Ähnlichkeitssuche beurteilt Verwandtschaft über Vokabelvergleich, so wie man die Nähe zweier Wissenschaftler an gemeinsamen Wörtern misst. Zwei Rivalen, die seit einem Jahrzehnt streiten, klingen fast gleich, während ein Fremder mit ein paar geteilten Begriffen genauso nah wirkt. Ein Zitationsgraph ist der Stammbaum: Er liest nicht, was Leute sagen, er verfolgt, wer tatsächlich mit wem spricht. Speichern Sie Entitäten und Zitationskanten neben Ihren Chunks und rufen Sie in zwei Stufen ab. Die Vektorsuche findet Ausgangsdokumente, die Graphtraversierung geht einen Schritt weiter und bringt Paper zutage, die eine Ähnlichkeitssuche nie zurückgäbe.
Exakte Zeichenketten brauchen Keyword-Suche
Dense-Modelle zerlegen Text in Subword-Teile, und genau deshalb sind sie schlecht bei wörtlichen Treffern. „FlashAttention-2“ zerfällt vielleicht in ein Stück, das wie „FlashAttention“ aussieht, plus ein generisches Zahlentoken, sodass das Modell es als ungefähr „irgendwas mit FlashAttention“ darstellt statt als eigenständige Einheit. Dasselbe trifft arXiv-IDs, Produktcodes und Funktionsnamen. Ein Keyword-Index mit BM25 wertet exakte Token-Überschneidung, sodass ein wörtlicher Treffer auf „2205.14135“ hoch rankt, gerade weil er exakt ist. Betreiben Sie ihn neben dem Dense-Index und fusionieren Sie die Ergebnisse.
4. Die Entscheidungen, bei denen „falsch“ schlimmer ist als „langsam“
Die meisten Speicher-Trade-offs sind Geschwindigkeit gegen Kosten. Zwei sind anders: Trifft man sie falsch, ist das System nicht langsam, sondern falsch oder nicht regelkonform.
Berechtigungen während der Suche filtern, nie danach
Eine Vektordatenbank holt approximative Nearest Neighbors und wendet, nur auf Anfrage, danach einen Berechtigungsfilter auf das bereits Zurückgegebene an. Durchsuchen Sie die Top 8 ohne Kenntnis der Berechtigungen, können alle 8 legitim Dokumente sein, die der Nutzer nicht sehen darf. Ein Filter im Nachhinein liefert dann nichts, obwohl weiter unten in einer nie zurückgegebenen Liste reichlich öffentliche Treffer stehen. Ziehen Sie die Berechtigungsprüfung in die Suche hinein, betrachtet der Algorithmus nur Kandidaten, die der Nutzer sehen darf:
index.search(embed(q), k=8, filter={„visibility“: {„$in“: user_groups}})
Die meisten produktiven Vektordatenbanken bieten das als nativen Filter-Parameter. Es lohnt sich, das ausdrücklich zu prüfen, denn der Unterschied ist keine Performance-Feinheit. Er ist der Unterschied zwischen einem korrekten und einem leeren Ergebnis. Nachträgliches Filtern ist ein Club, der alle durch die Tür lässt und die Tickets erst drinnen kontrolliert: Bis dahin ist der Raum voller falscher Leute, und die geladenen Gäste stehen draußen. Vorfiltern ist der Türsteher an der Tür.
Löschen: für immer weg, oder als gelöscht markiert
Ein Hard Delete entfernt die Zeile und irgendwann ihren Vektor, was Sie bei Wegwerf- oder Cache-Daten wollen, aber es bleibt kein Nachweis, wenn später jemand fragt, warum etwas fehlt oder wer es entfernt hat. Ein Soft Delete setzt einen deleted_at-Zeitstempel und lässt die Zeile stehen, wodurch jede Abfrage einen zusätzlichen Filter trägt, um tote Daten nicht anzuzeigen — eine kleine, dauerhafte Steuer. Für alles, was Compliance, gesetzliche Aufbewahrungspflichten oder DSGVO-Löschkonzepte berührt, ist diese Steuer es wert. Für Logs, die niemand prüft, ist sie reiner Overhead.
5. Vier Schichten, ein Orchestrator: die Lücke vom PoC zur Produktion
Legt man die sieben Entscheidungen übereinander, zeigt sich ein Muster. Ein produktives Retrieval-System ist keine einzelne Suchbox, sondern vier zusammenspielende Schichten:
Query
|
Orchestrator (fusionieren + reranken)
|
Vektorschicht: Text- / Bild- / Keyword-Indizes + Berechtigungsfilter
|
Graphschicht: Entitaeten + Zitationen
|
Object Storage: Rohdateien, ueber Pointer
Keine davon ist jenseits einer Demo optional. Die Vektorschicht beantwortet „Was ist dem hier ähnlich“. Die Graphschicht beantwortet „Was ist mit dem hier verbunden“, was Ähnlichkeit strukturell nicht kann, egal wie gut das Embedding-Modell wird. Der Object Storage hält große Dateien aus dem heißen Pfad. Die eigentliche Aufgabe des Orchestrators ist die Entscheidung, pro Abfrage, welche Schichten zu befragen sind und wie das Zurückkommende zusammengeführt wird. Behandeln Sie das als eine Suchbox statt als vier Systeme, und genau hier bricht die Architektur mit wachsender Skalierung leise.
Das ist exakt die Lücke zwischen einer Retrieval-Demo und einem Retrieval-Produkt, und sie ist nicht auf RAG beschränkt. Hier bleiben die meisten KI-Projekte stecken. GoTeams vertritt eine bewusst enge Haltung zu KI: KI generiert schnell Code, aber LLMs liefern Snippets, keine Systeme, und MVPs, die allein mit KI gebaut sind, skalieren selten. Die Arbeit, die ein Notebook mit plausiblen Antworten von einem System mit korrekten, berechtigten, prüfbaren Antworten trennt, ist Orchestrierung, und Orchestrierung ist eine menschliche Disziplin, keine Modellfähigkeit.
Genau dafür ist ein KI-orchestriertes Entwicklungsteam gebaut. Zennify (KI und Kommunikation, 17-köpfiges Team) ist ein laufendes Beispiel: eine Contact-Center-Plattform, erweitert zu einem Framework für KI-Assistenten, mit LLM-Orchestrierung, Sprachdiensten und Twilio-Integration hinter über 200 Konfigurationsoptionen. Sie ist heute europäischer Marktführer und bedient Kunden wie Nestlé und FlixBus. Der Unterschied zu einem stecken gebliebenen Pilotprojekt war nie das Modell. Es waren die Schichten darum herum und das Team, das wusste, welche Entscheidungen zu treffen sind.
Häufig gestellte Fragen
Was speichert man in einem RAG-System neben den Embeddings?
Speichern Sie den Quelltext, nicht nur den Vektor, denn ein LLM liest Text und keinen Float-Vektor. Ergänzen Sie eine Dokument-ID, um ein ganzes Dokument auf einmal zu aktualisieren oder zu löschen, eine Source-URI, um Nutzern die Herkunft einer Antwort zu zeigen, einen Content-Hash, um unveränderte Chunks nicht neu einzubetten, den Namen des verwendeten Embedding-Modells und ein visibility-Feld für Berechtigungen. Der Vektor findet den Treffer. Alles, was daneben liegt, macht den Treffer brauchbar, korrekt und sicher auslieferbar.
Warum scheitert reine Ähnlichkeitssuche bei manchen Abfragen?
Dense Embeddings treffen auf semantische Ähnlichkeit, das falsche Werkzeug für drei Abfragetypen. Exakte Zeichenketten wie eine arXiv-ID oder ein Funktionsname werden in Subword-Teile zerlegt und verlieren ihre Identität — sie brauchen einen Keyword-Index mit BM25. Beziehungsfragen wie „Was hat X verbessert“ scheitern, weil die Antwort X zitiert statt seine Worte zu wiederholen — sie brauchen einen Zitationsgraphen. Und Scores verschiedener Embedding-Modelle sind nicht vergleichbar, multimodale Suche braucht daher Rang-Fusion statt Rohwert-Sortierung. Produktive Systeme betreiben diese Indizes gemeinsam und fusionieren die Ergebnisse.
Was ist der Unterschied zwischen Vor- und Nachfilterung in der Vektorsuche?
Vorfilterung wendet den Berechtigungsfilter innerhalb der Suche an, sodass der Algorithmus nur Kandidaten rankt, die der Nutzer sehen darf. Nachfilterung sucht zuerst und entfernt verbotene Treffer danach, was ein leeres Ergebnis liefern kann, obwohl weiter unten gültige Treffer stehen, weil die Suche nur eine kleine Top-k zurückgab, die zufällig komplett privat war. Für jedes System mit Berechtigungen oder mehreren Mandanten ist Vorfilterung keine Optimierung. Sie ist der Unterschied zwischen einem korrekten und einem falschen Ergebnis. Die meisten produktiven Vektordatenbanken bieten sie als Filter-Parameter.
Warum funktionieren so viele RAG-Systeme als Demo, aber nicht in Produktion?
Weil „einbetten und abfragen“ eine Entscheidung ist, keine Voreinstellung, und bei den meisten Produktions-Trade-offs still die falsche Seite wählt. Eine Demo hat keine Berechtigungen, keine Mandantentrennung, keine Compliance-Anforderung, keine Exact-Match- und keine Beziehungsabfragen, also wirkt ein bloßer Vektorindex ausreichend. Echter Betrieb bringt alle fünf auf einmal. Die Lösung ist kein besseres Modell. Es sind die vier Schichten aus Vektor, Graph, Object Storage und Orchestrator, plus die Disziplin, jeden Speicher-Trade-off bewusst zu entscheiden. An dieser Orchestrierung bleiben KI-Projekte am häufigsten hängen.
Wie entscheidet man, welcher RAG-Speicher-Trade-off richtig ist?
Es gibt keine allgemeingültig richtige Antwort, nur den Trade in die richtige Richtung für Ihr System. Jede Entscheidung hat dieselbe Form: jetzt Aufwand investieren, beim Schreiben oder bei der Ingestion, um später beim Abfragen zu sparen, oder umgekehrt. Content-Hashing gibt Speicher aus, um Rechenzeit zu sparen. Metadaten zu kopieren gibt Schreibkosten aus, um Leselatenz zu sparen. Ein Zitationsgraph gibt Ingestion-Komplexität aus, um Fragen zu beantworten, die Ähnlichkeit nicht kann. Messen Sie zuerst Ihr tatsächliches Lese-Schreib-Verhältnis, Ihre Abfragetypen und Ihre Compliance-Anforderungen. Ein Setup, das bei 1000:1 offensichtlich richtig ist, kann für ein ständig neu einlesendes System genauso offensichtlich falsch sein.
Das Fazit
Bauen Sie eine Wegwerf-Demo über eine Handvoll öffentlicher Dokumente, reicht einbetten und abfragen, und alles oben ist Overhead, den Sie noch nicht brauchen. Doch sobald echte Nutzer, echte Berechtigungen und echte Skalierung dazukommen, ist die Tutorial-Voreinstellung kein Startpunkt mehr, sondern eine Reihe stiller Entscheidungen, die gegen Sie arbeiten. Ein produktives Retrieval-System speichert weit mehr als Vektoren: Text, Identifikatoren, Hashes, Modellnamen, Berechtigungen, Pointer, Graphkanten und einen Keyword-Index — jede davon ein bewusst gewählter Trade. Kennen Sie Ihr Lese-Schreib-Verhältnis, Ihre Abfragetypen und Ihre Compliance-Anforderungen. Dann zahlen Sie in der Währung, die Sie sich leisten können.
Die Lücke zwischen einer Retrieval-Demo und einem Retrieval-Produkt ist Orchestrierung, und Orchestrierung ist eine menschliche Disziplin. Genau das liefert ein KI-orchestriertes Entwicklungsteam: Entwickler, die wissen, welche dieser Entscheidungen in welche Richtung zu treffen sind, für das System, das Sie tatsächlich bauen, und die es so ausliefern, dass es mit der Skalierung korrekt bleibt. Das ist der Unterschied zwischen einem Pilotprojekt, das beeindruckt, und einem Produkt, das bleibt.

Schreibe einen Kommentar