Contacto

Gestión del contexto y memoria persistente

memoria

Gestión del contexto y memoria persistente

El problema

Un LLM responde al input y olvida todo cuando termina el turno. Para preguntas aisladas es suficiente. Para cualquier tarea que requiera continuidad no lo es.

Memory Management implementa una arquitectura doble, memoria a corto plazo dentro del context window, memoria a largo plazo en almacenamiento externo. La distinción no es cosmética. Cada capa tiene mecanismos de almacenamiento, lifetime, retrieval strategies y trade-offs distintos.

Pero el problema real no es «guardar datos». Es gestionar tres dimensiones concurrentes: qué guardar, cómo recuperarlo sin contaminar el contexto, y cuándo descartarlo. Gestionar mal cualquiera de esas dimensiones degrada el sistema, context overflow, information dilution, stale memory, retrieval failure.

Lo que es y lo que no es

Memory Management en agentes LLM no es un sistema de bases de datos. No es caching. No es session management de aplicaciones web tradicionales. Es un mecanismo para que un modelo probabilístico mantenga coherencia a través de interacciones discretas, sabiendo que cada interacción es independiente y que el modelo no «recuerda» nada por sí mismo.

La memoria no es una característica que se añade al final. Es una decisión arquitectónica que afecta el diseño del prompt, la estructura del estado, el retrieval, y la forma en que el modelo toma decisiones. Un sistema diseñado sin memoria desde el principio no la puede añadir después sin reescribir la arquitectura.

Memoria a corto plazo vs largo plazo

La separación refleja una tensión real: Acceso inmediato vs persistencia. La memoria de trabajo humana tiene capacidad limitada pero acceso directo. La memoria a largo plazo tiene capacidad amplia pero requiere retrieval activo. Los agentes LLM enfrentan la misma tensión.

Corto plazo: Vive dentro del context window. Es efímera, delimitada a una sesión, y se pierde cuando la sesión termina. Incluye historial de mensajes, estado actual de la tarea, y cualquier dato que el modelo necesita para su próxima decisión. El recurso limitante es el espacio, un context window de 128K tokens se agota más rápido de lo que parece cuando cargas system prompt, herramientas, historial y datos de contexto.

Largo plazo: Persiste entre sesiones. Vive en almacenamiento externo, vector databases, key-value stores, managed services. No está en el context window por defecto; debe ser llamada explícitamente. El recurso limitante es la precisión del retrieval, puedes almacenar terabytes, pero si el retrieval no encuentra lo relevante, la memoria es inútil. Y si encuentra información irrelevante, contamina el contexto.

Tipos de memoria: Taxonomía, no arquitectura

La literatura distingue tres tipos de memoria. Es una taxonomía útil, no una separación técnica estricta. En producción, todo converge en «memory store + retrieval + heuristics». La distinción ayuda a pensar en qué tipo de información necesitas guardar y cómo recuperarla, pero no implica que existan tres sistemas de almacenamiento separados.

Memoria semántica: Hechos y preferencias del usuario. «El usuario prefiere respuestas concisas». «El proyecto usa Python 3.12». Conocimiento factual que persiste entre sesiones. Se almacena en key-value stores para datos estructurados o vector databases para conocimiento no estructurado. Se busca por clave o por semantic search.

Memoria episódica: Secuencias de interacciones pasadas como few-shot examples. No almacena hechos aislados, sino patrones de comportamiento, «cuando el usuario preguntó X, la respuesta Y funcionó bien». Se almacena en vector databases con metadatos temporales. Se recupera con semantic search + filtros de metadatos.

Memoria procedimental: Instrucciones del agente que puede auto-modificar mediante reflection. No es conocimiento sobre el mundo, sino conocimiento sobre cómo el agente debe comportarse. Se almacena en key-value stores con versionado. Se carga directamente en el system prompt.

La distinción importa porque cada tipo tiene un patrón de acceso distinto. La memoria semántica se consulta frecuentemente y cambia poco. La episódica se consulta selectivamente y crece con el tiempo. La procedimental está siempre activa y cambia lentamente. Mezclar los tres tipos en un solo store sin distinguirlos produce recuperación imprecisa.

Context window management

El context window es el recurso más limitado. Gestionarlo mal es el error más común y el más costoso.

Tres estrategias dominan en producción. No son mutuamente excluyentes, se combinan.

Sliding windows con prioridad: En lugar de mantener un historial lineal, se mantiene una ventana donde los mensajes se ordenan por relevancia, no por antigüedad. Las scoring functions evalúan la relevancia basada en proximidad temporal a la query actual, similitud semántica con el input del usuario, e importancia declarada. Las instrucciones del sistema siempre tienen prioridad máxima.

