Módulo 8: Memoria y Persistencia

Introducción: Por Qué los Agentes Necesitan Memoria

Descripción

Tu AI Research Assistant es robusto. Tiene retry con backoff exponencial, búsqueda paralela en múltiples fuentes, merge con deduplicación, y graceful degradation cuando una fuente falla. Lo construiste en el Módulo 7 y funciona en el mundo real.

Pero es amnésico. Cada ejecución empieza de cero.

Cierra el terminal, ábrelo de nuevo, y tu agente no tiene idea de que hace 5 minutos estaba a mitad de una investigación sobre RAG. El usuario vuelve mañana y pregunta "¿puedes profundizar en lo que encontraste ayer?" — el agente no sabe de qué le hablas. Una investigación que llevaba 5 minutos procesando 3 de 5 fuentes se interrumpe por un crash del sistema — todo ese trabajo se pierde.

Esto no es un edge case. Es lo que le pasa a cualquier sistema stateless en producción. Y es exactamente lo que diferencia un demo de un producto que puedes poner frente a usuarios reales.

Por qué importa: Sin memoria y persistencia, los Módulos 9-12 no son posibles. Human-in-the-loop (M9) requiere que el agente guarde su estado para pausarse y esperar aprobación. Multi-agent (M10) requiere que agentes compartan contexto. Producción (M12) requiere que nada se pierda. Este módulo es la base técnica de todo lo que viene.


¿Dónde estamos en la guía?

Este es el Módulo 8 de la guía LangChain & LangGraph: From Chains to Agents. Es el primer módulo del Bloque 3 (LangGraph Avanzado).

Bloque 1: LangChain Core (Módulos 1-4)           ✅ Completado
Bloque 2: LangGraph Fundamentals (Módulos 5-7)   ✅ Completado
Bloque 3: LangGraph Avanzado (Módulos 8-10)      ← ESTÁS AQUÍ (Módulo 8)
Bloque 4: Producción (Módulos 11-12)
Tu progreso:

Bloque 1 — LangChain Core                   ✅ Completado
    │
    │  Módulo 1: Modelos y Proveedores       ✅
    │  Módulo 2: Tools y Tool Calling        ✅
    │  Módulo 3: Agents (create_agent)       ✅
    │  Módulo 4: Middleware y Customización   ✅
    │
    ▼
Bloque 2 — LangGraph Fundamentals           ✅ Completado
    │
    │  Módulo 5: Introducción a LangGraph    ✅
    │  Módulo 6: Functional API              ✅
    │  Módulo 7: Flujos Avanzados            ✅
    │
    ▼
Bloque 3 — LangGraph Avanzado
    │
    │  Módulo 8: Memoria y Persistencia      ← ESTÁS AQUÍ
    │  Módulo 9: Human-in-the-Loop           🔒 Siguiente
    │  Módulo 10: Multi-Agent Systems        🔒
    │
    ▼
Bloque 4 — Producción                       🔒
    │
    │  Módulo 11: Deep Agents                🔒
    │  Módulo 12: LangSmith y Producción     🔒

El Bloque 2 te dio las herramientas de construcción: StateGraph, Functional API, retry, branching, error handling. El Bloque 3 las convierte en capacidades enterprise: persistencia (este módulo), supervisión humana (M9), y colaboración multi-agente (M10).


El puente desde el Módulo 7

Lo que ya tienes

Tu Research Agent v2 es un sistema robusto:

  • ✅ Retry con backoff exponencial cuando las APIs fallan
  • ✅ Búsqueda paralela en 3 fuentes simultáneamente
  • ✅ Merge con deduplicación de resultados
  • ✅ Graceful degradation: si una fuente falla, el reporte se genera con las que respondieron
  • ✅ Logging estructurado para trazabilidad

Lo que le falta

Ejecuta esta secuencia mental:

Escenario 1 — Crash a mitad del proceso:
  Tu agente lleva 5 minutos investigando "state of AI in healthcare 2025"
  Procesó 3 de 5 fuentes exitosamente
  La máquina se reinicia (actualización de OS, crash, cierre accidental)
  
  Sin persistencia: empiezas de cero. 5 minutos + costos de API perdidos.
  Con persistencia: resumes desde la fuente 4. 30 segundos.

