Ilustración técnica para: Dale memoria a tu agente de IA sin inflar el contexto

Dale memoria a tu agente de IA sin inflar el contexto


TL;DR: La memoria de un agente es el almacenamiento externo que le deja recordar decisiones y hechos entre sesiones, en vez de empezar de cero cada vez. La clave no es guardarlo todo, sino persistir hechos estables y recuperar por relevancia. En este artículo verás los tipos de memoria (corto vs largo plazo, episódica, semántica, procedimental), el patrón mínimo reproducible (capturar, recuperar, podar) con código funcional usando Mem0 y el store de LangGraph, y qué cambia cuando esto va a producción: coste, latencia y el riesgo real de memoria contaminada.

El problema: tu agente tiene amnesia anterógrada

Un agente sin memoria es un buen empleado con amnesia: cada mañana le explicas el proyecto entero y por la tarde lo ha olvidado. Le dices que prefieres Python sobre Java, que el repo usa arquitectura hexagonal, que ya descartasteis una librería por licencia. Mañana, nada. Vuelve a preguntar lo mismo.

Esto pasa porque, por defecto, un LLM solo "ve" lo que cabe en su ventana de contexto durante una invocación. Cuando la sesión termina, ese estado se evapora. La memoria de agentes (en inglés, agent memory) es lo que separa un chatbot de un agente útil: el almacenamiento persistente y consultable que sobrevive entre ejecuciones.

El error que veo repetido (y que yo mismo cometí al principio) es resolverlo a lo bruto: volcar todo el historial de conversación en cada prompt. Funciona en la demo. En producción te come el presupuesto, dispara la latencia y, a partir de cierto tamaño, confunde al modelo. Como ya expliqué al hablar de cómo cruzar los 200k tokens te vacía el presupuesto, más contexto no es gratis ni siempre mejor.

¿Qué es la memoria de un agente?

La memoria de un agente es un sistema externo que codifica, almacena y recupera de forma selectiva información de interacciones pasadas, para que el agente mantenga continuidad y adapte su comportamiento sin reentrenar el modelo. No es la ventana de contexto (eso es memoria de trabajo, volátil) ni los pesos del modelo (eso es conocimiento congelado en el entrenamiento).

Conviene separar dos ejes. El primero es el horizonte temporal:

  • Memoria a corto plazo: el contexto de la sesión actual. Turnos recientes, estado de la tarea en curso. Vive en la ventana de contexto y muere al cerrar.
  • Memoria a largo plazo: almacenamiento durable fuera del contexto. Persiste entre sesiones y se recupera bajo demanda.

El segundo eje, dentro del largo plazo, es el tipo de información. La taxonomía que se ha estandarizado en 2026 viene de la ciencia cognitiva:

TipoQué guardaEjemplo en un agente de código
EpisódicaEventos y secuencias concretas, con marca temporal"El 14/06 desplegamos a GKE y falló por el límite de memoria del pod"
SemánticaHechos y conceptos estables sobre el mundo o el usuario"El proyecto usa FastAPI y Pinecone como vector DB"
ProcedimentalFlujos y habilidades aprendidas, el "cómo se hace""Para releases, primero corre los tests de integración, luego tag semver"

Para un dev junior, quédate con esto: la episódica es tu diario ("qué pasó y cuándo"), la semántica es tu libreta de hechos ("qué es verdad"), y la procedimental es tu manual de procedimientos ("cómo se hacen las cosas aquí").

Qué guardar de verdad (y qué no)

La regla operativa: persiste hechos estables y decisiones, no el historial crudo entero. Guardar cada token de cada conversación es la forma más rápida de tener una memoria cara, lenta y ruidosa.

Mi heurística después de meses montando esto en sistemas reales:

  • Guarda: preferencias del usuario, decisiones tomadas y su razón, restricciones del proyecto, hechos que rara vez cambian.
  • No guardes: el chit-chat, los pasos intermedios de razonamiento, datos que puedes recalcular, información sensible sin necesidad.
  • Recupera por relevancia, no por volumen: trae los 3-5 recuerdos pertinentes a la tarea actual, no el dump completo. Esto controla coste y latencia a la vez.

El paso de extracción es donde un buen sistema de memoria gana al "guardar todo". En lugar de almacenar el mensaje literal, un LLM destila el hecho: de "uy, pues la verdad es que prefiero que me respondas en español y con ejemplos cortos" sale el hecho estable "el usuario prefiere respuestas en español con ejemplos cortos".

Cómo se guarda: vector, clave-valor o grafo

