Mémoire
La mémoire d’OpenClaw est du Markdown brut dans l’espace de travail de l’agent. Les fichiers sont la source de vérité ; le modèle ne « se souvient » que de ce qui est écrit sur le disque. Les outils de recherche de mémoire sont fournis par le plugin de mémoire actif (par défaut :memory-core). Désactivez les plugins de mémoire avec plugins.slots.memory = "none".
Fichiers de mémoire (Markdown)
La disposition par défaut de l’espace de travail utilise deux couches de mémoire :memory/YYYY-MM-DD.md- Journal quotidien (ajout uniquement).
- Lecture d’aujourd’hui + hier au démarrage de la session.
MEMORY.md(facultatif)- Mémoire à long terme curatée.
- Chargée uniquement dans la session principale et privée (jamais dans des contextes de groupe).
agents.defaults.workspace, par défaut
~/.openclaw/workspace). Voir Espace de travail de l’agent pour la disposition complète.
Quand écrire en mémoire
- Les décisions, préférences et faits durables vont dans
MEMORY.md. - Les notes quotidiennes et le contexte courant vont dans
memory/YYYY-MM-DD.md. - Si quelqu’un dit « souviens‑toi de ceci », écrivez‑le (ne le gardez pas en RAM).
- Cette zone évolue encore. Il est utile de rappeler au modèle de stocker des souvenirs ; il saura quoi faire.
- Si vous voulez que quelque chose persiste, demandez au bot de l’écrire en mémoire.
Purge automatique de la mémoire (ping avant compaction)
Lorsqu’une session est proche de l’auto‑compaction, OpenClaw déclenche un tour agentique silencieux qui rappelle au modèle d’écrire la mémoire durable avant que le contexte ne soit compacté. Les invites par défaut indiquent explicitement que le modèle peut répondre, mais en généralNO_REPLY est la
réponse correcte afin que l’utilisateur ne voie jamais ce tour.
Ceci est contrôlé par agents.defaults.compaction.memoryFlush :
- Seuil souple : la purge se déclenche lorsque l’estimation des tokens de session dépasse
contextWindow - reserveTokensFloor - softThresholdTokens. - Silencieux par défaut : les invites incluent
NO_REPLYafin que rien ne soit livré. - Deux invites : une invite utilisateur plus une invite système ajoutent le rappel.
- Une purge par cycle de compaction (suivie dans
sessions.json). - L’espace de travail doit être accessible en écriture : si la session s’exécute en sandbox avec
workspaceAccess: "ro"ou"none", la purge est ignorée.
Recherche de mémoire vectorielle
OpenClaw peut construire un petit index vectoriel surMEMORY.md et memory/*.md afin que
les requêtes sémantiques trouvent des notes liées même lorsque le libellé diffère.
Valeurs par défaut :
- Activée par défaut.
- Surveille les fichiers de mémoire pour les changements (avec anti‑rebond).
- Configurez la recherche mémoire sous
agents.defaults.memorySearch(et non au niveau supérieurmemorySearch). - Utilise des embeddings distants par défaut. Si
memorySearch.providern’est pas défini, OpenClaw sélectionne automatiquement :localsi unmemorySearch.local.modelPathest configuré et que le fichier existe.openaisi une clé OpenAI peut être résolue.geminisi une clé Gemini peut être résolue.voyagesi une clé Voyage peut être résolue.- Sinon, la recherche mémoire reste désactivée jusqu’à configuration.
- Le mode local utilise node-llama-cpp et peut nécessiter
pnpm approve-builds. - Utilise sqlite-vec (lorsqu’il est disponible) pour accélérer la recherche vectorielle dans SQLite.
models.providers.*.apiKey, ou les variables
d’environnement. L’OAuth Codex couvre uniquement le chat/les complétions et ne satisfait pas
les embeddings pour la recherche mémoire. Pour Gemini, utilisez GEMINI_API_KEY ou
models.providers.google.apiKey. Pour Voyage, utilisez VOYAGE_API_KEY ou
models.providers.voyage.apiKey. Lors de l’utilisation d’un endpoint compatible OpenAI personnalisé,
définissez memorySearch.remote.apiKey (et éventuellement memorySearch.remote.headers).
Backend QMD (expérimental)
Définissezmemory.backend = "qmd" pour remplacer l’indexeur SQLite intégré par
QMD : un sidecar de recherche « local‑first » combinant
BM25 + vecteurs + reranking. Le Markdown reste la source de vérité ; OpenClaw délègue la
récupération à QMD. Points clés :
Prérequis
- Désactivé par défaut. Activation par configuration (
memory.backend = "qmd"). - Installez le CLI QMD séparément (
bun install -g github.com/tobi/qmdou téléchargez une version) et assurez‑vous que le binaireqmdest sur lePATHde la Gateway (passerelle). - QMD nécessite une version de SQLite autorisant les extensions (
brew install sqlitesur macOS). - QMD s’exécute entièrement en local via Bun +
node-llama-cppet télécharge automatiquement les modèles GGUF depuis HuggingFace au premier usage (aucun démon Ollama séparé requis). - La Gateway exécute QMD dans un home XDG autonome sous
~/.openclaw/agents/<agentId>/qmd/en définissantXDG_CONFIG_HOMEetXDG_CACHE_HOME. - Support des OS : macOS et Linux fonctionnent immédiatement une fois Bun + SQLite installés. Windows est mieux pris en charge via WSL2.
- La Gateway écrit un home QMD autonome sous
~/.openclaw/agents/<agentId>/qmd/(configuration + cache + base sqlite). - Les collections sont réécrites depuis
memory.qmd.paths(plus les fichiers de mémoire par défaut de l’espace de travail) versindex.yml, puisqmd update+qmd embeds’exécutent au démarrage et à un intervalle configurable (memory.qmd.update.interval, par défaut 5 min). - Le gateway initialise désormais le gestionnaire QMD au démarrage, de sorte que les minuteurs de mise à jour périodique
soient activés avant même le premier appel
memory_search. - L’actualisation du démarrage s’exécute maintenant en arrière-plan par défaut, de sorte que le démarrage du chat n’est pas
bloqué; définissez
mémoire. md.update.waitForBootSync = truepour garder le comportement de blocage précédent. - Les recherches s’exécutent via
qmd query --json. Si le mode sélectionné rejette les options sur votre build QMD, OpenClaw réessaie avecqmd query. Si QMD échoue ou si le binaire est absent, OpenClaw bascule automatiquement vers le gestionnaire SQLite intégré afin que les outils de mémoire continuent de fonctionner. - OpenClaw n’expose pas le réglage de la taille des lots QMD aujourd’hui ; le comportement des lots est contrôlé par QMD lui-même.
- La première recherche peut être lente : QMD peut télécharger des modèles GGUF locaux
(reranker/extension de requête) lors de la première exécution de
qmd query.-
OpenClaw définit automatiquement
XDG_CONFIG_HOME/XDG_CACHE_HOMElorsqu’il exécute QMD. -
Si vous souhaitez pré‑télécharger manuellement les modèles (et préchauffer le même index
qu’OpenClaw utilise), lancez une requête unique avec les répertoires XDG de l’agent.
L’état QMD d’OpenClaw se trouve dans votre répertoire d’état (par défaut
~/.openclaw). Vous pouvez pointerqmdvers exactement le même index en exportant les mêmes variables XDG qu’OpenClaw utilise :
-
OpenClaw définit automatiquement
memory.qmd.*)
command(par défautqmd) : remplacer le chemin de l’exécutable.includeDefaultMemory(par défauttrue) : indexation automatique deMEMORY.md+memory/**/*.md.includeDefaultMemory(par défauttrue) : indexation automatique deMEMORY.md+memory/**/*.md.paths[]: ajouter des répertoires/fichiers supplémentaires (path, optionnelpattern, optionnel stablename).sessions: activer l’indexation des JSONL de session (enabled,retentionDays,exportDir).update: contrôle la cadence d’actualisation (interval,debounceMs,onBoot,embedInterval).limits: plafonner la charge utile de rappel (maxResults,maxSnippetChars,maxInjectedChars,timeoutMs).scope: même schéma quesession.sendPolicy. La valeur par défaut est DM‑only (denytout,allowdiscussions directes) ; assouplissez‑la pour faire remonter les résultats QMD dans les groupes/canaux.match.keyPrefixcorrespond à la clé de session normalisée (en minuscules, avec tout préfixeagent:<id>:supprimé). Exemple :discord:channel:.match.rawKeyPrefixcorrespond à la clé de session brute (en minuscules), incluantagent:<id>:. Exemple :agent:main:discord:.- Legacy :
match.keyPrefix: "agent:..."est toujours traité comme un préfixe de clé brute, mais préférezrawKeyPrefixpour plus de clarté.
- When
scopedenies a search, OpenClaw logs a warning with the derivedchannel/chatTypeso empty results are easier to debug. - Les extraits provenant de l’extérieur de l’espace de travail apparaissent comme
qmd/<collection>/<relative-path>dans les résultatsmemory_search;memory_getcomprend ce préfixe et lit depuis la racine de collection QMD configurée. - Lorsque
memory.qmd.sessions.enabled = true, OpenClaw exporte des transcriptions de session assainies (tours Utilisateur/Assistant) dans une collection QMD dédiée sous~/.openclaw/agents/<id>/qmd/sessions/, afin quememory_searchpuisse rappeler des conversations récentes sans toucher à l’index SQLite intégré. - Les extraits
memory_searchincluent désormais un pied de pageSource: <path#line>lorsquememory.citationsestauto/on; définissezmemory.citations = "off"pour conserver les métadonnées de chemin en interne (l’agent reçoit toujours le chemin pourmemory_get, mais le texte de l’extrait omet le pied de page et l’invite système avertit l’agent de ne pas le citer).
memory.citationss’applique quel que soit le backend (auto/on/off).- Lorsque
qmds’exécute, nous marquonsstatus().backend = "qmd"afin que les diagnostics indiquent quel moteur a servi les résultats. Si le sous‑processus QMD se termine ou si la sortie JSON ne peut pas être analysée, le gestionnaire de recherche consigne un avertissement et renvoie le fournisseur intégré (embeddings Markdown existants) jusqu’à ce que QMD récupère.
Chemins de mémoire supplémentaires
Si vous souhaitez indexer des fichiers Markdown en dehors de la disposition par défaut de l’espace de travail, ajoutez des chemins explicites :- Les chemins peuvent être absolus ou relatifs à l’espace de travail.
- Les répertoires sont analysés récursivement pour les fichiers
.md. - Seuls les fichiers Markdown sont indexés.
- Les liens symboliques sont ignorés (fichiers ou répertoires).
Embeddings Gemini (natifs)
Définissez le fournisseur surgemini pour utiliser directement l’API d’embeddings Gemini :
remote.baseUrlest optionnel (par défaut l’URL de base de l’API Gemini).remote.headerspermet d’ajouter des en‑têtes supplémentaires si nécessaire.- Modèle par défaut :
gemini-embedding-001.
remote avec le fournisseur OpenAI :
memorySearch.provider = "local" ou définissez
memorySearch.fallback = "none".
Replis :
memorySearch.fallbackpeut êtreopenai,gemini,localounone.- Le fournisseur de repli n’est utilisé que lorsque le fournisseur d’embeddings principal échoue.
- Activée par défaut pour les embeddings OpenAI et Gemini. Définissez
agents.defaults.memorySearch.remote.batch.enabled = falsepour désactiver. - Le comportement par défaut attend la fin des lots ; ajustez
remote.batch.wait,remote.batch.pollIntervalMsetremote.batch.timeoutMinutessi nécessaire. - Définissez
remote.batch.concurrencypour contrôler le nombre de tâches de lot soumises en parallèle (par défaut : 2). - Le mode lot s’applique lorsque
memorySearch.provider = "openai"ou"gemini"et utilise la clé API correspondante. - Les lots Gemini utilisent l’endpoint de lot asynchrone des embeddings et nécessitent la disponibilité de l’API Batch Gemini.
- Pour les remplissages volumineux, OpenAI est généralement l’option la plus rapide que nous prenons en charge, car nous pouvons soumettre de nombreuses requêtes d’embeddings dans un seul lot et laisser OpenAI les traiter de manière asynchrone.
- OpenAI propose une tarification remisée pour les charges de travail de l’API Batch, de sorte que les grandes exécutions d’indexation sont généralement moins chères que l’envoi synchrone des mêmes requêtes.
- Voir la documentation et les tarifs de l’API Batch d’OpenAI pour plus de détails :
memory_search— renvoie des extraits avec fichier + plages de lignes.memory_get— lit le contenu d’un fichier de mémoire par chemin.
- Définissez
agents.defaults.memorySearch.provider = "local". - Fournissez
agents.defaults.memorySearch.local.modelPath(GGUF ou URIhf:). - Optionnel : définissez
agents.defaults.memorySearch.fallback = "none"pour éviter le repli distant.
Fonctionnement des outils de mémoire
memory_searcheffectue une recherche sémantique sur des fragments Markdown (~400 tokens ciblés, chevauchement de 80 tokens) provenant deMEMORY.md+memory/**/*.md. Il renvoie le texte de l’extrait (plafonné à ~700 caractères), le chemin du fichier, la plage de lignes, le score, le fournisseur/modèle, et indique si nous avons basculé de local → distant pour les embeddings. Aucune charge utile de fichier complet n’est renvoyée.memory_getlit un fichier Markdown de mémoire spécifique (relatif à l’espace de travail), éventuellement à partir d’une ligne de départ et pour N lignes. Les chemins en dehors deMEMORY.md/memory/sont rejetés.- Les deux outils ne sont activés que lorsque
memorySearch.enabledest vrai pour l’agent.
Ce qui est indexé (et quand)
- Type de fichier : Markdown uniquement (
MEMORY.md,memory/**/*.md). - Stockage de l’index : SQLite par agent à
~/.openclaw/memory/<agentId>.sqlite(configurable viaagents.defaults.memorySearch.store.path, prend en charge le jeton{agentId}). - Fraîcheur : un observateur sur
MEMORY.md+memory/marque l’index comme obsolète (anti‑rebond 1,5 s). La synchronisation est planifiée au démarrage de la session, lors d’une recherche ou à intervalle, et s’exécute de manière asynchrone. Les transcriptions de session utilisent des seuils delta pour déclencher une synchronisation en arrière‑plan. - Déclencheurs de réindexation : l’index stocke l’empreinte fournisseur/modèle d’embedding + endpoint + paramètres de découpage. Si l’un d’eux change, OpenClaw réinitialise et réindexe automatiquement l’ensemble du stockage.
Recherche hybride (BM25 + vecteur)
Lorsqu’elle est activée, OpenClaw combine :- Similarité vectorielle (correspondance sémantique, le libellé peut différer)
- Pertinence par mots‑clés BM25 (tokens exacts comme IDs, variables d’environnement, symboles de code)
Pourquoi l’hybride ?
La recherche vectorielle est excellente pour « cela signifie la même chose » :- « Mac Studio gateway host » vs « la machine exécutant la Gateway (passerelle) »
- « debounce file updates » vs « éviter l’indexation à chaque écriture »
- IDs (
a828e60,b3b9895a…) - symboles de code (
memorySearch.query.hybrid) - chaînes d’erreur (« sqlite-vec unavailable »)
Comment nous fusionnons les résultats (conception actuelle)
Esquisse d’implémentation :- Récupérer un pool de candidats des deux côtés :
- Vecteur : top
maxResults * candidateMultiplierpar similarité cosinus. - BM25 : top
maxResults * candidateMultiplierpar rang BM25 FTS5 (plus petit est meilleur).
- Convertir le rang BM25 en un score ~0..1 :
textScore = 1 / (1 + max(0, bm25Rank))
- Unifier les candidats par id de fragment et calculer un score pondéré :
finalScore = vectorWeight * vectorScore + textWeight * textScore
vectorWeight+textWeightest normalisé à 1,0 lors de la résolution de configuration, afin que les poids se comportent comme des pourcentages.- Si les embeddings sont indisponibles (ou si le fournisseur renvoie un vecteur nul), nous exécutons quand même BM25 et renvoyons les correspondances par mots‑clés.
- Si FTS5 ne peut pas être créé, nous conservons une recherche vectorielle seule (pas d’échec bloquant).
Cache d’embeddings
OpenClaw peut mettre en cache les embeddings de fragments dans SQLite afin que la réindexation et les mises à jour fréquentes (en particulier les transcriptions de session) ne ré‑encodent pas un texte inchangé. Configuration :Recherche de mémoire de session (expérimental)
Vous pouvez optionnellement indexer les transcriptions de session et les exposer viamemory_search.
Ceci est protégé par un indicateur expérimental.
- L’indexation des sessions est optionnelle (désactivée par défaut).
- Les mises à jour de session sont anti‑rebond et indexées de manière asynchrone une fois les seuils delta dépassés (best‑effort).
memory_searchne bloque jamais sur l’indexation ; les résultats peuvent être légèrement obsolètes jusqu’à la fin de la synchronisation en arrière‑plan.- Les résultats incluent toujours uniquement des extraits ;
memory_getreste limité aux fichiers de mémoire. - L’indexation des sessions est isolée par agent (seuls les journaux de session de cet agent sont indexés).
- Les journaux de session résident sur le disque (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). Tout processus/utilisateur ayant accès au système de fichiers peut les lire ; considérez donc l’accès disque comme la frontière de confiance. Pour une isolation plus stricte, exécutez les agents sous des utilisateurs ou des hôtes OS distincts.
Accélération vectorielle SQLite (sqlite-vec)
Lorsque l’extension sqlite-vec est disponible, OpenClaw stocke les embeddings dans une table virtuelle SQLite (vec0) et effectue les requêtes de distance vectorielle
dans la base de données. Cela maintient des recherches rapides sans charger chaque embedding en JS.
Configuration (facultatif) :
enabledest vrai par défaut ; lorsqu’il est désactivé, la recherche se replie sur la similarité cosinus en processus sur les embeddings stockés.- Si l’extension sqlite-vec est absente ou échoue au chargement, OpenClaw consigne l’erreur et continue avec le repli JS (pas de table vectorielle).
extensionPathremplace le chemin sqlite-vec fourni (utile pour des builds personnalisés ou des emplacements d’installation non standard).
Téléchargement automatique des embeddings locaux
- Modèle d’embedding local par défaut :
hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(~0,6 Go). - Lorsque
memorySearch.provider = "local",node-llama-cpprésoutmodelPath; si le GGUF est manquant, il est téléchargé automatiquement dans le cache (oulocal.modelCacheDirs’il est défini), puis chargé. Les téléchargements reprennent lors d’une nouvelle tentative. - Exigence de build natif : exécutez
pnpm approve-builds, choisisseznode-llama-cpp, puispnpm rebuild node-llama-cpp. - Repli : si la configuration locale échoue et que
memorySearch.fallback = "openai", nous basculons automatiquement vers des embeddings distants (openai/text-embedding-3-smallsauf indication contraire) et enregistrons la raison.
Exemple d’endpoint compatible OpenAI personnalisé
remote.*a priorité surmodels.providers.openai.*.remote.headersse fusionnent avec les en‑têtes OpenAI ; le distant l’emporte en cas de conflit de clés. Omettezremote.headerspour utiliser les valeurs par défaut OpenAI.