Escenario 2 — El usuario vuelve mañana:
  Hoy: "Investiga las tendencias de RAG en 2025"
  Mañana: "¿Puedes profundizar en lo que encontraste ayer sobre hybrid search?"
  
  Sin memoria: "No tengo información sobre investigaciones previas."
  Con memoria: "Ayer encontré 3 papers sobre hybrid search. Profundizo en ellos."

Escenario 3 — Múltiples usuarios:
  Usuario A investiga IA en salud. Usuario B investiga IA en finanzas.
  Ambos usan el mismo agente desplegado.
  
  Sin aislamiento: las conversaciones se mezclan.
  Con thread_id: cada usuario tiene su propio contexto aislado.

Estos tres problemas — crash recovery, memoria entre sesiones, y multi-usuario — son exactamente lo que resuelve este módulo.


Los dos tipos de memoria (no los confundas)

Esta distinción es fundamental. Confundir short-term y long-term memory es el error más común al trabajar con agentes stateful. Son conceptos completamente diferentes con implementaciones diferentes.

Short-term memory: la conversación actual

Short-term memory es el historial de mensajes dentro de la sesión actual. Es lo que permite que el agente mantenga contexto entre turnos de conversación:

Turno 1 — Usuario: "¿Qué es RAG?"
Turno 1 — Agente: "RAG es Retrieval-Augmented Generation, un patrón que..."

Turno 2 — Usuario: "¿Me das un ejemplo?"
           ↑ Sin short-term memory, el agente no sabe a qué se refiere "un ejemplo"
           ↑ Con short-term memory, sabe que "un ejemplo" se refiere a RAG

Características:

  • ✅ Existe dentro de una sesión (una conversación)
  • ✅ Incluye: mensajes del usuario, respuestas del agente, tool calls, resultados de tools
  • ✅ Se gestiona con MessagesState y thread_id
  • ✅ Tiene un límite práctico: el context window del modelo (128K tokens en GPT-4.1)
  • ❌ Se pierde cuando la sesión termina (a menos que uses checkpointing)

Long-term memory: lo que persiste entre sesiones

Long-term memory es información que sobrevive entre conversaciones diferentes. No son mensajes — son datos estructurados que el agente acumula y consulta:

Sesión 1 (lunes):
  Usuario investiga "AI in healthcare"
  Agente guarda: preferencia por fuentes académicas, interés en diagnóstico médico

Sesión 2 (miércoles):
  Usuario: "Investiga algo nuevo"
  Agente consulta long-term memory:
    → "Este usuario prefiere fuentes académicas"
    → "Sus temas previos incluyen IA en salud, especialmente diagnóstico"
    → Adapta la búsqueda automáticamente

Características:

  • ✅ Persiste entre sesiones diferentes (días, semanas)
  • ✅ Incluye: preferencias del usuario, conocimiento acumulado, perfiles de intereses
  • ✅ Se gestiona con InMemoryStore o bases de datos externas
  • ✅ No está limitada por el context window — se almacena fuera del modelo
  • ❌ Requiere diseño explícito: qué guardar, cuándo consultarlo, cómo actualizarlo

Episodic memory: interacciones pasadas específicas

Episodic memory es un subconjunto de long-term memory que se refiere a interacciones específicas que el agente puede referenciar:

Usuario: "¿Recuerdas lo que encontraste la última vez sobre RAG?"
Agente consulta episodic memory:
  → Sesión del 3 de marzo: investigó RAG, encontró 5 papers, conclusión principal fue...
  → "Sí, la última vez encontré que hybrid search supera a dense retrieval en un 15%..."

No es un sistema separado — es cómo usas la long-term memory para recordar eventos pasados.

Tabla comparativa

AspectoShort-termLong-termEpisodic
AlcanceUna sesiónTodas las sesionesSesiones específicas
ContenidoMensajes, tool callsPreferencias, perfilesEventos pasados
LímiteContext windowAlmacenamiento externoAlmacenamiento externo
ImplementaciónMessagesStateInMemoryStore / DBSubset de long-term
Se pierde si...La sesión terminaSe borra el storeSe borra el store
Ejemplo"Acabas de preguntar sobre RAG""Prefieres fuentes académicas""El lunes investigaste healthcare"

