• entaina
  • Posts
  • llmemory: memoria persistente para agentes LLM en Ruby

llmemory: memoria persistente para agentes LLM en Ruby

Los modelos de lenguaje tienen un problema de fábrica: amnesia. Cada llamada a la API empieza de cero. Si quieres que tu agente recuerde que el usuario es vegano, que trabaja en Acme o que la semana pasada resolvió un problema parecido, tienes que construir esa memoria tú mismo. Eso es exactamente lo que hace llmemory, una gema Ruby que da a tus agentes una memoria completa: a corto plazo, a largo plazo y —lo más interesante— cognitiva.

La idea en 30 segundos

memory = Llmemory::Memory.new(user_id: "user_123", session_id: "conv_456")

memory.add_message(role: :user, content: "Soy vegano y trabajo en Acme")
memory.add_message(role: :assistant, content: "Entendido, lo recordaré")

# Consolida la conversación en memoria a largo plazo (extrae hechos con el LLM)
memory.consolidate!

# En la siguiente sesión, días después:
context = memory.retrieve("¿Qué preferencias alimentarias tiene el usuario?")
# => contexto listo para inyectar en tu prompt

Una única API (Llmemory::Memory) orquesta todo: el historial de conversación se guarda como checkpoints (memoria a corto plazo), un extractor basado en LLM destila hechos hacia la memoria a largo plazo, y la recuperación combina ambas fuentes en un contexto formateado y acotado por tokens.

Dos formas de recordar: hechos o grafo de conocimiento

La memoria a largo plazo tiene dos sabores:

  • File-based (por defecto): hechos planos organizados en categorías y recursos. Simple y suficiente para la mayoría de chatbots.

  • Graph-based: un grafo de conocimiento con entidades y relaciones sujeto–predicado–objeto (User —works_at→ Acme), combinado con embeddings vectoriales. La recuperación es híbrida: búsqueda semántica + recorrido del grafo desde los nodos encontrados. Incluye resolución de conflictos: si el usuario cambia de empresa, el predicado exclusivo works_at archiva el valor anterior en vez de acumular contradicciones.

Memoria cognitiva: el patrón CoALA

Aquí es donde llmemory va más allá del típico "RAG sobre conversaciones". Implementa la arquitectura de memoria del paper CoALA (Cognitive Architectures for Language Agents):

  • Memoria de trabajo (WorkingMemory): un espacio simbólico estructurado (objetivos, tarea actual, slots arbitrarios) que persiste entre llamadas al LLM, separado del buffer de mensajes.

  • Memoria episódica: trayectorias de experiencia completas (observación → acción → resultado), al estilo de los agentes que aprenden de lo que les pasó.

  • Memoria procedural: una biblioteca de skills (prompts, plantillas, código) inspirada en Voyager, con versionado automático y tasa de éxito/fracaso que alimenta el ranking de recuperación.

  • Reflexión: un Reflector destila episodios recientes en insights semánticos (patrón Reflexion / Generative Agents), con trazabilidad hacia los episodios de origen.

  • Skill mining: extrae automáticamente procedimientos reutilizables de los episodios y los registra como skills.

Un solo método, memory.cognitive_maintain!, cierra el ciclo completo: consolida, reflexiona, mina skills y expira lo caducado.

Recuperación que entiende el tiempo (y aprende)

Recuperar memoria no es solo buscar: llmemory aplica decaimiento temporal (media vida configurable: lo de hace tres meses pesa menos que lo de ayer), importancia, búsqueda híbrida BM25 + vectores con re-ranking MMR opcional, y un bucle de feedback adaptativo — marca una memoria recuperada como útil o dañina y los siguientes rankings se ajustan. También hay recuperación iterativa multi-hop: el LLM propone consultas de seguimiento hasta cubrir la pregunta.

Preparado para producción

  • Backends conectables:memory, Redis, PostgreSQL o ActiveRecord (con generador de migraciones para Rails y pgvector para embeddings).

  • Cifrado en reposo AES-256-GCM opcional, con clave global o por instancia — aislar tenants o agentes criptográficamente es una línea de código.

  • Contabilidad de tokens real: captura los contadores de las respuestas de OpenAI y Anthropic (chat y embeddings) y los acumula por usuario. memory.llm_usage te dice cuánto te está costando la memoria de cada usuario.

  • Gestión de contextoflush de memoria antes de compactar (no se pierde conocimiento al resumir), poda de resultados de herramientas, seguimiento de la ventana de contexto y auto-consolidación al superar umbrales.

  • Olvido auditadoforget elimina memorias y deja constancia en un ForgetLog — porque "borra lo que sabes de mí" también hay que poder demostrarlo.

  • Trazabilidad (provenance): cada hecho, nodo o insight sabe de dónde salió, con qué método y con qué confianza.

Inspección e integración

  • CLIllmemory stats USER_ID para ver qué recuerda el sistema (y cuántos tokens ha gastado).

  • Dashboard Rails opcional para explorar la memoria desde el navegador.

  • Servidor MCP (Model Context Protocol) con transporte stdio y HTTP/HTTPS con autenticación: cualquier agente compatible con MCP — Claude Code incluido — puede leer y escribir memoria como herramientas nativas.

En resumen

llmemory convierte "mi bot no se acuerda de nada" en un problema resuelto con una gema: add_messageconsolidate!retrieve — y por debajo, una arquitectura cognitiva completa con grafo de conocimiento, memoria episódica y procedural, cifrado, y control de costes. Si construyes agentes LLM en Ruby, es la pieza de memoria que no tienes que volver a escribir.

gem "llmemory"