Cómo construir un agente con memoria usando LangGraph

By Carlos Montiel | Especialista en IA Empresarial
Publicado: 2026-07-28 | Por: Carlos Montiel | Lectura: ~4 minutos

Un agente sin memoria repite las mismas preguntas y pierde contexto entre sesiones. LangGraph resuelve esto con dos mecanismos distintos: checkpointers para memoria de corto plazo y stores para memoria de largo plazo.

Dos tipos de memoria, dos mecanismos

Es un error común tratar "memoria" como un concepto único. LangGraph distingue explícitamente entre memoria de corto plazo —el historial de la conversación actual, ligado a un `thread_id`— y memoria de largo plazo —hechos o preferencias del usuario que deben persistir entre conversaciones distintas, incluso después de que el `thread_id` cambie. La primera se resuelve con checkpointers; la segunda con el `Store` de LangGraph.

Memoria de corto plazo con checkpointer

Para desarrollo y pruebas, `MemorySaver` guarda el estado en memoria del proceso. Para producción, se necesita persistencia real:

from langgraph.checkpoint.postgres import PostgresSaver from psycopg_pool import ConnectionPool pool = ConnectionPool(conninfo="postgresql://usuario:pass@localhost:5432/agentes_db") checkpointer = PostgresSaver(pool) checkpointer.setup() # crea las tablas necesarias la primera vez app = builder.compile(checkpointer=checkpointer) config = {"configurable": {"thread_id": "usuario-4471-sesion-1"}} app.invoke({"mensajes": [HumanMessage(content="Necesito cotizar 3 licencias")]}, config=config)

Con `PostgresSaver`, si el proceso se reinicia o el usuario cierra y reabre la conversación con el mismo `thread_id`, el grafo recupera el estado exacto donde quedó, incluyendo el historial completo de mensajes y cualquier otra clave del estado definido.

Memoria de largo plazo con Store

Cuando se necesita recordar información del usuario más allá de una sola conversación —su nombre, preferencias, historial de compras resumido— se usa un `Store`, indexado no por `thread_id` sino por un espacio de nombres (`namespace`) propio del usuario:

from langgraph.store.postgres import PostgresStore store = PostgresStore(pool) store.setup() def nodo_guardar_preferencia(estado, config, *, store): user_id = config["configurable"]["user_id"] store.put( namespace=("preferencias", user_id), key="idioma_preferido", value={"idioma": "es-GT"}, ) return {} def nodo_leer_preferencia(estado, config, *, store): user_id = config["configurable"]["user_id"] item = store.get(namespace=("preferencias", user_id), key="idioma_preferido") return {"preferencias_cargadas": item.value if item else {}}

Al compilar el grafo con `builder.compile(checkpointer=checkpointer, store=store)`, cualquier nodo puede declarar el parámetro `store` en su firma y LangGraph lo inyecta automáticamente en tiempo de ejecución.

Resumiendo historial largo para no saturar el contexto

Una conversación de cientos de mensajes eventualmente excede la ventana de contexto o dispara costos innecesarios. El patrón estándar es un nodo que, cuando el historial supera un umbral, lo resume y reemplaza los mensajes antiguos por el resumen:

from langchain_core.messages import RemoveMessage, SystemMessage def resumir_si_necesario(estado): if len(estado["mensajes"]) <= 20: return {} resumen = llm.invoke( [SystemMessage(content="Resume esta conversación en un párrafo:")] + estado["mensajes"][:-6] ) mensajes_a_borrar = [RemoveMessage(id=m.id) for m in estado["mensajes"][:-6]] return {"mensajes": [SystemMessage(content=f"Resumen previo: {resumen.content}")] + mensajes_a_borrar}

`RemoveMessage` es un tipo especial que, combinado con el reductor de mensajes de LangGraph, elimina mensajes específicos del estado por id, permitiendo podar el historial sin perder los últimos turnos, que suelen ser los más relevantes para la respuesta inmediata.

Recomendación de arquitectura

En despliegues reales usamos `PostgresSaver` para el estado transaccional de la conversación activa (con un TTL razonable, ya que no todo hilo necesita vivir para siempre) y un `Store` separado —a veces respaldado por la misma base de datos, a veces por un vector store cuando la memoria de largo plazo necesita búsqueda semántica sobre preferencias acumuladas— para lo que debe sobrevivir entre sesiones. Mezclar ambos conceptos en una sola tabla ad-hoc es la causa más común de bugs de "memoria fantasma" que hemos visto en auditorías: información de una conversación filtrándose a otra por reutilizar el mismo `thread_id` para usuarios distintos.

Carlos Montiel
Arquitecto de Soluciones IA Empresarial
Especialista en LLMs, Agentes y Orquestación
guatemalia.com/#contacto · info@guatemalia.com

¿Necesitas implementar IA en tu empresa?

Carlos Montiel es arquitecto de soluciones IA empresarial. Implementa LLMs, Agentes, RAG y orquestadores en empresas de Guatemala y Latinoamérica. Contáctalo para una consultoría.

Contactar a Carlos Montiel

info@guatemalia.com