Stateless vs stateful: por qué importa

Agente stateless (lo que tienes ahora)

result = agent.invoke({"query": "¿Qué es RAG?"})
# El agente responde, y olvida todo inmediatamente.

result = agent.invoke({"query": "Dame más detalles"})
# "¿Más detalles sobre qué? No tengo contexto previo."

Cada invoke() es una isla. No hay conexión entre llamadas. Es como hablar con alguien que tiene amnesia anterógrada: cada interacción empieza desde cero.

Agente stateful (lo que construirás)

config = {"configurable": {"thread_id": "user_123"}}

result = agent.invoke({"query": "¿Qué es RAG?"}, config)
# El agente responde Y guarda la conversación en el thread "user_123"

result = agent.invoke({"query": "Dame más detalles"}, config)
# El agente lee el historial del thread "user_123"
# Sabe que "más detalles" se refiere a RAG
# Responde con contexto

El thread_id es la clave. Cada thread es una conversación independiente con su propio historial. Mismo agente, diferentes threads, diferentes contextos. Así funciona el multi-usuario.


El stack de persistencia

LangGraph tiene un diseño deliberado para persistencia: empiezas simple para desarrollo, y migras a producción cambiando una línea.

MemorySaver: desarrollo y testing

from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)
  • ✅ Zero config: no necesitas base de datos, no necesitas Docker
  • ✅ Perfecto para desarrollo: pruebas rápidas, iteración, debugging
  • ❌ In-memory: si el proceso se reinicia, se pierde todo
  • ❌ Single-process: no funciona con múltiples workers

Usa MemorySaver para: prototipar, testear, desarrollo local, tutoriales.

PostgresSaver: producción

from langgraph.checkpoint.postgres import PostgresSaver

checkpointer = PostgresSaver.from_conn_string("postgresql://user:pass@host:5432/db")
graph = builder.compile(checkpointer=checkpointer)
  • ✅ Durable: sobrevive a reinicios del proceso, crashes, deployments
  • ✅ Multi-process: múltiples workers pueden leer y escribir
  • ✅ Escalable: PostgreSQL es battle-tested para producción
  • ❌ Requiere una instancia de PostgreSQL

Usa PostgresSaver para: producción, staging, cualquier entorno donde la durabilidad importa.

La migración es trivial

Mira el cambio:

# Desarrollo
checkpointer = MemorySaver()

# Producción (la ÚNICA línea que cambia)
checkpointer = PostgresSaver.from_conn_string(os.getenv("DATABASE_URL"))

# El resto del código es IDÉNTICO
graph = builder.compile(checkpointer=checkpointer)

Una línea. El resto de tu código — nodos, edges, estado, lógica — no cambia absolutamente nada. Esa es la abstracción bien diseñada: el checkpointer es un backend intercambiable.


Mapa del módulo

#CápsulaQué aprenderásTipo
01Introducción (esta)Por qué los agentes necesitan memoria, tipos de memoria, stack de persistenciaIntro
02Short-term memory: conversation historyMessagesState, thread_id, message trimming, summarizationTécnica
03Checkpointing: MemorySaverCheckpoint automático, inspeccionar estados, thread managementTécnica
04Durable execution y crash recoverySimular crashes, resume desde checkpoint, idempotenciaTécnica
05Time-travel debuggingNavegar historial de estados, replay, debugging de decisionesTécnica
06Long-term memory con StoreInMemoryStore, namespaces, guardar y consultar datos entre sesionesTécnica
07PostgresSaver: persistencia en producciónSetup PostgreSQL, migración desde MemorySaver, multi-workerTécnica
08Proyecto: Research Agent con memoriaResearch Agent v3: checkpointing + long-term memory + multi-usuarioProyecto

Flujo de aprendizaje

Empiezas con short-term memory (cápsula 02) — el concepto más inmediato: cómo mantener contexto entre turnos de conversación. Luego aprendes checkpointing (cápsula 03) — el mecanismo que guarda el estado del agente en cada paso. Con checkpointing, implementas crash recovery (cápsula 04) — el agente sobrevive a interrupciones y resume donde quedó. Después, usas los checkpoints para time-travel debugging (cápsula 05) — navegas el historial de estados y entiendes por qué el agente tomó cada decisión. Agregas long-term memory (cápsula 06) — información que persiste entre sesiones. Migras a PostgresSaver (cápsula 07) — persistencia real para producción. Finalmente, integras todo en el Research Agent v3 (cápsula 08).

