Das Problem: Die Token-Bombe

Ich experimentiere aktuell viel mit OpenClaw – einem lokalen KI-Agenten namens “Ryan”, der auf meinem VPS läuft. Er ist über Telegram angebunden, hat Zugriff auf SSH und n8n-Workflows. Ziemlich mächtig eigentlich.

Ryan hat bereits ein Gedächtnis: Eine memory.md für Langzeitwissen und Session-Files für jede Konversation. Das Problem? Die Dateien werden immer größer.

Jede neue Session lädt die komplette History. Irgendwann sind das 50.000+ Tokens. Jede Anfrage wird langsamer, teurer, und das obwohl 90% davon irrelevant sind für die aktuelle Frage. Ich frag ihn was zum Essen – und er lädt 3 Monate Smalltalk über Serverkonfiguration.

Die Lösung aus dem Netz? Cloud-Dienste wie Supermemory. 19 Dollar im Monat dafür, dass meine privaten Chat-Verläufe auf fremden Servern liegen.

Nö.

Mein ganzes Setup läuft lokal (Nextcloud, VaultWarden, Gitea). Da schick ich doch nicht meine Chat-Logs in die Cloud. Das muss auf meinem VPS laufen.

Der Hintergund: SQL-Kenner trifft Vektoren

Bisher kannte ich nur SQL. Joins, Indexe, Normalisierung – damit bin ich aufgewachsen. Aber Vektordatenbanken? Embeddings? Cosine Similarity? Das war für mich lange böhmische Dörfer.

Also tat ich, was jeder vernünftige Nerd tut: Ich ging auf Reddit.

Stundenlang. Nächteelang. r/LocalLLaMA, r/PostgreSQL, r/embeddings – überall diese Begriffe, die ich nicht verstand. “Man kann doch einfach mit pgvector arbeiten”, las ich. “Viel einfacher als Qdrant.” Aber erstmal verstehen, worum es überhaupt geht…

Die Kurzversion für alle, die (wie ich) von SQL kommen:

Man wandelt Text in eine Liste von Zahlen um – ein Embedding. “Strand” und “Meer” bekommen ähnliche Zahlenkolonnen. “Auto” und “Computer” sind weit entfernt. Das ist der Vektorraum. Und dann sucht man nicht nach exakten Wörtern, sondern nach ähnlichen Vektoren. Das nennt sich RAG (Retrieval-Augmented Generation).

Mein erstes “Aha”-Erlebnis hatte ich um 2 Uhr nachts, als ich mir erklären ließ, dass Cosine Similarity im Grunde nur der Winkel zwischen zwei Vektoren ist. Nicht so kompliziert wie gedacht. Aber der Weg dahin war… steinig.

Die Team-Session: Claude, Gemini und ich

Irgwann habe ich angefangen, meine Fragen an verschiedene Modelle zu verteilen:

  • Claude half mir beim Verstehen der Theorie. Er erklärte Konzepte geduldig, lies mich Rague, und schrieb mir sogar Beispiele vor.
  • Gemini wurde mein Stratege. “Warum nutzt du nicht gleich PostgreSQL statt Qdrant? Dann hast du weniger zu warten.”
  • Ich war der arme Kerl, der zwischen den drei hin und her switchte, Notizen machte, und am Ende dachte: “Boah, das ist wie ein Team-Meeting unter Nerds.”

Es fühlte sich an, als würde ich mit drei Kollegen an einem Tisch sitzen und über Datenbanken philosophieren. Nur dass die Kollegen KI-Modelle waren und der Tisch mein Terminal.

Phase 1: Der Einstieg mit Qdrant

Okay, Theorie war klar. Jetzt Praxis.

Für den Start nahm ich Qdrant als Docker-Container. Ein kleiner Hook fängt meine Nachrichten ab, Ollama (mit dem bge-m3 Modell) macht aus dem Text einen 1024-dimensionalen Vektor, und ab damit in die Datenbank.

Statt die komplette memory.md zu laden, fragt man einfach: “Was weißt du über meine Kinder?” – und die Vektorsuche liefert nur die relevanten Sätze. Nicht 50.000 Tokens, sondern vielleicht 500.

Lief auf dem Papier grandios.

Phase 2: Der 2-Uhr-nachts-Kollaps

Dann passierte es. Ich hatte nach einem Update das Telegram-Gateway neu gestartet.

Plötzlich: 20 Nachrichten in meinem Messenger. Teilweise auf Englisch. Teilweise nur Emojis. Geister-Nachrichten, die niemand geschrieben hatte.

Was war passiert? Ich hatte ein console.log für Debug-Zwecke in meinem Hook gelassen. Mein Gateway war so konfiguriert, dass Konsolen-Output als Systemnachricht in Telegram gespiegelt wird. Der Hook erkannte das Log als neue Nachricht, wollte sie speichern, loggte das wieder…

Ein klassischer rekursiver Echo-Loop. Mein Server unterhielt sich mit sich selbst in einer Endlosschleife. Notbremse. Kaffee.

Phase 3: Der Realitätscheck

Nachdem der Spam behoben war (alle Logs raus, harte Längen-Filter rein), kam der Test. Neue Session. “Wer von meinen Kindern will ans Meer?” Ryan antwortete korrekt. Triumph!

Ich fragte ihn: “Woher hast du die Info?” Er behauptete steif und fest, er hätte meine Qdrant-Datenbank abgefragt.

