Lokales RAG ohne Vektoren: SQLite FTS5 und BM25 für die Codesuche
Warum dichte Vektorindizes Entwicklerrechner belasten und wie SQLite FTS5 mit BM25 schnellere, exakte Codesuche bei einem Bruchteil des Speichers liefert.
Ein paar Jahre lang war das Rezept für lokale Codesuche immer dasselbe: das Repository in Chunks zerlegen, jeden Chunk in ein Embedding mit 1536 Dimensionen verwandeln und einen HNSW-Index in einem Hintergrundprozess am Leben halten. Das wirkte modern, als hätte der Laptop eine kleine Suchmaschine bekommen, die versteht, was der Code bedeutet. Auf einer ausgelasteten Workstation hat dieses Rezept aber einen Preis, der selten in einer README auftaucht.
Die Schlagzeilen zur lokalen Vektorsuche sind beeindruckend: starke MTEB-Retrieval-Werte, Millionen Code-Tokens in Minuten eingebettet, "sofortige semantische Intelligenz" auf Consumer-Hardware. Wer statt des Marketings die Hinweise zum Speicher liest, sieht ein anderes Bild. Dichte Vektorindizierung erkauft ihren Recall mit Speicherbandbreite, RAM oder VRAM und mit Vorhersagbarkeit.
Wenn überall Vektoren auf die Speichergrenze treffen
Lässt man eine Vektordatenbank neben einem lokalen LLM, einer IDE und ein paar Docker-Containern laufen, ist sie nicht untätig. Sie hält große Graphstrukturen im RAM oder VRAM, konkurriert mit den anderen Werkzeugen um Bandbreite und bringt semantischen Drift mit: Man sucht nach dem exakten String ERR_AUTH_EXPIRED und bekommt Code zurück, der bloß irgendwie mit Authentifizierung zu tun hat.
Deshalb kehren viele Teams still zu nativen C-Algorithmen zurück, nämlich zu SQLite FTS5 mit BM25. Statt Vektormathematik für lokale Abfragen nutzen sie ein deterministisches Ranking nach Termhäufigkeit und finden exakte Bezeichner in unter 5 Millisekunden.
Begriffsabgleich gegen vorhersagbare Geschwindigkeit
Das ist mehr als eine kleine Anpassung. Es verändert, wie Entwicklerwerkzeuge gebaut werden. Wer den lokalen Vektor-Overhead gegen FTS5 tauscht, gibt den theoretischen Begriffsabgleich auf und bekommt dafür schlanke, schnelle Ausführung.
- Effizienz: Der Verzicht auf dichte Indizierung macht Gigabytes an Speicher frei. Arbeit, die rund 200 ms mit dem Berechnen von Embeddings verbrachte, ist nativ in unter 5 ms erledigt.
- Präzision: Abfragen nach exakten Schlüsselwörtern und Funktionsnamen wie
getUserById()sind vollständig deterministisch, der Index liefert also keine fremden Funktionsrümpfe.
Die beiden Abläufe im Vergleich:
[Dense Vector RAG Flow]
Code Query -> Generate Vector Embeddings -> HNSW Index Search -> Semantic Drift Risk -> LLM Context
[Deterministic BM25 Flow]
Code Query -> Native SQLite C-Index -> Exact Keyword Match (5ms) -> Minimal LLM Context
Symptome, die Sie vielleicht schon kennen
Wer lokale Agenten oder Codesuche betreibt, hat die Reibung vermutlich schon bemerkt:
- Ressourcenkonkurrenz. Der Lüfter dreht hoch, der Akku hält zwei Stunden, und die lokale Inferenz kriecht, weil eine Engine im Hintergrund um Speicher kämpft.
- Die Strafe für exakte Treffer. Die Suche nach einem bestimmten Fehlerstring oder einer Variable liefert fünf Dateien, die inhaltlich in der Nähe der Authentifizierung liegen, aber nicht die eine Datei, die das eigentliche Flag enthält.
Eine Gegenüberstellung mit groben Zahlen:
| Dimension | Lokale Vektor-DB (Chroma, Qdrant) | SQLite FTS5 (BM25) |
|---|---|---|
| Speicherbedarf | Etwa 1,5 bis 4 GB RAM oder VRAM | Etwa 15 bis 30 MB RAM |
| Suchlatenz | 120 bis 400 ms, größtenteils für Embeddings | Unter 5 ms, natives C |
| Exakter Abgleich von Bezeichnern | Schwach, anfällig für Drift | Stark, deterministischer Schlüsselwortabgleich |
| System-Overhead | Hintergrunddienste, C++-Bindings | Im Leerlauf läuft nichts |
| Am besten für | Breite, thematische Suchen in Fließtext | Präzise Abfragen in Code, Logs und lokalem RAG |
Das sind Richtwerte, denn die Ergebnisse hängen von Korpusgröße, Modellwahl und Hardware ab.
Was das für Engineering-Leads bedeutet
Der Reflex, an jedes lokale Problem eine Vektordatenbank zu hängen, lässt nach. Nützlicher ist ein Sinn für Verhältnismäßigkeit. Die Kunst eines erfahrenen Architekten besteht nicht darin, immer schwerere KI-Infrastruktur auf Entwickler-Laptops zu packen. Sie besteht darin zu erkennen, wann zehn Zeilen nativer Code oder eine 30 MB große SQLite-Datei eine neuronale Pipeline im Gigabyte-Bereich schlagen.
Wenn die Werkzeuge schneller und die Abläufe schlanker werden, gewinnen nicht die Stacks mit den größten Modellen. Gewinnen werden die, die sauberen Code ohne Ballast ausliefern. Embeddings werden dadurch nicht nutzlos: Für unscharfe, begriffliche Fragen über Fließtext haben sie weiter ihren Platz. Um aber einen exakten Bezeichner in einer Codebasis zu finden, beginnen Sie mit dem günstigen deterministischen Werkzeug und ergänzen Vektoren nur dort, wo es versagt.