La progresión es: conversación → checkpoints → durabilidad → debugging → memoria persistente → producción → proyecto.


Conexión con el proyecto

Research Agent v3: el agente que recuerda

Tu Research Agent evoluciona significativamente en este módulo:

v1 (Módulo 6): Funcional pero frágil
    ↓
v2 (Módulo 7): Robusto (retry, branching, error handling)
    ↓
v3 (Este módulo): Persistente (checkpointing, memoria, multi-usuario)
    │
    │  + Checkpointing: investigaciones se guardan paso a paso
    │  + Crash recovery: si se interrumpe, resume donde quedó
    │  + Long-term memory: recuerda preferencias entre sesiones
    │  + Thread management: multi-usuario con contexto aislado
    │
    ▼
v4 (Módulo 9): + Aprobaciones humanas antes de acciones costosas

La prueba de éxito es concreta: cierra el terminal, abre uno nuevo, ejecuta tu agente con el mismo thread_id — y recuerda la investigación anterior. Ese momento, cuando ves que el agente "sabe" lo que investigaste hace una hora, es cuando este módulo hace clic.


Conexión con el Módulo 9: Human-in-the-Loop

La persistencia es prerequisito técnico para human-in-the-loop. La razón es directa:

Sin persistencia:
  Agente: "Voy a ejecutar una búsqueda costosa en 5 APIs"
  Sistema: interrupt() — pausar para aprobación humana
  ??? El agente perdió su estado. No sabe dónde estaba.

Con persistencia:
  Agente: "Voy a ejecutar una búsqueda costosa en 5 APIs"
  Sistema: interrupt() — pausar para aprobación humana
  Estado guardado en checkpoint con thread_id
  ... 10 minutos después ...
  Humano: "Aprobado"
  Sistema: resume desde checkpoint — el agente continúa exactamente donde pausó

Sin checkpointing, interrupt() no tiene sentido — el agente no puede pausarse y resumir si no tiene estado persistente. Por eso este módulo viene antes del M9.


Qué NO cubre este módulo

  • Vector stores y RAG — Guardar embeddings para búsqueda semántica es un tema diferente. Este módulo trata sobre el estado del agente (conversaciones, checkpoints, preferencias), no sobre knowledge bases externas.
  • Bases de datos de conocimiento — No construimos un sistema de retrieval. La long-term memory aquí son preferencias y perfiles, no documentos indexados.
  • Redis como backend — Mencionamos que existe como opción, pero nos enfocamos en MemorySaver (dev) y PostgresSaver (prod). Redis es útil para caching y sesiones efímeras.
  • Human-in-the-loop — Mencionamos que la persistencia lo habilita, pero la implementación de interrupts y approvals es del Módulo 9.
  • Multi-agent memory sharing — Cómo comparten memoria múltiples agentes se cubre en el Módulo 10.

Setup técnico

Prerequisitos

  • Módulo 7 completado — tienes un Research Agent v2 con retry, branching, y error handling
  • Python 3.11+ instalado
  • ✅ Al menos una API key de un proveedor (OpenAI recomendado)

Instalación

Si completaste el Módulo 7, ya tienes las dependencias principales. Agrega el paquete de checkpointing para PostgreSQL (lo usarás en la cápsula 07):

pip install langgraph langchain-openai python-dotenv langgraph-checkpoint-postgres

Verifica que la importación funciona:

from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import MessagesState

print("MemorySaver disponible")
print("MessagesState disponible")
# Output esperado:
# MemorySaver disponible
# MessagesState disponible

Variables de entorno

Tu .env del Módulo 7 sigue funcionando:

# .env
OPENAI_API_KEY=sk-...

# Para la cápsula 07 (PostgresSaver), agregarás:
# DATABASE_URL=postgresql://user:password@localhost:5432/langgraph_db

Verificación rápida: agente con memoria

Ejecuta este script para verificar que el checkpointing funciona:

from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.checkpoint.memory import MemorySaver

