Speicher
Der OpenClaw-Speicher besteht aus einfachem Markdown im Agent-Workspace. Die Dateien sind die maßgebliche Quelle; das Modell „erinnert“ sich nur an das, was auf die Festplatte geschrieben wird. Speicher-Suchwerkzeuge werden vom aktiven Speicher-Plugin bereitgestellt (Standard:memory-core). Speicher-Plugins können mit plugins.slots.memory = "none" deaktiviert werden.
Speicherdateien (Markdown)
Das Standard-Workspace-Layout verwendet zwei Speicherebenen:memory/YYYY-MM-DD.md- Tägliches Protokoll (nur anhängend).
- Liest heute + gestern beim Sitzungsstart.
MEMORY.md(optional)- Kuratierter Langzeitspeicher.
- Wird nur in der Haupt-, privaten Sitzung geladen (niemals in Gruppenkontexten).
agents.defaults.workspace, Standard
~/.openclaw/workspace). Siehe Agent workspace für das vollständige Layout.
Wann Speicher geschrieben werden sollte
- Entscheidungen, Präferenzen und dauerhafte Fakten gehören in
MEMORY.md. - Alltägliche Notizen und laufender Kontext gehören in
memory/YYYY-MM-DD.md. - Wenn jemand sagt „merk dir das“, schreiben Sie es auf (nicht im RAM behalten).
- Dieser Bereich entwickelt sich noch. Es hilft, das Modell daran zu erinnern, Speicher abzulegen; es weiß dann, was zu tun ist.
- Wenn etwas dauerhaft bleiben soll, bitten Sie den Bot, es in den Speicher zu schreiben.
Automatischer Speicher-Flush (Pre-Compaction-Ping)
Wenn eine Sitzung kurz vor der Auto-Kompaktierung steht, löst OpenClaw einen stillen, agentischen Zug aus, der das Modell daran erinnert, dauerhaften Speicher vor der Kompaktierung des Kontexts zu schreiben. Die Standard-Prompts sagen ausdrücklich, dass das Modell antworten darf, aber in der Regel istNO_REPLY die richtige Antwort, sodass der Nutzer diesen Zug nie sieht.
Gesteuert wird dies über agents.defaults.compaction.memoryFlush:
- Weicher Schwellenwert: Der Flush wird ausgelöst, wenn die geschätzte Sitzungs-Tokenanzahl
contextWindow - reserveTokensFloor - softThresholdTokensüberschreitet. - Standardmäßig still: Prompts enthalten
NO_REPLY, sodass nichts ausgeliefert wird. - Zwei Prompts: Ein Nutzer-Prompt plus ein System-Prompt hängen die Erinnerung an.
- Ein Flush pro Kompaktierungszyklus (nachverfolgt in
sessions.json). - Workspace muss beschreibbar sein: Läuft die Sitzung in einer Sandbox mit
workspaceAccess: "ro"oder"none", wird der Flush übersprungen.
Vektorbasierte Speichersuche
OpenClaw kann einen kleinen Vektorindex überMEMORY.md und memory/*.md aufbauen, sodass
semantische Abfragen verwandte Notizen finden können, selbst wenn sich die Wortwahl unterscheidet.
Standards:
- Standardmäßig aktiviert.
- Überwacht Speicherdateien auf Änderungen (entprellt).
- Konfigurieren Sie die Memory-Suche unter
agents.defaults.memorySearch(nicht auf Top-LevelmemorySearch). - Verwendet standardmäßig Remote-Embeddings. Wenn
memorySearch.providernicht gesetzt ist, wählt OpenClaw automatisch:local, wenn einmemorySearch.local.modelPathkonfiguriert ist und die Datei existiert.openai, wenn ein OpenAI-Schlüssel aufgelöst werden kann.gemini, wenn ein Gemini-Schlüssel aufgelöst werden kann.voyage, wenn ein Voyage-Schlüssel aufgelöst werden kann.- Andernfalls bleibt die Speichersuche deaktiviert, bis sie konfiguriert wird.
- Der lokale Modus verwendet node-llama-cpp und erfordert ggf.
pnpm approve-builds. - Verwendet sqlite-vec (falls verfügbar), um die Vektorsuche innerhalb von SQLite zu beschleunigen.
models.providers.*.apiKey oder
Umgebungsvariablen auf. Codex OAuth deckt nur Chat/Completions ab und erfüllt nicht
die Anforderungen für Embeddings bei der Speichersuche. Für Gemini verwenden Sie GEMINI_API_KEY oder
models.providers.google.apiKey. Für Voyage verwenden Sie VOYAGE_API_KEY oder
models.providers.voyage.apiKey. Bei Verwendung eines benutzerdefinierten OpenAI-kompatiblen Endpunkts
setzen Sie memorySearch.remote.apiKey (und optional memorySearch.remote.headers).
QMD-Backend (experimentell)
Setzen Siememory.backend = "qmd", um den eingebauten SQLite-Indexer durch
QMD zu ersetzen: einen Local-first-Such-Sidecar, der
BM25 + Vektoren + Reranking kombiniert. Markdown bleibt die maßgebliche Quelle; OpenClaw
ruft QMD für die Abfrage auf. Wichtige Punkte:
Voraussetzungen
- Standardmäßig deaktiviert. Opt-in pro Konfiguration (
memory.backend = "qmd"). - Installieren Sie die QMD-CLI separat (
bun install -g https://github.com/tobi/qmdoder laden Sie ein Release) und stellen Sie sicher, dass dasqmd-Binary imPATHdes Gateways liegt. - QMD benötigt einen SQLite-Build, der Erweiterungen erlaubt (
brew install sqliteunter macOS). - QMD läuft vollständig lokal über Bun +
node-llama-cppund lädt beim ersten Einsatz automatisch GGUF-Modelle von HuggingFace herunter (kein separater Ollama-Daemon erforderlich). - Das Gateway führt QMD in einem eigenständigen XDG-Home unter
~/.openclaw/agents/<agentId>/qmd/aus, indemXDG_CONFIG_HOMEundXDG_CACHE_HOMEgesetzt werden. - Betriebssystem-Support: macOS und Linux funktionieren sofort, sobald Bun + SQLite installiert sind. Windows wird am besten über WSL2 unterstützt.
- Das Gateway schreibt ein eigenständiges QMD-Home unter
~/.openclaw/agents/<agentId>/qmd/(Konfiguration + Cache + SQLite-DB). - Collections werden über
qmd collection addausmemory.qmd.paths(plus Standard-Workspace-Speicherdateien) erstellt; anschließend laufenqmd update+qmd embedbeim Start und in einem konfigurierbaren Intervall (memory.qmd.update.interval, Standard 5 Min.). - Das Gateway initialisiert nun den QMD-Manager beim Start, sodass periodische Update-Timer
bereits vor dem ersten
memory_search-Aufruf aktiviert sind. - Die Aktualisierung beim Start läuft nun standardmäßig im Hintergrund, damit der Chat-Start
nicht blockiert wird; setzen Sie
memory.qmd.update.waitForBootSync = true, um das frühere blockierende Verhalten beizubehalten. - Suchen laufen über
qmd query --json. Wenn der ausgewählte Modus Flags in Ihrem QMD-Build ablehnt, versucht OpenClaw es erneut mitqmd query. Wenn QMD fehlschlägt oder das Binary fehlt, fällt OpenClaw automatisch auf den eingebauten SQLite-Manager zurück, sodass die Speicher-Tools weiter funktionieren. - OpenClaw stellt derzeit keine Batch-Size-Abstimmung für QMD-Embeddings bereit; das Batch-Verhalten wird von QMD selbst gesteuert.
- Erste Suche kann langsam sein: QMD lädt beim ersten
qmd query-Lauf möglicherweise lokale GGUF-Modelle (Reranker/Query-Expansion) herunter.-
OpenClaw setzt
XDG_CONFIG_HOME/XDG_CACHE_HOMEautomatisch, wenn es QMD ausführt. -
Wenn Sie Modelle manuell vorab herunterladen möchten (und denselben Index vorwärmen,
den OpenClaw verwendet), führen Sie eine einmalige Abfrage mit den XDG-Verzeichnissen des Agenten aus.
Der QMD-Status von OpenClaw liegt unter Ihrem State-Dir (Standard:
~/.openclaw). Sie könnenqmdauf exakt denselben Index zeigen lassen, indem Sie dieselben XDG-Variablen exportieren, die OpenClaw verwendet:
-
OpenClaw setzt
memory.qmd.*)
command(Standardqmd): überschreibt den Pfad zur ausführbaren Datei.searchMode(Standardsearch): Wählen Sie, welcher QMD-Befehlmemory_searchzugrunde liegt (search,vsearch,query).includeDefaultMemory(Standardtrue): indiziert automatischMEMORY.md+memory/**/*.md.paths[]: fügt zusätzliche Verzeichnisse/Dateien hinzu (path, optionalpattern, optional stabilname).sessions: Opt-in für Sitzungs-JSONL-Indizierung (enabled,retentionDays,exportDir).update: steuert Aktualisierungsfrequenz und Wartungsausführung: (interval,debounceMs,onBoot,waitForBootSync,embedInterval,commandTimeoutMs,updateTimeoutMs,embedTimeoutMs).limits: begrenzt den Recall-Payload (maxResults,maxSnippetChars,maxInjectedChars,timeoutMs).scope: gleiches Schema wiesession.sendPolicy. Standard ist nur DM (denyalle,allowDirektchats); lockern Sie dies, um QMD-Treffer in Gruppen/Kanälen anzuzeigen.match.keyPrefixgleicht den normalisierten Session-Key ab (kleingeschrieben, mit entferntem führendemagent:<id>:). Beispiel:discord:channel:.match.rawKeyPrefixgleicht den rohen Session-Key ab (kleingeschrieben), einschließlichagent:<id>:. Beispiel:agent:main:discord:.- Legacy:
match.keyPrefix: "agent:..."wird weiterhin als Raw-Key-Präfix behandelt, aber verwenden Sie zur Klarheit bevorzugtrawKeyPrefix.
- When
scopedenies a search, OpenClaw logs a warning with the derivedchannel/chatTypeso empty results are easier to debug. - Snippets aus Quellen außerhalb des Workspace erscheinen als
qmd/<collection>/<relative-path>inmemory_search-Ergebnissen;memory_getversteht dieses Präfix und liest aus dem konfigurierten QMD-Collection-Root. - Wenn
memory.qmd.sessions.enabled = true, exportiert OpenClaw bereinigte Sitzungs- Transkripte (User/Assistant-Züge) in eine dedizierte QMD-Collection unter~/.openclaw/agents/<id>/qmd/sessions/, sodassmemory_searchkürzliche Unterhaltungen abrufen kann, ohne den eingebauten SQLite-Index zu berühren. memory_search-Snippets enthalten nun eineSource: <path#line>-Fußzeile, wennmemory.citationsauto/onist; setzen Siememory.citations = "off", um die Pfad-Metadaten intern zu halten (der Agent erhält den Pfad weiterhin fürmemory_get, aber der Snippet-Text lässt die Fußzeile weg und der System-Prompt warnt den Agenten, sie nicht zu zitieren).
memory.citationsgilt unabhängig vom Backend (auto/on/off).- Wenn
qmdläuft, markieren wirstatus().backend = "qmd", sodass Diagnosen anzeigen, welche Engine die Ergebnisse geliefert hat. Wenn der QMD-Subprozess beendet wird oder JSON-Ausgaben nicht geparst werden können, protokolliert der Search-Manager eine Warnung und gibt den eingebauten Anbieter (bestehende Markdown-Embeddings) zurück, bis QMD sich erholt.
Zusätzliche Speicherpfade
Wenn Sie Markdown-Dateien außerhalb des Standard-Workspace-Layouts indizieren möchten, fügen Sie explizite Pfade hinzu:- Pfade können absolut oder workspace-relativ sein.
- Verzeichnisse werden rekursiv nach
.md-Dateien durchsucht. - Es werden nur Markdown-Dateien indiziert.
- Symlinks werden ignoriert (Dateien oder Verzeichnisse).
Gemini-Embeddings (nativ)
Setzen Sie den Anbieter aufgemini, um die Gemini-Embeddings-API direkt zu verwenden:
remote.baseUrlist optional (Standard ist die Basis-URL der Gemini-API).remote.headersermöglicht das Hinzufügen zusätzlicher Header bei Bedarf.- Standardmodell:
gemini-embedding-001.
remote-Konfiguration mit dem OpenAI-Anbieter nutzen:
memorySearch.provider = "local" oder setzen Sie
memorySearch.fallback = "none".
Fallbacks:
memorySearch.fallbackkannopenai,gemini,localodernonesein.- Der Fallback-Anbieter wird nur verwendet, wenn der primäre Embedding-Anbieter fehlschlägt.
- Standardmäßig aktiviert für OpenAI- und Gemini-Embeddings. Setzen Sie
agents.defaults.memorySearch.remote.batch.enabled = false, um sie zu deaktivieren. - Das Standardverhalten wartet auf den Abschluss des Batches; passen Sie
remote.batch.wait,remote.batch.pollIntervalMsundremote.batch.timeoutMinutesbei Bedarf an. - Setzen Sie
remote.batch.concurrency, um zu steuern, wie viele Batch-Jobs parallel eingereicht werden (Standard: 2). - Der Batch-Modus gilt, wenn
memorySearch.provider = "openai"oder"gemini"und verwendet den entsprechenden API-Schlüssel. - Gemini-Batch-Jobs verwenden den asynchronen Embeddings-Batch-Endpunkt und erfordern die Verfügbarkeit der Gemini Batch API.
- Für große Backfills ist OpenAI in der Regel die schnellste Option, die wir unterstützen, da wir viele Embedding-Anfragen in einem einzigen Batch-Job einreichen und OpenAI sie asynchron verarbeiten lassen können.
- OpenAI bietet rabattierte Preise für Batch-API-Workloads, sodass große Indizierungsläufe meist günstiger sind als das synchrone Senden derselben Anfragen.
- Siehe die OpenAI-Batch-API-Dokumente und Preise für Details:
memory_search— gibt Snippets mit Datei- und Zeilenbereichen zurück.memory_get— liest den Inhalt einer Speicherdatei anhand des Pfads.
- Setzen Sie
agents.defaults.memorySearch.provider = "local". - Geben Sie
agents.defaults.memorySearch.local.modelPath(GGUF oderhf:-URI) an. - Optional: Setzen Sie
agents.defaults.memorySearch.fallback = "none", um Remote-Fallbacks zu vermeiden.
Wie die Speicherwerkzeuge funktionieren
memory_searchdurchsucht semantisch Markdown-Chunks (~400 Token Ziel, 80-Token-Überlappung) ausMEMORY.md+memory/**/*.md. Es gibt Snippet-Text (begrenzt auf ~700 Zeichen), Dateipfad, Zeilenbereich, Score, Anbieter/Modell und ob von lokalen → Remote-Embeddings zurückgefallen wurde, zurück. Es wird kein vollständiger Dateiinhalts-Payload zurückgegeben.memory_getliest eine bestimmte Speicher-Markdown-Datei (workspace-relativ), optional ab einer Startzeile und für N Zeilen. Pfade außerhalb vonMEMORY.md/memory/werden abgelehnt.- Beide Werkzeuge sind nur aktiviert, wenn
memorySearch.enabledfür den Agenten zu true aufgelöst wird.
Was indiziert wird (und wann)
- Dateityp: nur Markdown (
MEMORY.md,memory/**/*.md). - Index-Speicher: pro Agent SQLite unter
~/.openclaw/memory/<agentId>.sqlite(konfigurierbar überagents.defaults.memorySearch.store.path, unterstützt das{agentId}-Token). - Aktualität: Watcher auf
MEMORY.md+memory/markieren den Index als „dirty“ (Entprellung 1,5 s). Die Synchronisierung wird beim Sitzungsstart, bei einer Suche oder in einem Intervall geplant und läuft asynchron. Sitzungs-Transkripte verwenden Delta-Schwellen, um eine Hintergrund-Synchronisierung auszulösen. - Reindex-Auslöser: Der Index speichert Anbieter/Modell + Endpunkt-Fingerprint + Chunking-Parameter. Wenn sich einer davon ändert, setzt OpenClaw den gesamten Store automatisch zurück und indiziert neu.
Hybride Suche (BM25 + Vektor)
Wenn aktiviert, kombiniert OpenClaw:- Vektor-Ähnlichkeit (semantische Übereinstimmung, Wortwahl kann variieren)
- BM25-Schlüsselwort-Relevanz (exakte Tokens wie IDs, Umgebungsvariablen, Code-Symbole)
Warum hybrid?
Vektorsuche ist hervorragend für „das bedeutet dasselbe“:- „Mac Studio Gateway-Host“ vs. „die Maschine, auf der das Gateway läuft“
- „Dateiaktualisierungen entprellen“ vs. „Indizierung bei jedem Schreiben vermeiden“
- IDs (
a828e60,b3b9895a…) - Code-Symbole (
memorySearch.query.hybrid) - Fehlermeldungen („sqlite-vec unavailable“)
Wie wir Ergebnisse zusammenführen (aktuelles Design)
Implementierungsskizze:- Abruf eines Kandidatenpools von beiden Seiten:
- Vektor: Top
maxResults * candidateMultipliernach Kosinus-Ähnlichkeit. - BM25: Top
maxResults * candidateMultipliernach FTS5-BM25-Rang (niedriger ist besser).
- Umwandlung des BM25-Rangs in einen 0..1-ähnlichen Score:
textScore = 1 / (1 + max(0, bm25Rank))
- Vereinigung der Kandidaten nach Chunk-ID und Berechnung eines gewichteten Scores:
finalScore = vectorWeight * vectorScore + textWeight * textScore
vectorWeight+textWeightwerden bei der Konfigurationsauflösung auf 1,0 normiert, sodass die Gewichte wie Prozentwerte wirken.- Wenn Embeddings nicht verfügbar sind (oder der Anbieter einen Null-Vektor zurückgibt), führen wir weiterhin BM25 aus und geben Schlüsselworttreffer zurück.
- Wenn FTS5 nicht erstellt werden kann, behalten wir die reine Vektorsuche bei (kein harter Fehler).
Embedding-Cache
OpenClaw kann Chunk-Embeddings in SQLite zwischenspeichern, sodass Reindizierung und häufige Updates (insbesondere Sitzungs-Transkripte) unveränderten Text nicht erneut einbetten. Konfiguration:Sitzungs-Speichersuche (experimentell)
Optional können Sie Sitzungs-Transkripte indizieren und übermemory_search verfügbar machen.
Dies ist hinter einem experimentellen Flag abgesichert.
- Die Sitzungsindizierung ist Opt-in (standardmäßig aus).
- Sitzungsaktualisierungen werden entprellt und asynchron indiziert, sobald sie Delta-Schwellen überschreiten (Best-Effort).
memory_searchblockiert niemals auf die Indizierung; Ergebnisse können leicht veraltet sein, bis die Hintergrund-Synchronisierung abgeschlossen ist.- Ergebnisse enthalten weiterhin nur Snippets;
memory_getbleibt auf Speicherdateien beschränkt. - Die Sitzungsindizierung ist pro Agent isoliert (es werden nur die Sitzungsprotokolle dieses Agenten indiziert).
- Sitzungsprotokolle liegen auf der Festplatte (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). Jeder Prozess/Nutzer mit Dateisystemzugriff kann sie lesen; betrachten Sie daher den Festplattenzugriff als Vertrauensgrenze. Für strengere Isolation führen Sie Agenten unter separaten OS-Benutzern oder Hosts aus.
SQLite-Vektor-Beschleunigung (sqlite-vec)
Wenn die sqlite-vec-Erweiterung verfügbar ist, speichert OpenClaw Embeddings in einer SQLite-virtuellen Tabelle (vec0) und führt Vektor-Distanzabfragen in der
Datenbank aus. Das hält die Suche schnell, ohne jedes Embedding in JS zu laden.
Konfiguration (optional):
enabledist standardmäßig true; wenn deaktiviert, fällt die Suche auf eine In-Process- Kosinus-Ähnlichkeit über gespeicherte Embeddings zurück.- Wenn die sqlite-vec-Erweiterung fehlt oder nicht geladen werden kann, protokolliert OpenClaw den Fehler und fährt mit dem JS-Fallback fort (keine Vektortabelle).
extensionPathüberschreibt den mitgelieferten sqlite-vec-Pfad (nützlich für Custom-Builds oder nicht standardisierte Installationsorte).
Automatischer Download lokaler Embeddings
- Standardmäßiges lokales Embedding-Modell:
hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(~0,6 GB). - Wenn
memorySearch.provider = "local", löstnode-llama-cppmodelPathauf; fehlt das GGUF, wird es automatisch heruntergeladen in den Cache (oderlocal.modelCacheDir, falls gesetzt) und anschließend geladen. Downloads werden bei Wiederholung fortgesetzt. - Native-Build-Anforderung: führen Sie
pnpm approve-buildsaus, wählen Sienode-llama-cpp, dannpnpm rebuild node-llama-cpp. - Fallback: Wenn das lokale Setup fehlschlägt und
memorySearch.fallback = "openai", wechseln wir automatisch zu Remote-Embeddings (openai/text-embedding-3-small, sofern nicht überschrieben) und protokollieren den Grund.
Beispiel für einen benutzerdefinierten OpenAI-kompatiblen Endpunkt
remote.*hat Vorrang vormodels.providers.openai.*.remote.headerswerden mit OpenAI-Headern zusammengeführt; bei Schlüsselkonflikten gewinnt Remote. Lassen Sieremote.headersweg, um die OpenAI-Standardwerte zu verwenden.