Warum ich Vektorsuche für mein Wiki verworfen habe
Vektorsuche ist der Default für RAG – aber für mein persönliches Wiki war strukturiertes Retrieval über Metadaten und Volltext die bessere Wahl. Wo Embeddings scheitern, mit SQL- und Prompt-Beispielen.

Als ich mein LLM-Wiki nach Karpathy gebaut habe, war der reflexartige erste Schritt: Embeddings rein, Vektor-DB dazu, fertig ist das RAG. Ein paar Wochen später habe ich die Vektorsuche wieder rausgeworfen. Nicht aus Prinzip – sondern weil sie für diese Wissensbasis die schlechtere Wahl war. Hier warum.
Was Vektorsuche eigentlich tut
Vektorsuche bettet Text in hochdimensionale Vektoren ein und findet per Kosinus- Ähnlichkeit die „semantisch nächsten“ Chunks. Das ist mächtig für unstrukturierte, fuzzy Anfragen über riesige, uneinheitliche Korpora. Ein gepflegtes persönliches Wiki ist aber genau das Gegenteil: strukturiert, kuratiert, mit Metadaten.
Wo es bei mir konkret scheiterte
1. Chunking zerstört Struktur. Ein Wiki-Eintrag hat Titel, Tags, Datum, Beziehungen. Zerhackt in 512-Token-Fenster bleibt davon Textbrei. Die Grenze zwischen zwei Themen landet mitten im Chunk.
2. Kosinus-Nähe ≠ Relevanz. „Wie deploye ich X?“ holt begeistert jeden Absatz, der oft „deploy“ sagt – auch das veraltete von vor einem Jahr. Semantische Nähe kennt kein „aktuell“ und kein „autoritativ“.
3. Exakte Lookups gehen unter. „Zeig mir Eintrag cbks-arch vom März.“ Das ist kein Ähnlichkeitsproblem, das ist eine WHERE-Klausel. Embeddings machen daraus eine Ratepartie.
4. Kein sauberes Filtern. „Nur Tag=infra, nur letztes Quartal“ – in reiner Vektorsuche umständlich, in SQL ein Einzeiler.
Was ich stattdessen mache: strukturiertes Retrieval
Mein Wiki liegt ohnehin in PostgreSQL. Also nutze ich, was schon da ist – Metadaten-Filter plus Volltext (BM25-artig) statt Embeddings:
-- Kandidaten gezielt über Struktur + Volltext, nicht über Kosinus-Raten
SELECT id, title, tags, updated_at,
ts_rank(search_vector, query) AS rank
FROM wiki_entries,
plainto_tsquery('german', 'deployment fly.io') AS query
WHERE search_vector @@ query
AND 'infra' = ANY(tags) -- Metadaten-Filter
AND updated_at > now() - interval '180 days' -- nur aktuelles Wissen
ORDER BY rank DESC
LIMIT 5;Das liefert präzise, filterbare, frische Treffer – und, ganz nebenbei, die strukturierten Metadaten gleich mit. Genau das Rohmaterial, das ich dann als kompakten Kontext ins Modell reiche (das Prinzip aus dem Context-Engineering-Post):
// Aus den Treffern einen kompakten, budgetierten Kontext bauen
const context = rows.map((r) => `## ${r.title} [${r.tags.join(', ')}] (${r.updated_at})\n${r.snippet}`).join('\n\n');
const prompt = `<instructions>
Antworte nur anhand von <kontext>. Nenne den Eintrag-Titel als Quelle.
Fehlt die Info, sage das.
</instructions>
<kontext>
${context}
</kontext>
<frage>${userQuery}</frage>`;Wann Vektorsuche trotzdem gewinnt
Das ist kein „Embeddings sind schlecht“. Sie sind die richtige Wahl, wenn:
- der Korpus groß und unstrukturiert ist (tausende PDFs ohne Metadaten),
- Anfragen rein semantisch sind („finde alles, was thematisch ähnlich ist“),
- es keine verlässlichen Metadaten zum Filtern gibt.
Für ein kuratiertes Wiki trifft nichts davon zu. Die pragmatische Mitte ist oft hybrid: strukturiert vorfiltern, dann innerhalb der Treffer semantisch ranken. Aber der teure Vektor-Layer als erster Schritt war bei mir schlicht die falsche Reihenfolge.
Fazit
Vektorsuche ist ein Default, kein Naturgesetz. Bevor man Embeddings, eine Vektor-DB und Chunking-Pipelines aufsetzt, lohnt die Frage: Ist mein Wissen schon strukturiert? Wenn ja, ist die langweilige Antwort – WHERE, ts_rank, Metadaten – oft präziser, billiger und leichter zu debuggen als jeder Embedding-Stack.