def echo(state: MessagesState) -> dict:
    last_message = state["messages"][-1].content
    return {"messages": [{"role": "assistant", "content": f"Echo: {last_message}"}]}

builder = StateGraph(MessagesState)
builder.add_node("echo", echo)
builder.add_edge(START, "echo")
builder.add_edge("echo", END)

checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)

config = {"configurable": {"thread_id": "test_001"}}

result1 = graph.invoke({"messages": [{"role": "user", "content": "Hola"}]}, config)
print(f"Turno 1: {result1['messages'][-1].content}")

result2 = graph.invoke({"messages": [{"role": "user", "content": "¿Recuerdas qué dije?"}]}, config)
print(f"Turno 2: {result2['messages'][-1].content}")
print(f"Mensajes en historial: {len(result2['messages'])}")
# Output esperado:
# Turno 1: Echo: Hola
# Turno 2: Echo: ¿Recuerdas qué dije?
# Mensajes en historial: 4

Si ves 4 mensajes en el historial (2 del usuario + 2 del agente), el checkpointing está funcionando. El agente acumula mensajes entre invocaciones gracias al thread_id.


Evidencia de éxito

Al terminar este módulo, sabrás que tuviste éxito si:

  • ✅ Tu agente mantiene conversación con contexto: puedes referirte a mensajes anteriores y el agente entiende
  • ✅ Puedes cerrar el terminal, abrir uno nuevo, y el agente recuerda la conversación anterior (con PostgresSaver)
  • ✅ Simulas un crash a mitad de una investigación y el agente resume exactamente donde quedó
  • ✅ Puedes navegar el historial de estados del agente y ver qué estado tenía en cada paso (time-travel)
  • ✅ El agente recuerda preferencias del usuario entre sesiones diferentes (long-term memory)
  • ✅ Dos usuarios diferentes usan el mismo agente con contextos completamente aislados (thread_id)

Test de autoevaluación

Si puedes responder estas preguntas, vas por buen camino:

  1. ¿Cuál es la diferencia entre short-term y long-term memory en un agente?
  2. ¿Por qué MemorySaver no es adecuado para producción?
  3. ¿Qué pasa si no implementas message trimming en una conversación larga?
  4. ¿Cómo permite el checkpointing que un agente se pause y resuma?
  5. ¿Qué es un thread_id y por qué es necesario para multi-usuario?

Resumen

  • Tu Research Agent v2 es robusto, pero amnésico: cada ejecución empieza de cero. Sin persistencia, los crashes destruyen trabajo, los usuarios no tienen continuidad, y no hay aislamiento multi-usuario
  • Short-term memory es el historial de la conversación actual — mensajes, tool calls, resultados. Se gestiona con MessagesState y thread_id
  • Long-term memory es información que persiste entre sesiones — preferencias, perfiles, conocimiento acumulado. Se gestiona con InMemoryStore o bases de datos
  • Episodic memory es un subset de long-term: interacciones pasadas específicas que el agente puede referenciar
  • MemorySaver = desarrollo y testing (in-memory, zero config). PostgresSaver = producción (durable, multi-process). La migración es una línea de código
  • La persistencia es prerequisito para human-in-the-loop (M9): el agente necesita estado guardado para pausarse y resumir
  • Este módulo transforma el Research Agent de un prototipo que "funciona" a un sistema que recuerda — la diferencia entre un demo y un producto

Recursos adicionales

  1. LangGraph — Persistence — Documentación oficial sobre el sistema de persistencia de LangGraph: checkpointers, threads, estado
  2. LangGraph — Memory — Conceptos de short-term y long-term memory en LangGraph
  3. How to add memory to chatbots — Guía práctica para agregar historial de conversación
  4. How to add cross-thread memory — Implementar long-term memory que persiste entre threads
  5. LangGraph Checkpoint PostgreSQL — Setup de PostgresSaver para producción
  6. Designing AI Agents with Memory — LangChain Blog — Artículo sobre patrones de memoria para agentes

Módulo 8 — LangChain & LangGraph: From Chains to Agents

Siguiente cápsula: Short-term Memory: Conversation History — aprenderás cómo MessagesState gestiona el historial de conversación, cómo thread_id aísla contextos por usuario, y por qué message trimming es obligatorio para producción.