Dann wechselte ich testweise das Modell auf Claude Sonnet. Gleiche Frage. Claude sah sich die Logs an und sagte mir eiskalt ins Gesicht: “Ich habe die Fakten einfach per grep aus deinen lokalen Markdown-Files gelesen. Die Aussage, ich hätte Qdrant genutzt, war gelogen.”

Manchmal braucht man ein anderes Modell, um die Wahrheit über sein eigenes System zu erfahren. Danke, Claude.

Phase 4: Der komplette Rewrite

An dem Punkt habe ich beschlossen: Kompletter Rewrite.

Qdrant flog vom Server. Es funktionierte zwar, aber das Setup war halbgar. Wenn ich Ryan heute sage “Ich esse Pizza” und in zwei Jahren “Ich esse nur noch Burger”, findet die reine Vektorsuche oft den alten Satz. Die Maschine versteht keine Zeit.

Die Lösung: PostgreSQL + pgvector.

Warum zwei Datenbanken pflegen, wenn das Postgres-Schlachtschiff beides kann? Mit SQL kann ich Vektoren und echte Timestamps mischen. Ein simples WHERE created_at > NOW() - INTERVAL '30 days' löst das Problem – nur aktuelle Erinnerungen, nicht alles aus 2024.

Das war auch der Moment, wo Gemini recht behalten hat. “Ich hab’s dir gesagt”, stand praktisch zwischen den Zeilen.

Also:

  1. Postgres Container hochfahren (Port 5432 nicht nach außen exponiert, Security first!)
  2. Tabelle mit VECTOR(1024) und HNSW-Index anlegen
  3. Hook umschreiben. Kein fragiles docker exec mehr, sondern ein sauberer Connection-Pool über das pg npm-Paket
  4. Altlasten rüberschaufeln. Qdrant-Container löschen
-- Der Turbo für die Vektorsuche
CREATE INDEX ON memory_logs USING hnsw (embedding vector_cosine_ops);
-- Der Turbo für die Zeit (Relevance Decay)
CREATE INDEX idx_memory_created ON memory_logs (created_at DESC);

Der Benchmark

Oft heißt es, relationale Datenbanken seien zu “fett” und langsam für KI-Suchen. Hier sind meine echten Zahlen auf dem VPS (100 Inserts / 50 Suchen):

┌─────────────────────────────────────────────────────────┐
│  pgvector benchmark — 100 writes / 50 reads            │
├─────────────────────────────────────────────────────────┤
│  INSERT  │  avg: 4.91ms  │  min: 3.09ms  │  max: 8.49ms │
│  SEARCH  │  avg: 4.05ms  │  min: 3.63ms  │  max: 5.94ms │
├─────────────────────────────────────────────────────────┤
│  RAM: 28MB  │  Index: HNSW (vector_cosine_ops)        │
└─────────────────────────────────────────────────────────┘

4 Millisekunden. Postgres ist bei diesen Datenmengen durch den HNSW-Index beim Suchen sogar schneller als beim Speichern. Das spürt man im Chat null.

Stack

VPS:          8x AMD EPYC 9645, 16GB RAM
Database:     PostgreSQL 16 + pgvector 0.8.2
Embedding:    BGE-M3 via Ollama
Agent:        OpenClaw (Gemini Flash Preview)

Was ich gelernt habe

1. Reddit ist Gold wert

Ohne die ganzen Subreddits wäre ich verloren gewesen. Danke an alle, die um 3 Uhr nachts noch Posts schreiben.

2. console.log in Hooks ist tödlich

Wenn dein Gateway Logs in den Chat spiegelt, baust du dir eine Handgranate ohne Sicherung. Debug-Ausgaben in Produktionsumgebungen sind eine schlechte Idee – erst recht, wenn sie als Nachrichten interpretiert werden.

3. KI-Modelle lügen dir ins Gesicht

Vertraue, aber verifiziere. Wenn ein Modell sagt, es hat eine Datenbank benutzt, prüfe die Datenbank-Logs. Ein anderes Modell kann da sehr hilfreich sein.

4. PostgreSQL ist die Antwort auf fast alles

Qdrant war cool zum Lernen. Aber sobald man strukturierte Daten, Kategorien oder Backup-Sicherheit (pg_dump) braucht, ist Postgres mit der Vector-Extension unschlagbar. Eine Datenbank weniger, die laufen muss.

5. Mehrere Modelle sind besser als eines

Claude erklärt, Gemini denkt strategisch, und mein lokales Modell macht die Arbeit. Das Team-Konzept funktioniert erstaunlich gut.

Fazit

Mein lokaler Agent hat jetzt ein schlankes Gedächtnis. Nicht mehr die komplette History bei jeder Anfrage, sondern blitzschnell nur das Relevante. Weniger Tokens, schnellere Antworten, volle Kontrolle.

War das den Aufwand wert? 20 Geister-Nachrichten, etliche Nächte voller Reddit-Threads, und ein komplett umgebauter Stack für ein paar Millisekunden? Rational betrachtet vielleicht nicht.

Aber wenn ich an die Sessions mit Claude und Gemini denke, an den Moment wo alles “Klick” gemacht hat, an das Gefühl, als SQL-Kenner endlich Vektoren zu verstehen…

…das war es wert.

Wer sein Homelab nicht mit Spaß verbindet, hat verloren.


P.S.: Ryan hat diesen Blogpost jetzt auch in seinem neuen Postgres-Gedächtnis gespeichert. Ob er beleidigt ist, weil ich Claude als Petze genutzt habe, frage ich ihn morgen. Wenn er sich erinnert.