Resumen progresivo. Los mensajes antiguos se comprimen. En lugar de mantener el texto completo, se mantiene un resumen. El trade-off es precisión vs compresión, un resumen agresivo pierde detalles relevantes. Un resumen conservador no ahorra suficientes tokens. Lo que suele funcionar es compresión adaptativa: Mensajes recientes intactos, mensajes intermedios comprimidos moderadamente, mensajes antiguos resumidos agresivamente.

Data pruning efímero. Datos relevantes solo para un turno específico se eliminan después de ese turno. El output detallado de una herramienta se necesita para generar la respuesta actual, pero no para turnos futuros. Se usa, se procesa, se descarta. Requiere que el agente distinga explícitamente entre datos persistentes y efímeros.

Retrieval: El punto donde la memoria se hace útil o inútil

La calidad del retrieval determina si la memoria a largo plazo es útil o ruido. Recuperar demasiado contamina el contexto. Recuperar poco deja al agente sin información necesaria.

Semantic search básico: La query se convierte en embedding y se busca por similitud coseno. Simple, efectivo para conocimiento factual. Limitación: No entiende contexto conversacional. Si el usuario dice «¿y eso cómo se configura?», la búsqueda semántica no sabe qué significa «eso» sin el historial.

Hybrid retrieval: Combina semantic search con keyword matching y filtros de metadatos. Captura tanto similitud conceptual como coincidencia literal. Un usuario que busca «configurar RAG» necesita resultados que contengan «RAG» explícitamente, no solo conceptos semanticamente relacionados.

Re-ranking: Después del retrieval inicial, un modelo evalúa la relevancia de cada resultado en contexto. Los resultados se reordenan por relevancia real, no por similitud vectorial. Elimina falsos positivos del retrieval inicial. El coste es una llamada adicional al modelo, pero la mejora en precisión justifica el overhead cuando la calidad del retrieval impacta directamente en la calidad del output.

Memory decay y stale data

La memoria no es estática. Los datos se vuelven obsoletos, las preferencias cambian, el contexto evoluciona.

Tres tipos de stale data aparecen en producción:

  • Preferencias desactualizadas: El usuario prefería Python 3.11, ahora usa 3.12. El agente sigue generando código para 3.11 porque la memoria semántica no se actualizó.
  • Episodios irrelevantes: Un few-shot example de hace meses ya no es aplicable porque el dominio cambió. El retrieval lo encuentra, el agente lo usa, y produce output desactualizado.
  • Contradicciones acumuladas: El usuario dijo «prefiero respuestas largas» en una sesión y «prefiero respuestas concisas» en otra. La memoria contiene ambas preferencias sin resolución. El agente recibe señales contradictorias.

Las defensas que podemos usar: Timestamps en toda memoria, contradiction detection antes de almacenar, memory expiration con umbrales configurables por dominio.

Memory leakage

La memoria de un usuario o sesión contamina la de otro. Aparece cuando el scoping es incorrecto o cuando el retrieval no filtra por contexto apropiado.

Ejemplo: Un agente almacena preferencias de usuario en memoria semántica. El usuario A prefiere documentación en español. El usuario B pregunta en inglés. El retrieval encuentra la preferencia del usuario A porque no filtró por user_id. El agente responde al usuario B en español.

La defensa es scoping explícito. Cada entrada de memoria tiene un alcance, user-specific, session-specific, o global. El retrieval siempre filtra por alcance apropiado. En Google ADK, los prefixes user:, app:, y temp: implementan este scoping. En LangGraph, los namespaces cumplen la misma función.

Memory Management en código

Memory Management es un patrón de arquitectura. LangChain, LangGraph, Google ADK o Vertex Memory Bank son implementaciones del patrón, no el patrón en sí mismo. Confundir herramienta con patrón lleva a soluciones acopladas a un framework.

Memoria dual con LangGraph

from langgraph.store.memory import InMemoryStore
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
store = InMemoryStore(
    index={"embed": embeddings.embed_query, "dims": 1536}
)

# Memoria semántica: preferencias del usuario
store.put(
    namespace=("user_prefs", "alice"),
    key="style",
    value={"preference": "concise", "language": "python", "updated": "2026-06-17"}
)

# Memoria episódica: Few-shot example
store.put(
    namespace=("episodes", "debugging"),
    key="session_20260610",
    value={
        "context": "Error de connection timeout en API",
        "action": "Verificar timeout settings y retry logic",
        "result": "Success after increasing timeout",
        "timestamp": "2026-06-10"
    }
)

