Dale a Hermes Agent una memoria semántica con LanceDB: instala, configura y evalúa

Una de las experiencias más frustrantes con un agente de IA es que olvida. El lunes le dices: «uso pnpm workspaces y despliego con wrangler». El viernes, en una sesión nueva, no tiene ni idea de lo que le hablas. Hermes Agent sí tiene memoria integrada (MEMORY.md / USER.md en ~/.hermes/memories/) y recall entre sesiones, pero en el fondo es coincidencia léxica. Di «deploy» como «ship it», o «pnpm» como «the package manager», y la memoria simplemente no aparece.
En agosto de 2026, LanceDB publicó un plugin oficial de memoria semántica para Hermes Agent — hermes-agent-memory — que convierte esto en un problema puramente de ingeniería: los hechos se guardan como vectores en una tabla local de LanceDB y el recall se basa en la similitud semántica en lugar de las palabras clave. En el benchmark LongMemEval del plugin, el recall puramente vectorial consigue una precisión de 0.661 y un Recall@5 de 0.795, claramente por delante de la búsqueda de sesión FTS5 integrada de Hermes, con 0.533 / 0.659.
Esta publicación te guía por la instalación completa, explica cómo funcionan las cuatro herramientas de memoria, cómo elegir entre los modos de recuperación híbrida y analiza con cuidado las cifras del benchmark.
1. Primero, entiende la arquitectura de memoria de Hermes
Antes de instalar nada, dedica dos minutos a entender cómo está diseñada la capa de memoria de Hermes; de lo contrario, puedes instalarlo todo y preguntarte por qué no funciona nada.
La memoria de Hermes es una arquitectura de providers. agent/memory_provider.py define una interfaz abstracta MemoryProvider, y agent/memory_manager.py la orquesta (prefetch, sync, shutdown). Dos hooks importan sobre todo:
on_pre_compress(messages)— extrae lo que merece la pena conservar antes de que se ejecute la compresión de contexto;on_session_end(messages)— una última pasada de extracción al final de la sesión.
El comando interactivo hermes memory setup escanea los providers instalados en plugins/memory/, te deja elegir uno y escribe memory.provider: <name> en ~/.hermes/config.yaml (la línea 277 de hermes_cli/memory_setup.py es exactamente esa escritura). En otras palabras: el backend de memoria es un registro de providers conectables. De serie, Hermes trae ocho providers: mem0, hindsight, honcho, supermemory, byterover, retaindb, holographic y openviking.
El plugin de LanceDB usa el mismo canal: se registra como memory provider, se instala en ~/.hermes/plugins/lancedb/ mediante hermes plugins install y luego se selecciona en hermes memory setup.
¿Quieres probarlo sin tocar tu configuración actual?
hermes profile create lancedb-democrea un perfil aislado; añade-p lancedb-demoa cada comando de abajo y ejecutarm -rf ~/.hermes/profiles/lancedb-democuando termines.
2. Instalación: cuatro pasos, unos cinco minutos
Paso 1: instala el plugin
hermes plugins install lancedb/hermes-agent-memory
Esto hace un shallow clone de https://github.com/lancedb/hermes-agent-memory.git en ~/.hermes/plugins/lancedb/. Vuelve a ejecutar el mismo comando más adelante para actualizarlo.
Paso 2: instala las dependencias de ejecución en el Python propio de Hermes
Hermes carga los plugins dentro de su propio intérprete, así que las dependencias deben ir al venv de Hermes, no a un virtualenv aparte:
# If you used the one-line installer:
uv pip install --python ~/.hermes/hermes-agent/venv/bin/python3 lancedb openai pyyaml
Nota: el intérprete de Hermes es compartido por todos los perfiles, así que este paso no lleva la bandera
-py solo hay que ejecutarlo una vez. La configuración por defecto no necesita ningún stack de ML local: los embeddings pasan por la API de OpenAI. Solo si activas el reranker cross-encoder necesitarássentence-transformers(que arrastra unos 2GB de torch).
Paso 3: activa el provider
hermes memory setup
# pick "lancedb" in the interactive menu
Espera una salida como esta, y memory.provider: lancedb escrito en ~/.hermes/config.yaml:
# ✓ LanceDB memory configured (embedding dim: 1536)
# Start a new session to activate.
Por defecto, los embeddings usan OpenAI text-embedding-3-small (1536 dimensiones), así que debe haber una OPENAI_API_KEY disponible.
Paso 4: verifica (no te lo saltes)
El informe de «la memoria no funciona» más común es, simplemente, que el provider no está activo: si memory.provider no está definido, Hermes recurre silenciosamente a sus notas integradas y nunca verás las herramientas lancedb_*. Confirma que está activado:
hermes memory status # look for: Provider: lancedb, installed ✓, available ✓
hermes plugins list # should list "lancedb"
hermes chat -q "Hello" # agent.log should contain "lancedb provider initialized"
Si memory status no muestra nada (o muestra el provider equivocado), vuelve a ejecutar hermes memory setup y elige lancedb de nuevo.
3. Las cuatro herramientas de memoria
Una vez activo, el agente gana cuatro herramientas nuevas:
| Herramienta | Propósito |
|---|---|
lancedb_recall |
Recall vectorial (por defecto) o híbrido sobre la memoria del workspace; devuelve IDs, fragmentos, puntuaciones e IDs de turno de procedencia |
lancedb_remember |
Guarda un hecho duradero, con tipo preference / entity / event / case / pattern / general; deduplicado por hash de contenido |
lancedb_read |
Recupera una memoria por ID, opcionalmente con los turnos de procedencia de los que se extrajo |
lancedb_forget |
Borrado en dos pasos: action: preview lista los candidatos por descripción y luego action: delete con el ID exacto |
El bloque de system prompt del provider indica al modelo cuándo usar cada herramienta: lancedb_remember solo cuando el usuario pide explícitamente recordar algo, y siempre preview antes de cualquier borrado, para que el agente no pueda eliminar una memoria importante por accidente.
Más allá de las llamadas explícitas, hay un pipeline de extracción automática: cuando una sesión acumula suficientes turnos (por defecto min_turns: 3), un LLM auxiliar extrae los hechos duraderos de la conversación, tanto antes de la compresión de contexto como al final de la sesión. Aunque nunca digas «recuerda esto», la información útil a largo plazo se sigue guardando: ese es el mecanismo de «cuanto más lo usas, más listo se vuelve el agente».
4. Modos de recuperación: vector vs híbrido
El recall es el corazón de la memoria semántica, y el plugin te da dos niveles de control:
1. Modo de búsqueda (por llamada): vector (por defecto) o hybrid (vector + texto completo BM25); se sobreescribe en cada llamada mediante el parámetro mode de lancedb_recall.
2. Fusión híbrida (configuración global): en modo hybrid, cómo se combinan la parte vectorial y la de texto completo lo define plugins.lancedb.retrieval.reranker.type:
rrf(por defecto) — Reciprocal Rank Fusion, fusión por rango con pesos iguales;linear— combinación lineal ponderada;reranker.weight(por defecto 0.7) favorece la parte vectorial;cross-encoder— reordena un pool sobremuestreado con un modelo local de sentence-transformers; máxima calidad, más lento.
Ejemplo de configuración (~/.hermes/config.yaml; escribe solo las claves que quieras sobreescribir):
plugins:
lancedb:
retrieval:
mode: hybrid # vector (default) | hybrid
top_k: 10
reranker:
type: linear # rrf | linear | cross-encoder
weight: 0.7
También existe un modo puramente léxico
fts, pero los autores desaconsejan explícitamente usarlo: la coincidencia solo por palabras clave tiende a sacar filas irrelevantes y casuales que contaminan el contexto del agente. El recall semántico vive envector/hybrid.
5. Backends de embeddings: no solo OpenAI
En la configuración por defecto, la única llamada remota es la API de embeddings; todo lo demás es local. Apunta el cliente compatible con OpenAI a cualquier endpoint que hable el mismo formato y listo, sin cambios de código. Algunos ejemplos prácticos:
# Non-OpenAI model via OpenRouter
plugins:
lancedb:
embedding:
model: google/gemini-embedding-001
base_url: https://openrouter.ai/api/v1
api_key_env: OPENROUTER_API_KEY
# Fully local: Ollama
plugins:
lancedb:
embedding:
model: nomic-embed-text
base_url: http://localhost:11434/v1
api_key_env: OLLAMA_API_KEY # any value works for local Ollama
Cambiar de modelo de embeddings requiere cuidado: si la dimensión del nuevo modelo no coincide con la tabla existente, el plugin falla de forma ruidosa en lugar de devolver silenciosamente nada. La solución es borrar ~/.hermes/lancedb/memories.lance/ y dejar que la siguiente sesión vuelva a crear la tabla (perfecto si no te importan las memorias antiguas).
El LLM auxiliar que se usa para extraer hechos también puede apuntar a un modelo más barato, a través del enrutamiento auxiliar propio de Hermes (el enrutamiento de providers, el fallback y el agotamiento de crédito los gestiona por ti):
auxiliary:
lancedb_extraction:
provider: openrouter
model: google/gemini-3-flash
6. Cómo leer el benchmark: ¿es realmente mejor el recall semántico?
El repositorio del plugin trae un banco de pruebas de QA de conversaciones largas LongMemEval-S (60 casos estratificados, respondidos por gpt-5.4 y evaluados por gpt-5.4-mini, top-k 5). Compara las opciones de recall que tiene realmente un usuario de Hermes:
| Variante | Accuracy | Recall@5 | MRR@5 | Query p50 |
|---|---|---|---|---|
| hermes-session-search (baseline FTS5/BM25 integrado) | 0.533 | 0.659 | 0.639 | 0.002s |
| lancedb-vector (por defecto) | 0.661 | 0.795 | 0.682 | 0.207s |
| lancedb-hybrid-rrf | 0.610 | 0.650 | 0.635 | 0.235s |
| lancedb-hybrid-linear | 0.610 | 0.718 | 0.676 | 0.246s |
| lancedb-hybrid-cross-encoder | 0.678 | 0.754 | 0.689 | 0.702s |
Conclusiones destacables:
- El recall semántico gana claramente a la línea base léxica: 0.661 frente a 0.533 de precisión y 0.795 frente a 0.659 de Recall@5; la paráfrasis (deploy vs ship) es justo donde BM25 se queda ciego, y la recuperación vectorial es mucho más robusta, con ~0.2s por consulta.
- El RRF con pesos iguales en realidad perjudica (0.610 < 0.661): los aciertos léxicos ruidosos desplazan a los buenos resultados vectoriales. Por eso el valor por defecto que se distribuye es
vector, nohybrid. - Si quieres señal léxica, usa
linear, no RRF: la fusión ponderada recupera el Recall@5 hasta 0.718 con un coste de latencia mínimo. - El cross-encoder lidera en calidad (0.678 / 0.754), pero el p50 sube a ~0.7s y necesita torch: para entornos tolerantes a la latencia y sensibles a la precisión.
Los autores las etiquetan como ilustrativas: la precisión absoluta depende del modelo que responde (aquí gpt-5.4), pero el orden relativo de los métodos de recuperación es estable. Además, el banco de pruebas solo mide el sustrato de recuperación (recall literal de los turnos originales), no el ciclo completo de extracción de hechos: en uso real, la recuperación basada en hechos puede funcionar incluso mejor.
7. Estructura de almacenamiento y compactación automática
Todo es local, sin servicios externos:
| Ruta | Contenido |
|---|---|
~/.hermes/lancedb/memories.lance/ |
LanceDB dataset (fragments, manifest, indexes). Una única tabla memories; la columna kind separa las filas de hechos y de turnos |
~/.hermes/lancedb/.last_optimize_version |
Archivo centinela: table.version en el último optimize() con éxito |
~/.cache/huggingface/ |
Caché del reranker cross-encoder; solo presente cuando reranker.type: cross-encoder está activado |
¿Quieres inspeccionar el almacén directamente, estilo SQL?
uv run --project ~/.hermes/hermes-agent python -c "
import lancedb
db = lancedb.connect('~/.hermes/lancedb')
df = db.open_table('memories').to_pandas()
print(df[['kind', 'category', 'content']].head())
"
Las cargas de trabajo de los agentes están dominadas por escrituras de una sola fila, y cada add/delete de Lance es un commit: sin intervención, los fragmentos diminutos y los archivos de versión se acumulan para siempre. La compactación automática del plugin (activada por defecto) compara la versión con el archivo centinela y ejecuta table.optimize(cleanup_older_than=timedelta(days=7)) en un hilo daemon cuando el delta supera optimize_every_commits (por defecto 50). Un lock no bloqueante garantiza un solo optimize a la vez y nunca bloquea a los escritores. Si la desactivas (maintenance.enabled: false), el dataset crece sin límite; por lo general, no se recomienda.
8. Referencia rápida de solución de problemas
hermes plugins listno muestralancedb: comprueba que el symlink~/.hermes/plugins/lancedbapunta al repositorio.- El agente solo escribe en la memoria integrada, sin herramientas
lancedb_*: el provider no está activo. Ejecutahermes memory status; quieres verProvider: lancedbconavailable ✓; si está en blanco, vuelve a ejecutarhermes memory setup. - El recall falla con un error de autenticación: los embeddings llaman a la API de OpenAI; asegúrate de que
OPENAI_API_KEYestá definida (en el entorno o en~/.hermes/.env). - El directorio
.lanceno deja de crecer: confirma quemaintenance.enabled: truey que~/.hermes/lancedb/.last_optimize_versionavanza entre sesiones; si enagent.logaparecelancedb optimize starting, la compactación está en marcha. - Cambiaste
embedding.modely el recall no devuelve nada: hay un desajuste de dimensiones. Borra~/.hermes/lancedb/memories.lance/para recrear la tabla.
Recapitulación
El plugin de LanceDB cubre la laguna más importante de la memoria a largo plazo de Hermes Agent: recuperar por significado, no por palabras clave. Cinco minutos de instalación, cero ajustes sobre los valores por defecto y todos los datos en local, a cambio de una precisión ~24% mejor (0.661 frente a 0.533) y un gran salto en Recall@5 en LongMemEval. Para quienes trabajan con conocimiento, significa que «lo que le contaste una vez vuelve a aparecer aunque lo preguntes de otra forma».
Lecturas relacionadas:
- ¿Quieres tus memorias destiladas en una base de conocimiento legible? Consulta cómo convertir conversaciones de Hermes en notas de Obsidian.
- Los almacenes de memoria también crecen: gestiona sesiones y espacio en disco con la guía de optimización de almacenamiento de Hermes.
- Más consejos del día a día para sacarle el máximo partido a tu agente: consejos de productividad de Hermes Agent.
- ¿Aún no has instalado Hermes? Empieza por la guía de instalación.