Geplante Agenten begannen bei jedem Cron-Lauf bei null. Ein Agent, der alle 30 Minuten lief, wusste nichts von seinem letzten Durchgang — er rief dieselben Quellen ab, zog dieselben Schluesse und konnte keine Entwicklung ueber Zeit verfolgen. Das war zugleich die groesste Faehigkeitsluecke und eine dauerhafte Token-Verschwendung. Speicher-Fundament SqliteStorage buendelt den Zugang zur Instanz-Datenbank und aktiviert WAL, busy_timeout und Connection-Pooling. Vorher oeffnete jeder Aufruf eine Verbindung ohne diese Einstellungen; bei mehreren gleichzeitig schreibenden Agenten gab das "database is locked". Das sah nach einer Grenze von SQLite aus, war aber nur fehlende Konfiguration. Zwei Tests decken das gezielt ab. Gedaechtnis Typisierte Tabelle statt JSON in einer Wert-Spalte — nur so laesst sich filtern, sortieren und spaeter auswerten. Das Schema ist schlicht gehalten, damit eine MySQL-Variante spaeter dieselbe Struktur mit wenigen Dialektunterschieden bekommen kann. Der wichtigste Teil ist der optionale Schluessel: Erneutes Merken darunter aktualisiert den Eintrag, statt einen zweiten anzulegen. Ohne das wuechse das Gedaechtnis eines halbstuendlich laufenden Agenten um 48 Eintraege pro Tag zur selben Sache. Beobachtungen ohne Schluessel sammeln sich weiterhin an, wenn ein Verlauf entstehen soll. Der Abruf sortiert nach Wichtigkeit, dann Aktualitaet — wesentlich, weil das Ergebnis begrenzt wird und bei einer Kappung das Wichtigste ueberleben muss. Zusaetzlich greift eine Zeichenobergrenze, damit ein Abruf den Kontext nicht sprengt. Die Trennung privat/geteilt ist absichtlich dieselbe wie beim FileRW-Tool, damit das Konzept fuer Agenten wiedererkennbar bleibt. Beim Testen fiel auf, dass das Maskieren der LIKE-Platzhalter falsch war: Die Zeichen wurden entfernt statt maskiert, wodurch eine Suche nach einem Prozentzeichen zu einem leeren Muster und damit zu einem Treffer auf alles wurde. Jetzt mit ESCAPE-Klausel. 338 Tests gruen (190 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.3 KiB
Memory — Langzeitgedächtnis für Agenten
Löst K1 aus der Bestandsaufnahme: Geplante Agenten begannen bei jedem Cron-Lauf bei null. Ein Agent, der alle 30 Minuten lief, wusste nichts von seinem letzten Durchgang — er rief dieselben Quellen ab, zog dieselben Schlüsse und konnte keine Entwicklung über Zeit verfolgen.
Warum nicht der vorhandene State-Store
IStateStore ist eine Schlüssel-Wert-Tabelle für kleine Marker („zuletzt gesehene ID").
Ein Gedächtnis darin abzulegen hieße, JSON in eine Value-Spalte zu schreiben — damit
lässt sich nichts filtern, sortieren oder auswerten.
Deshalb typisierte Spalten in einer eigenen Tabelle. Das Schema ist bewusst schlicht gehalten, damit eine MySQL-Variante später dieselbe Struktur mit wenigen Dialektunterschieden bekommen kann.
Modell
| Feld | Zweck |
|---|---|
Scope |
agent (privat) oder shared (alle Agenten der Instanz) |
Subject |
Worum es geht — Ticker, Kunde, Projekt |
Key |
Optional. Erneutes Merken darunter aktualisiert statt anzulegen |
Category |
fact, decision, observation, task, contact, other |
Tags |
Schlagworte zum Wiederfinden |
Importance |
1–5, steuert die Reihenfolge beim Abruf |
CreatedBy |
Bleibt auch im geteilten Bereich sichtbar |
Die Scope-Trennung ist absichtlich dieselbe wie beim FileRW-Tool (personal/shared) —
für Agenten bleibt das Konzept dadurch wiedererkennbar.
Der Schlüssel ist das Wichtigste
Ohne ihn wüchse das Gedächtnis eines alle 30 Minuten laufenden Agenten um 48 Einträge
pro Tag zur selben Sache. Mit key='kursziel_nvda' bleibt es ein Eintrag, der
sich fortschreibt — das Anlagedatum bleibt erhalten, nur UpdatedAt wandert.
Beobachtungen ohne Schlüssel sammeln sich weiterhin an; das ist gewollt, wenn ein Verlauf entstehen soll.
Abruf
Sortiert nach Wichtigkeit, dann Aktualität. Das ist wesentlich, weil das Ergebnis begrenzt wird: Bei einer Kappung muss das Wichtigste überleben.
Zusätzlich greift eine Zeichenobergrenze (8.000 Zeichen) — ein Abruf darf den Kontext nicht sprengen, dieselbe Überlegung wie bei der Tool-Ergebnis-Kappung (T2).
Speicher-Fundament
SqliteStorage bündelt den Zugang zur Instanz-Datenbank:
- WAL — beliebig viele Leser parallel zu einem Schreiber
- busy_timeout — ein Schreiber wartet kurz, statt sofort zu scheitern
- Connection-Pooling — kein Verbindungsaufbau je Aufruf
- Schreib-Warteschlange im Prozess — macht Fehlerbilder reproduzierbar
Vorher öffnete jeder Aufruf eine Verbindung ohne diese Einstellungen. Bei mehreren
gleichzeitig schreibenden Agenten gab das database is locked — das sah nach einer
Grenze von SQLite aus, war aber nur fehlende Konfiguration. Zwei Tests decken das
gezielt ab (60 gleichzeitige Schreibvorgänge, gemischtes Lesen und Schreiben).
Offen
- Automatische Einblendung: Ein Agent muss
recallderzeit selbst aufrufen. Für geplante Läufe wäre eine kurze Übersicht der wichtigsten Erinnerungen im Auftrag hilfreich. Sie gehört in die Nutzernachricht, nicht in den System-Prompt — sonst verfällt bei jedem Lauf der Prompt-Cache (T1). - Verfall: Alte, unwichtige Beobachtungen könnten nach einer Frist entfallen.
- MySQL: Zweite Implementierung von
IMemoryRepository, wenn mehrere Rechner dazukommen.