Hay tres sustratos de almacenamiento, y la elección no es cosmética:

  • Clave-valor / documento: simple y barato. Ideal para perfiles de usuario y hechos estructurados. Recuperas por clave exacta, no por significado.
  • Vectorial (embeddings): guardas el hecho como vector y recuperas por similitud semántica. Es la base de la memoria semántica. Si esto te suena a RAG, es porque comparte la maquinaria: misma lógica de chunking y embeddings que en un pipeline de datos.
  • Grafo de conocimiento: modela entidades y relaciones ("Sergio trabaja en VITALY", "VITALY usa Pinecone"). Brilla cuando necesitas razonar sobre conexiones, en la línea de lo que vimos con el knowledge graph de tu código.

En la práctica, los sistemas serios combinan varios. El truco de recuperación que más rinde es el mismo que en búsqueda híbrida en RAG: fusionar similitud vectorial, BM25 (keyword) y matching de entidades en una sola puntuación. La memoria de un agente, al final, es RAG sobre tus propias interacciones.

El patrón mínimo reproducible: capturar, recuperar, podar

Tres operaciones bastan para una memoria útil: captura al cerrar una tarea, recupera al abrir la siguiente, y poda para que no crezca sin control. Vamos con código funcional.

El camino más corto en Python es Mem0 (Apache 2.0, framework-agnóstico). Instalación:

# Instala el SDK; necesita una API key de LLM para extraer y embeber hechos
# pip install mem0ai
# export OPENAI_API_KEY="tu-api-key"

from mem0 import Memory

memory = Memory()  # por defecto usa un vector store local en memoria

Paso 1, capturar. Le pasas los mensajes y Mem0 extrae los hechos estables por ti, no guarda el texto crudo:

# add() destila hechos de la conversación y los asocia a un user_id
mensajes = [
    {"role": "user", "content": "Prefiero Python y respuestas en español, cortas."},
    {"role": "assistant", "content": "Anotado, lo tendré en cuenta."},
]
memory.add(mensajes, user_id="sergio")
# Output esperado: se almacena algo como
# "Prefiere Python" / "Prefiere respuestas en español y cortas"

Paso 2, recuperar. Al empezar una nueva tarea, traes solo lo relevante a la consulta actual:

# search() devuelve los recuerdos más pertinentes, no todo el historial
recuerdos = memory.search("¿En qué lenguaje respondo?", user_id="sergio", limit=3)
for r in recuerdos["results"]:
    print(r["memory"])  # -> "Prefiere Python", "Prefiere respuestas en español..."

Esos 3 recuerdos los inyectas en el system prompt de la siguiente llamada. Pasas de volcar 50 turnos a inyectar 3 hechos: ahí está el ahorro de tokens y latencia.

Paso 3, podar. Sin poda, la memoria crece hasta volverse ruido. La estrategia básica es decaimiento por relevancia y recencia: lo poco recuperado y antiguo, fuera.

# Poda simple: elimina recuerdos viejos y casi nunca recuperados
def podar(memory, user_id, dias_max=90, min_accesos=1):
    for m in memory.get_all(user_id=user_id)["results"]:
        viejo = m.get("age_days", 0) > dias_max
        ignorado = m.get("hits", 0) < min_accesos
        if viejo and ignorado:
            memory.delete(m["id"])  # libera espacio y reduce ruido

Este esquema captura-recupera-poda es agnóstico a la herramienta. Si trabajas con LangGraph, el patrón es idéntico pero con su Store: store.put((namespace,), key, valor) para guardar y store.search((namespace,), query=...) para recuperar, con persistencia en Postgres, Redis o MongoDB en vez de en memoria.

Comparativa: frameworks de memoria en 2026

Si no quieres montarlo a mano, el ecosistema maduró bastante. A junio de 2026, estas son las opciones que considero:

FrameworkAlmacenamientoCuándo usarloCuándo evitarlo
Mem0Vector + grafo (grafo solo en Pro)Caso general, mayor comunidad, SDK Python y TSNecesitas grafo gratis o reranking avanzado open-source
Letta (ex MemGPT)Por niveles, estilo SOQuieres un runtime completo con memoria auto-editableSolo quieres una librería ligera in-process
Zep / GraphitiGrafo temporalNecesitas saber cómo cambian los hechos en el tiempoTu caso no tiene dimensión temporal relevante
LangMemVectorYa usas LangGraph y quieres mínima fricciónNecesitas multi-framework o TypeScript

Mi recomendación honesta: para un proyecto pequeño o mediano, empieza con Mem0 o LangMem en su tier gratis. No saltes a una plataforma gestionada hasta que tengas evidencia de que la necesitas. Y mide el benchmark relevante: LoCoMo es el estándar de facto para evaluar recuerdo en conversaciones largas, pero como siempre, tu tarea no es la del benchmark.