# Retrieval con semantic search + metadata filtering
def retrieve_relevant_memory(store, query, user_id, max_results=3):
    results = store.search(
        namespace=("user_prefs", user_id),
        query=query,
        limit=max_results
    )
    # Filter by recency
    import datetime
    cutoff = datetime.datetime.now() - datetime.timedelta(days=30)
    recent = [
        r for r in results
        if r.value.get("updated", "") >= cutoff.strftime("%Y-%m-%d")
    ]
    return recent

user_memory = retrieve_relevant_memory(store, "coding style", "alice")
system_prompt = f"""Eres un asistente técnico.
Preferencias del usuario: {user_memory}
Responde según estas preferencias."""

Memoria semántica con scoping por usuario, retrieval con semantic search y filtrado por actualidad. El namespace ("user_prefs", "alice") aísla la memoria de cada usuario.

Memoria procedimental con reflection

from langgraph.store.memory import InMemoryStore
from langchain_openai import ChatOpenAI
import datetime

store = InMemoryStore()
llm = ChatOpenAI(model="gpt-4o")

# Inicializar memoria procedimental
initial_instructions = {
    "instructions": "Analiza código Python y reporta bugs.",
    "versión": 1,
    "updated": "2026-06-01"
}
store.put(
    namespace=("procedural",),
    key="code_analyzer",
    value=initial_instructions
)

# Reflection: el agente mejora sus propias instrucciones
def reflect_and_update(state, store):
    current = store.get(("procedural",), "code_analyzer")
    
    reflection_prompt = f"""
Tus instrucciones actuales son:
{current.value['instructions']}

Historial de errores recientes:
{state.get('recent_errors', 'Ninguno')}

Historial de aciertos:
{state.get('recent_successes', 'Ninguno')}

Mejora tus instrucciones basándote en este historial.
Mantén las que funcionan, ajusta las que fallaron.
Devuelve solo las nuevas instrucciones.
"""
    new_instructions = llm.invoke(reflection_prompt)
    
    # Actualizar con versionado
    new_version = current.value.get("versión", 1) + 1
    store.put(
        namespace=("procedural",),
        key="code_analyzer",
        value={
            "instructions": new_instructions.content,
            "versión": new_version,
            "updated": datetime.date.today().isoformat()
        }
    )
    return {"instructions_updated": True}

Memoria procedimental con versionado y reflection. El versionado permite revertir si una actualización empeora el rendimiento. Sin versionado, una reflection errónea puede degradar el comportamiento de forma irreversible.

Fallos reales

Memory Management parece directo hasta que aparece con volumen real.

El context overflow silencioso no es que el contexto se llene de golpe. Crece gradualmente hasta que el modelo empieza a degradarse. Los primeros síntomas son sutiles: el modelo olvida instrucciones del system prompt, prioriza información reciente sobre información importante, o produce respuestas más genéricas. Cuando se detecta, el contexto ya lleva meses creciendo.

El retrieval drift aparece cuando las embeddings que funcionaban bien al inicio se vuelven menos precisas a medida que el dominio evoluciona. Términos nuevos aparecen, significados cambian, y el retrieval empieza a encontrar resultados cada vez menos relevantes. La precisión cae gradualmente, lo que hace difícil detectar el problema hasta que el output del agente se degrada noticeably.

La memory pollution por few-shot examples mal seleccionados ocurre cuando la memoria episódica retrieva ejemplos que son semanticamente similares pero contextualmente irrelevantes. El usuario pregunta sobre «configurar timeout en HTTP». La memoria episódica recupera un ejemplo sobre «configurar timeout en database connection». Semanticamente similares, contextualmente distintos. El modelo aplica el patrón de database timeout a HTTP y produce configuración incorrecta.

Observabilidad

La observabilidad de memoria requiere métricas específicas que revelen cómo el sistema usa y recupera información.

Métricas operativas: Context utilization rate (porcentaje del context window usado en cada turno), memory hit rate (porcentaje de queries donde la recuperación encuentra resultados relevantes), average retrieval latency (tiempo medio de recuperación).

Métricas de calidad: Stale memory rate (porcentaje de memorias recuperadas que superan el umbral de actualidad), contradiction rate (frecuencia de memorias contradictorias en la recuperación), memory precision score (evaluación periódica de si las memorias recuperadas son relevantes para el contexto actual).

Formato de log: {memory_type, operation, namespace, key, retrieval_score, age_days, tokens_consumed, hit_or_miss}. El campo retrieval_score es crítico para detectar retrieval drift, si los scores bajan gradualmente, las embeddings o las queries están perdiendo precisión.

Memory Management combinado con otros patrones

Con Planning, la memoria almacena planes anteriores y sus resultados. El planificador retrieva planes exitosos para tareas similares. La memoria procedimental almacena lecciones aprendidas sobre qué estrategias de planificación funcionan mejor en cada dominio.

