Memoria
Cómo funciona la memoria de OpenClaw (archivos del espacio de trabajo + actualización automática de memoria).
La memoria de OpenClaw es Markdown simple en espacios de trabajo de agentes. Estos archivos son
la fuente de verdad; el modelo solo "recuerda" lo que está escrito en disco.
Las herramientas de búsqueda de memoria son proporcionadas por el plugin de memoria activo (predeterminado:
''memory-core''). Usa ''plugins.slots.memory = "none"'' para deshabilitar el plugin de memoria.
Archivos de Memoria (Markdown)
El diseño predeterminado del espacio de trabajo usa dos capas de memoria:
- ''memory/YYYY-MM-DD.md''
- Registros diarios (solo añadir).
- Hoy + ayer se leen al inicio de un turno.
- ''MEMORY.md'' (opcional)
- Memoria a largo plazo curada.
- Solo se carga en la sesión privada principal (nunca en contexto de grupo).
Estos archivos viven bajo el espacio de trabajo (''agents.defaults.workspace'', predeterminado
Cuándo Escribir a Memoria
- Decisiones, preferencias y hechos persistentes van a ''MEMORY.md''.
- Notas diarias y entorno de ejecución van a ''memory/YYYY-MM-DD.md''.
- Si alguien dice "recuerda esto", escríbelo (no lo mantengas en RAM).
- Esta área aún está evolucionando. Es útil recordar al modelo que almacene memorias; sabrá qué hacer.
- Si quieres que algo persista, pide al bot que lo escriba en memoria.
Vaciado Automático de Memoria (Ping Pre-Compactación)
Cuando una sesión se acerca a la compactación automática, OpenClaw dispara un **turno
de Agente silencioso que recuerda al modelo que **escriba memoria duradera
antes de que'' el contexto se compacte. El prompt predeterminado establece explícitamente que el modelo _puede responder_,
pero usualmente ''NO_REPLY'' es la respuesta correcta, así que el usuario nunca ve este turno.
Esto se controla con ''agents.defaults.compaction.memoryFlush'':
{
agents: {
defaults: {
compaction: {
reserveTokensFloor: 20000,
memoryFlush: {
enabled: true,
softThresholdTokens: 4000,
systemPrompt: "Sesión acercándose a compactación. Almacena memorias duraderas ahora.",
prompt: "Escribe notas duraderas en memory/YYYY-MM-DD.md; responde con NO_REPLY si no hay nada que almacenar.",
},
},
},
},
}Detalles:
- Umbral suave: El vaciado se dispara cuando la estimación de tokens de la sesión excede
''contextWindow - reserveTokensFloor - softThresholdTokens''.
- ''Silencioso por defecto'': El prompt incluye ''NO_REPLY'', así que nada se entrega.
- Dos prompts: Prompt de usuario más prompt de sistema con el recordatorio adjunto.
- ''Un vaciado por ciclo de compactación'' (rastreado en ''sessions.json'').
- El espacio de trabajo debe ser escribible: Si la sesión corre en un sandbox con
''workspaceAccess: "ro"'' o ''"none"'', el vaciado se omite.
Para el ciclo de vida completo de compactación, ver
Búsqueda Vectorial de Memoria
OpenClaw puede construir un pequeño índice vectorial sobre ''MEMORY.md'' y ''memory/*.md'' (más
cualquier directorio o archivo extra que optes), para que consultas semánticas puedan encontrar notas
relevantes incluso cuando la redacción es diferente.
Predeterminados:
- Habilitado por defecto.
- Observa archivos de memoria por cambios (con debounce).
- Usa embeddings remotos por defecto. Si ''memorySearch.provider'' no está configurado, OpenClaw auto-selecciona:
1. ''local'' (si ''memorySearch.local.modelPath'' está configurado y el archivo existe).
2. ''openai'' si una clave OpenAI puede resolverse.
3. ''gemini'' si una clave Gemini puede resolverse.
4. De lo contrario, la búsqueda de memoria permanece deshabilitada hasta configurarse.
- El modo local usa node-llama-cpp y puede requerir ''pnpm approve-builds''.
- Usa sqlite-vec (si disponible) para acelerar la búsqueda vectorial dentro de SQLite.
Los embeddings remotos requieren una clave API para el proveedor de embeddings. OpenClaw
resuelve claves de perfiles de auth, ''models.providers.*.apiKey'', o variables
#
Rutas de Memoria Adicionales
Si quieres indexar archivos Markdown fuera del diseño predeterminado del espacio de trabajo, añade
agents: {
defaults: {
memorySearch: {
extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
}
}
}rutas explícitas:
Notas:
- Las rutas pueden ser absolutas o relativas al espacio de trabajo.
- Escanea directorios recursivamente por archivos ''.md''.
#
Embeddings de Gemini (Nativo)
Configura el proveedor en ''gemini'' para usar la API de embeddings de Gemini directamente:
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-001",
remote: {
apiKey: "TU_GEMINI_API_KEY"
}
}
}
}Notas:
- ''remote.baseUrl'' es opcional (por defecto la URL base de la API de Gemini).
- ''remote.headers'' te permite añadir headers extra según necesites.
- Modelo predeterminado: ''gemini-embedding-001''.
Si quieres usar un endpoint personalizado compatible con OpenAI (OpenRouter, vLLM, o un proxy),
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.ejemplo.com/v1/",
apiKey: "TU_OPENAI_COMPAT_API_KEY",
headers: { "X-Custom-Header": "valor" }
}
}
}
}puedes usar la configuración ''remote'' con el proveedor OpenAI:
Si no quieres configurar una clave API, usa ''memorySearch.provider = "local"'' o configura
''memorySearch.fallback = "none"''.
Fallback:
- ''memorySearch.fallback'' puede ser ''openai'', ''gemini'', ''local'', o ''none''.
- El proveedor de fallback solo se usa si el proveedor de embeddings primario falla.
Indexación por Lotes (OpenAI + Gemini):
- Los embeddings de OpenAI y Gemini están habilitados por defecto. Configura ''agents.defaults.memorySearch.remote.batch.enabled = false'' para deshabilitar.
- El comportamiento predeterminado espera la completación del lote; ajusta ''remote.batch.wait'', ''remote.batch.pollIntervalMs'', y ''remote.batch.timeoutMinutes'' si es necesario.
- Configura ''remote.batch.concurrency'' para controlar cuántos trabajos en lote enviamos en paralelo (predeterminado: 2).
- El modo lote funciona con ''memorySearch.provider = "openai"'' o ''"gemini"'' y usa la clave API correspondiente.
- Los trabajos en lote de Gemini usan el endpoint de lote de embeddings asíncrono y requieren disponibilidad de Gemini Batch API.
Por qué OpenAI Batch es rápido y económico:
- Para reindexaciones grandes, OpenAI es a menudo nuestra opción más rápida porque podemos enviar muchas solicitudes de embeddings en un solo trabajo en lote y dejar que OpenAI las procese asíncronamente.
- OpenAI ofrece precios con descuento para cargas de trabajo de Batch API, así que las grandes ejecuciones de índice son a menudo más económicas que enviar las mismas solicitudes sincrónicamente.
Cómo Funcionan las Herramientas de Memoria
- ''memory_search'' busca fragmentos Markdown de ''MEMORY.md'' + ''memory/**/*.md'' semánticamente (~400 tokens objetivo, 80 tokens de superposición). Devuelve texto del fragmento (limitado a 700 caracteres), ruta del archivo, rango de líneas, puntuación, proveedor/modelo, y si caímos de embedding local → remoto. No devuelve el payload completo del archivo.
- ''memory_get'' lee un archivo Markdown de memoria específico (relativo al espacio de trabajo), opcionalmente leyendo N líneas comenzando desde una línea de inicio. Rutas fuera de ''MEMORY.md'' / ''memory/'' solo se permiten si están explícitamente listadas en ''memorySearch.extraPaths''.
- Ambas herramientas solo están habilitadas si ''memorySearch.enabled'' del agente resuelve a true.
#
Qué Se Indexa (y Cuándo)
- Tipos de archivo: Solo Markdown (''MEMORY.md'', ''memory/**/*.md'', y cualquier archivo ''.md'' bajo ''memorySearch.extraPaths'').
- Almacenamiento del índice: SQLite por agente en ''~/.openclaw/memory/<agentId>.sqlite'' (configurable via ''agents.defaults.memorySearch.store.path'', soporta token ''{agentId}'').
- Frescura: Observadores en ''MEMORY.md'', ''memory/'', y ''memorySearch.extraPaths'' marcan el índice como sucio (debounce 1.5s). La sincronización se programa al inicio de sesión, en búsqueda, o a intervalos, y corre asíncronamente. Las transcripciones de sesión usan umbrales delta para disparar sincronización en segundo plano.
- Disparadores de re-indexación: El índice almacena proveedor/modelo de embedding + huella del endpoint + parámetros de fragmentación. Si cualquiera de estos cambia, OpenClaw automáticamente reinicia todo el almacén y re-indexa.
#
Búsqueda Híbrida (BM25 + Vector)
Cuando está habilitado, OpenClaw combina:
- Similitud vectorial (coincidencia semántica, la redacción puede diferir)
- Relevancia de palabras clave BM25 (tokens exactos como IDs, variables de entorno, símbolos de código)
Si la búsqueda de texto completo no es soportada en tu plataforma, OpenClaw recurre a búsqueda vectorial pura.
##
¿Por Qué Híbrido?
La búsqueda vectorial es buena en "esto significa lo mismo":
- "host gateway Mac Studio" vs "computadora ejecutando gateway"
- "debounce actualizaciones de archivo" vs "evitar indexar en cada escritura"
Pero puede ser débil en tokens precisos de alta señal:
- IDs (''a828e60'', ''b3b9895a…'')
- Símbolos de código (''memorySearch.query.hybrid'')
- Strings de error ("sqlite-vec no disponible")
BM25 (texto completo) es lo opuesto: fuerte en tokens exactos, débil en paráfrasis.
La búsqueda híbrida es un punto medio pragmático: usa ambas señales de recuperación para que obtengas
buenos resultados tanto para consultas de "lenguaje natural" como consultas de "aguja en un pajar".
##
Cómo Fusionamos Resultados (Diseño Actual)
Bosquejo de implementación:
1. Recuperar pools de candidatos de ambos lados:
- ''Vector'': Top ''maxResults * candidateMultiplier'' por similitud de coseno.
- ''BM25'': Top ''maxResults * candidateMultiplier'' por rango FTS5 BM25 (menor es mejor).
2. Convertir rango BM25 a un puntaje ~0..1:
- ''textScore = 1 / (1 + max(0, bm25Rank))''
3. Unir candidatos por chunk id y computar puntaje ponderado:
- ''finalScore = vectorWeight * vectorScore + textWeight * textScore''
Notas:
- ''vectorWeight'' + ''textWeight'' se normalizan a 1.0 en resolución de config, así que los pesos se comportan como porcentajes.
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
enabled: true,
vectorWeight: 0.7,
textWeight: 0.3,
candidateMultiplier: 4
}
}
}
}
}#
Caché de Embeddings
OpenClaw puede cachear embeddings de chunks en SQLite, para que re-indexar y actualizaciones frecuentes (especialmente transcripciones de sesión) no re-embeddeen texto sin cambios.
Configuración:
agents: {
defaults: {
memorySearch: {
cache: {
enabled: true,
maxEntries: 50000
}
}
}
}#
Búsqueda de Memoria de Sesión (Experimental)
Puedes optar por indexar ''transcripciones de sesión'' y mostrarlas vía ''memory_search''.
Esto está detrás de un flag experimental.
agents: {
defaults: {
memorySearch: {
experimental: { sessionMemory: true },
sources: ["memory", "sessions"]
}
}
}Notas:
- Indexación de sesión es opt-in (desactivada por defecto).
- Actualizaciones de sesión tienen debounce y se indexan asincrónicamente una vez exceden un umbral delta (best effort).
- ''memory_search'' nunca bloquea en indexación; los resultados pueden estar ligeramente desactualizados hasta que el sync en background complete.
- Los resultados aún solo contienen snippets; ''memory_get'' aún está limitado a archivos de memoria.
- Índices de sesión están aislados por agente (solo indexa logs de sesión de ese agente).
- Logs de sesión se almacenan en disco (''~/.openclaw/agents/<agentId>/sessions/*.jsonl''). Cualquier proceso/usuario con acceso al filesystem puede leerlos, así que trata el acceso a disco como un límite de confianza. Para aislamiento más estricto, ejecuta agentes bajo usuarios de OS separados o hosts.
agents: {
defaults: {
memorySearch: {
sync: {
sessions: {
deltaBytes: 100000, // ~100 KB
deltaMessages: 50 // JSONL lines
}
}
}
}
}#
Aceleración Vectorial SQLite (sqlite-vec)
Cuando la extensión sqlite-vec está disponible, OpenClaw almacena embeddings en
tablas virtuales de SQLite (''vec0'') y realiza consultas de distancia vectorial
dentro de la base de datos. Esto mantiene la búsqueda rápida sin cargar cada embedding en JS.
agents: {
defaults: {
memorySearch: {
store: {
vector: {
enabled: true,
extensionPath: "/path/to/sqlite-vec"
}
}
}
}
}Configuración (opcional):
Notas:
- ''enabled'' por defecto es true; cuando está deshabilitado, la búsqueda recurre a similitud de coseno
en proceso sobre embeddings almacenados.
#
Auto-Descarga de Embedding Local
- Modelo de embedding local predeterminado: ''hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf'' (~0.6 GB).
- Cuando ''memorySearch.provider = "local"'', ''node-llama-cpp'' resuelve ''modelPath''; si falta el GGUF, ''lo auto-descarga'' al caché (o ''local.modelCacheDir'' si está establecido), luego lo carga. Las descargas se reanudan en reintento.
- Requisito de build local: Ejecuta ''pnpm approve-builds'', selecciona ''node-llama-cpp'', luego ''pnpm rebuild node-llama-cpp''.
- Fallback: Si la configuración local falla y ''memorySearch.fallback = "openai"'', cambiamos automáticamente a embeddings remotos (''openai/text-embedding-3-small'' a menos que se anule) y registramos la razón.
#
Ejemplo de Endpoint Compatible con OpenAI Personalizado
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.example.com/v1/",
apiKey: "YOUR_REMOTE_API_KEY",
headers: {
"X-Organization": "org-id",
"X-Project": "project-id"
}
}
}
}
}Notas:
- ''remote.*'' toma precedencia sobre ''models.providers.openai.*''.
- ''remote.headers'' se fusiona con headers de OpenAI; remote gana en conflictos de claves. Omite ''remote.headers'' para usar valores predeterminados de OpenAI.