En Producción

Aquí es donde el tutorial y la realidad se separan. Cuatro frentes que cambian todo:

Coste. Cada add() con extracción dispara una llamada al LLM, y cada search() calcula embeddings. No es gratis. En un proyecto personal con tráfico moderado, la memoria me ha supuesto entre 10 y 30 € al mes en APIs, casi todo en la extracción. Truco: no extraigas en cada turno, hazlo por lotes al cerrar la tarea. La captura no necesita ser síncrona.

Latencia. Recuperar memoria añade un salto antes de responder. Mantén el limit bajo (3-5 recuerdos) y cachea el perfil estable del usuario para no buscarlo en cada mensaje. La memoria a corto plazo va en contexto; solo bajas al store para lo de largo plazo.

Memoria contaminada (memory poisoning). Este es el riesgo serio y poco hablado. Si el agente guarda una alucinación o una inyección maliciosa como "hecho válido", la arrastra entre sesiones. A diferencia de un RAG estático, donde el error se aísla en una recuperación, en memoria evolutiva los errores son acumulativos y persistentes. Aparece también el drift semántico: resumir un hecho una y otra vez lo va distorsionando. Mitigación: separa un log episódico inmutable (la fuente de verdad cruda) de la capa semántica mutable, para poder reconciliar y revertir si el comportamiento se degrada.

Staleness (hechos caducados). "Sergio trabaja en VITALY" es cierto hasta que cambia de empleo, y entonces es confiadamente falso. El decaimiento maneja los recuerdos poco relevantes, pero la caducidad de hechos muy recuperados sigue siendo un problema abierto. Para datos con fecha de caducidad conocida, guárdala explícitamente y filtra al recuperar.

Errores comunes y depuración

  • Error: el agente no recupera lo que guardaste. Causa: la descripción del recuerdo es vaga y no matchea la query semántica. Solución: guarda hechos atómicos y específicos, no párrafos; un hecho por entrada.
  • Error: la factura de API se dispara. Causa: extraes memoria en cada turno y recuperas sin límite. Solución: captura por lotes al cerrar tarea y fija limit en la recuperación.
  • Error: el agente repite información obsoleta. Causa: staleness, el hecho viejo sigue puntuando alto. Solución: versiona hechos mutables con timestamp y prioriza el más reciente al recuperar.
  • Error: la memoria crece sin parar y la latencia sube. Causa: no hay poda. Solución: job periódico de decaimiento por relevancia y recencia.

Preguntas frecuentes

¿Memoria de agente es lo mismo que RAG?

Comparten la maquinaria (embeddings, vector store, recuperación), pero el propósito difiere. RAG recupera de un corpus externo estático de documentos; la memoria de un agente recupera de sus propias interacciones pasadas, que crecen y cambian con el uso. La memoria es, en esencia, RAG aplicado a tu historial con un paso extra de extracción y olvido.

¿Necesito una vector database para dar memoria a mi agente?

No siempre. Para hechos estructurados y perfiles de usuario, un store clave-valor o incluso ficheros en disco bastan y son más baratos. La vector DB la necesitas cuando quieres recuperación por significado sobre texto libre. Empieza simple y añade el vector store solo si la recuperación semántica te hace falta.

¿Cuánto cuesta montar memoria persistente en un proyecto pequeño?

El coste dominante es el LLM que extrae y embebe hechos. En proyectos pequeños o medianos, hablamos de un rango aproximado de 10 a 30 € al mes en APIs si capturas por lotes y limitas la recuperación. La infraestructura de almacenamiento (Redis, Postgres con pgvector) puede correr gratis en local o por unos pocos euros gestionada.

Cierre

Hemos visto que dar memoria a un agente no es guardarlo todo, sino capturar hechos estables, recuperarlos por relevancia y podar lo que sobra. El patrón mínimo capturar-recuperar-podar funciona igual con Mem0, con el store de LangGraph o montado a mano; lo que cambia en producción es el criterio: vigilar el coste de extracción, la latencia de recuperación y, sobre todo, evitar que una alucinación se convierta en un "hecho" que tu agente arrastre para siempre. La diferencia entre un chatbot que repite preguntas y un agente que recuerda tus decisiones está justo en esa capa.

¿Has montado memoria persistente en algún agente, a mano o con framework? ¿Te has topado con el problema de los hechos caducados o la memoria contaminada? Cuéntamelo en los comentarios o en Twitter @sergiomarquezp_. En el próximo artículo quiero bajar a tierra los agentes de horizonte largo: cómo sostienen una tarea de horas combinando memoria, sandbox y checkpoints sin perderse a mitad de camino.

Compartir X LinkedIn