Con Tool Use, la memoria almacena el resultado de tool calls anteriores. Si el agente ya consultó una API hace poco, no necesita consultarla de nuevo.

Con Reflection, la memoria procedimental es el substrate donde la reflection escribe mejoras. Sin memoria procedimental, la reflection no persiste.

Con Routing, la memoria semántica almacena patrones de routing exitosos como few-shot examples para futuras decisiones.

Con Multi-Agent, la memoria compartida permite que agentes especializados accedan al mismo conocimiento. La memoria es el canal de comunicación persistente entre agentes.

Cuándo NO usar Memory Management

Tareas one-shot: Si la interacción es una pregunta y una respuesta, la memoria es sobrecarga innecesaria.

Datos efímeros: Información relevante solo para el turno actual no necesita persistencia. Dominio estable: Si el dominio no evoluciona y las preferencias son estáticas, hardcodear la información en el system prompt es más eficiente.

Latencia crítica: Cada retrieval añade latencia.

La prueba práctica es directa, implementa sin memoria primero. Si la calidad del output es insuficiente porque el agente olvida información relevante, entonces añade memoria.

Anti-patrones

  • Dumping toda la memoria en contexto: Cargar todo el historial o toda la memoria semántica en cada prompt quema tokens, aumenta latencia y diluye la señal con ruido irrelevante.
  • Memoria sin scoping: Almacenar datos sin distinguir entre user-specific, session-specific y global causa data leakage entre usuarios o sesiones.
  • Retrieval sin filtrado temporal: Recuperar memorias antiguas sin verificar si siguen siendo relevantes produce output desactualizado.
  • Memoria episódica sin compresión: Almacenar conversaciones completas como episodios consume tokens excesivos. Comprime cada episodio a su información esencial.
  • Reflection sin versionado: Actualizar instrucciones procedimentales sin versionado hace imposible revertir cambios que empeoran el rendimiento.
  • Ignorar memory decay: Dejar que la memoria crezca indefinidamente sin expiración o pruning degrada la precisión del retrieval con el tiempo.
  • Contradicciones no resueltas: Almacenar preferencias contradictorias sin detección o resolución confunde al agente y produce output inconsistente.
  • Memoria como excusa para prompts malos: Si el system prompt es vago, añadir memoria no soluciona el problema. Un prompt claro con memoria mínima supera a un prompt vago con memoria extensiva.

Conclusión

Memory Management es una decisión arquitectónica con trade-offs explícitos entre persistencia y latencia, precisión del retrieval y consumo de tokens, personalización y aislamiento de datos. Sin memoria, cada interacción es un arranque en frío. Con memoria mal gestionada, el agente recuerda cosas incorrectas o desactualizadas y produce output confiante pero erróneo.

La arquitectura que funciona no es la más ambiciosa. Es la que distingue entre lo que necesita estar en contexto ahora y lo que puede esperar en almacenamiento externo, que recupera información relevante sin contaminar el contexto con ruido, y que descarta datos obsoletos antes de que degraden el sistema.

Un agente sin memoria olvida. Un agente con mala memoria recuerda cosas equivocadas. La diferencia es sutil, un sistema es útil y otro genera confianza en resultados incorrectos.

¿Cuándo debo usar Memory Management?

Cuando el agente necesita continuidad entre interacciones, conversaciones multi-turno, personalización basada en preferencias del usuario, o tareas que requieren conocimiento acumulado. Si una interacción es autocontenida, la memoria es sobrecoste.

¿Cuál es la diferencia entre memoria a corto y largo plazo?

La memoria a corto plazo vive en el la ventana de contexto, es inmediata pero efímera. La memoria a largo plazo vive en almacenamiento externo, persiste entre sesiones pero requiere de recuperación explícita.

¿Cómo evito que el contexto se llene?

Sliding windows con prioridad, resumen progresivo de mensajes antiguos, y pruning de datos efímeros. Monitoriza el context utilization rate, si supera consistentemente un umbral alto, ajusta la estrategia de compresión o recuperación.

¿Qué hago cuando el retrieval devuelve información irrelevante?

Implementa hybrid retrieval (semantic search + keyword matching + metadata filters) y re-ranking. Si el problema persiste, revisa la calidad de las embeddings, pueden estar desactualizadas o mal calibradas para tu dominio específico.

¿Cuánta memoria episódica es demasiado?

Depende del dominio. Un punto de razonable es un pequeño número de episodios comprimidos por query. Más episodios consumen tokens sin mejorar necesariamente la calidad.

¿Memory Management funciona con modelos locales?

Sí, pero el context window es más limitado. La estrategia de gestión es más crítica en modelos locales porque no puedes escalar el contexto como con APIs comerciales. Prioriza memoria semántica compacta y recuperación precisa sobre memoria episódica extensiva.

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *