¿Quieres que tu agente recuerde cosas útiles… o que haga como si recordara y te deje colgado en la siguiente conversación?
Tiempo estimado de lectura: 7 min
- Separar memoria corta y larga: la conversación viva debe manejarse aparte de hechos estructurados.
- Extraer hechos estructurados: usar un extractor que emita JSON y aplicar UPSERT/DELETE, no append infinito.
- Decisiones arquitectónicas: síncrono vs asíncrono, versionado y locks para evitar race conditions.
- Optimizar costes: usar modelos baratos para extracción, modelos premium solo para generación crítica.
- Observabilidad y Gobernanza: logs, métricas, cifrado y políticas de retención son imprescindibles.
Poca gente habla de esto: la memoria en agentes no es un problema de “mandar el historial” al modelo. Es un problema de arquitectura, coste y criterio. Hacerlo mal es pagar tokens, cargar latencia y, lo peor, construir una ilusión de memoria que falla cuando más importa.
Te voy a contar, sin florituras, cómo se construyó el sistema de memoria de Agent Builder y qué decisiones concretas puedes tomar hoy para replicarlo sin pelearte con un monster framework.
Resumen rápido (lectores con prisa)
Separar memoria corta (últimos N mensajes) de memoria larga (hechos estructurados). Usar un extractor barato que devuelva JSON forzado con operaciones UPSERT/DELETE. Preferir extracción asíncrona por defecto y checkpoints síncronos para acciones críticas. Versionado y locks para evitar race conditions; observabilidad y gobernanza desde el día 1.
Primera verdad incómoda
Primera verdad incómoda: los LLMs no recuerdan.
Cada petición es una hoja en blanco. Si quieres que el agente actúe con coherencia, tienes que diseñar la memoria fuera del modelo.
Resumen rápido del approach que funciona
- Separar memoria a corto plazo (conversación viva) de memoria a largo plazo (hechos estructurados).
- Extraer hechos con un LLM dedicado (extractor) y guardarlos como pares clave-valor o documentos estructurados.
- Forzar salidas en JSON (Tool Calling) para que la memoria sea determinista.
- Resolver conflictos con UPSERT/DELETE, no con append infinito.
- Decidir entre extracción síncrona o asíncrona según prioridades (latencia vs coherencia).
1) Memoria a corto plazo: lo que vive ahora
¿Qué es? Los últimos N mensajes del hilo (thread_id).
Para qué sirve: referencias inmediatas (“bórralo”, “ese archivo”, “la última tarea”).
Implementación simple: Redis o una tabla en Postgres con TTL y lista acotada.
Por qué importa: reduce tokens enviados al LLM principal y mantiene claridad a corto plazo.
2) Memoria a largo plazo: hechos, no chats
No guardes el chat crudo. Guarda hechos estructurados: preferencias, roles, reglas de negocio, acciones ya realizadas.
¿Cómo se obtienen? Un LLM extractor lee el hilo (o el resumen) y emite objetos JSON con campos tipo {key, value, source, timestamp, confidence}.
Dónde guardarlos: una tabla Key-Value en Postgres o en Redis para lecturas rápidas; opcionalmente, una base vectorial si necesitas búsquedas semánticas sobre fragmentos largos.
3) El extractor: el héroe silencioso
Debe ser un LLM barato y rápido (GPT-4o-mini, Claude 3 Haiku o un modelo local si tienes infra).
Se le da: el hilo reciente + la memoria actual (opcional, si quieres que compare).
Debe devolver: operaciones del tipo {op: “UPSERT”, key: “pref_theme”, value: “dark”, reason: “…”} o {op: “DELETE”, key: “pref_theme”, reason: “…”}.
Forzar JSON es obligatorio. Si el modelo alucina, valida la salida con un schema validator (Zod, JSON Schema).
4) Resolver conflictos: no más “y también”
Problema típico: ayer dije “React”, hoy “Angular” y el sistema almacena ambos.
Solución: lógica de reconciliación dentro del extractor — recibe la memoria existente y decide overwrites o borrados.
Políticas útiles: última declaración gana para preferencias personales; para estados transaccionales usar confirmación explícita (“Confirmo que he migrado a Angular”).
5) Síncrono vs Asíncrono — la decisión que rompe equipos
Síncrono: esperas a que el extractor actualice la memoria antes de responder. Plus: coherencia. Contra: latencia.
Asíncrono: respondes al usuario y actualizas memoria en background. Plus: experiencia rápida. Contra: race conditions si el usuario dispara múltiples mensajes seguidos.
Recomendación práctica: asíncrono por defecto, con checkpoints síncronos en operaciones críticas (ej. ejecutar acciones que dependen de la memoria: “programa el pago” → usa extracción síncrona o confirmación humana).
6) Mitigar race conditions: patrones que funcionan
- Versionado por evento: cada update incluye un version_id. Si un job en background llega con versión vieja, lo descarta.
- Locks optimistas: comparar-timestamps antes de aplicar UPSERT.
- Event sourcing ligero: mandar events al bus (Kafka, Redis Streams) y procesarlos ordenadamente.
- Si necesitas garantía fuerte, usa transacciones y bloqueo por llave (Postgres advisory locks).
7) Costes y optimización de tokens
No envíes texto innecesario al LLM principal. Inyecta solo facts relevantes (top-K) y un resumen de contexto.
Batch extraction: agrupa varias interacciones y extrae cada X minutos si no hay acciones críticas.
Usar modelos cheap para extractor y modelos premium para generación cuando haga falta.
8) Observabilidad y LLMOps: no es opcional
- Logea: inputs al extractor, salidas JSON, ops aplicadas (UPSERT/DELETE), latencias, errores de parsing.
- Métricas clave: TTFT, tiempo de extracción, tasa de conflictos, porcentaje de respuestas incoherentes relacionadas con memoria.
- Guarda trazabilidad para auditoría (what was injected, when, by which extractor) — imprescindible si manejas PII.
9) Privacidad y gobernanza
- Nunca almacenes datos sensibles sin cifrado y consentimiento.
- Tokeniza o anonimiza cuando sea posible.
- Control de accesos: solo servicios autorizados pueden leer/escribir la memoria.
- Políticas de retención: define cuánto tiempo quedan los hechos y cómo se borran permanentemente.
10) Tests y validación
- Tests unitarios de extractor: inputs -> JSON schema válido.
- Integración: simula secuencias de diálogos para validar conflict resolution.
- E2E: pruebas que cubran casos de race conditions y rollback.
- Prueba manual de A/B: compara comportamiento con y sin memoria en producción limitada.
11) Stack recomendado mínimo (para lanzar rápido)
- Storage corto: Redis (listas con TTL)
- Storage largo: Postgres (tabla kv con versioning) + opcional vector DB (Pinecone/Qdrant)
- Orquestador: n8n / Lambda / Sidecar service
- Extractor model: GPT-4o-mini / Claude 3 Haiku (económicos)
- Generación model: GPT-4o / Claude 3 Sonnet (cuando necesites calidad)
- Validación: JSON Schema + Zod en backend
- Observabilidad: logs estructurados + Sentry / Datadog
12) Checklist práctico para ponerlo en producción (si te gusta lo concreto)
- [ ] Definir qué “hechos” guardas (user_prefs, last_actions, contracts_signed, etc.).
- [ ] Implementar almacenamiento corto (Redis) y largo (Postgres).
- [ ] Crear extractor con JSON forced output y validar schema.
- [ ] Implementar operaciones UPSERT/DELETE con versionado.
- [ ] Diseñar flujo asíncrono por defecto y rutas síncronas para operaciones críticas.
- [ ] Añadir metrics y logs para cada extracción y operación.
- [ ] Revisar PII/retención y cifrado en reposo y en tránsito.
- [ ] Tests automáticos para race conditions y reconciliación.
- [ ] Plan de rollback si una actualización de prompt rompe el extractor.
Metáfora que guarda la idea
La memoria del agente no es una mochila donde tiras todo el chat. Es una libreta indexada. Solo apuntas lo que te sirve, lo fechas, lo restructuras y borras lo viejo. Si apilas notas sin orden, la libreta es ruido. Si la estructuras, te salva.
Historias reales (1 párrafo cada una)
El equipo A metió todo el historial en cada prompt: coste x10, latencias enormes y usuarios desconectados. Migraron a extractor asíncrono y bajaron costes un 70%.
El equipo B aseguró cada operación con versión y locks: sacrificaron un poco de velocidad, pero nunca perdieron coherencia en flujos transaccionales.
El equipo C dejó la extracción en background y puso un checkpoint síncrono antes de ejecutar pagos — ganador en UX y seguridad.
Cierre con decisión: ¿lo haces tú o lo dejas para después?
Construir memoria útil no es sexy. Es ingeniería, decisiones difíciles y pruebas. Pero sin ella, tu “agente” será otro bot que habla bonito y olvida todo. Si quieres lanzar algo que realmente parezca inteligente, hazlo con lógica, no con parcheos.
Si quieres la checklist descargable, un prompt extractor listo para copiar/pegar y un mini-plan de 30 días para implementar esto en tu stack, respóndeme “QUIERO MEMORIA” y te lo mando. Esto no acaba aquí — y si no empiezas hoy, otro equipo lo hará.
Como continuación lógica para quienes trabajan en automatización, agentes y workflows, puedes encontrar recursos y experimentos en Dominicode Labs.
FAQ
- ¿Qué diferencia hay entre memoria a corto y a largo plazo?
- ¿Por qué no guardar el chat completo?
- ¿Qué es un extractor y qué formato debe devolver?
- ¿Cuándo usar extracción síncrona en lugar de asíncrona?
- ¿Cómo mitigo race conditions en actualizaciones de memoria?
- ¿Qué métricas debo monitorizar?
- ¿Qué precauciones de privacidad aplicar?
Respuesta: ¿Qué diferencia hay entre memoria a corto y a largo plazo?
La memoria a corto plazo contiene los últimos N mensajes del hilo y sirve para referencias inmediatas. La memoria a largo plazo almacena hechos estructurados (preferencias, roles, acciones realizadas) que deben persistir y consultarse por el agente cuando sea relevante.
Respuesta: ¿Por qué no guardar el chat completo?
Guardar el chat crudo aumenta costes (tokens), latencia y ruido. Es mejor extraer hechos útiles y estructurarlos para lecturas rápidas y deterministas.
Respuesta: ¿Qué es un extractor y qué formato debe devolver?
Un extractor es un LLM barato y rápido que lee el hilo o su resumen y devuelve operaciones en JSON forzado, por ejemplo {op: “UPSERT”, key: “…”, value: “…”, reason: “…”}. La salida debe validarse con un schema validator.
Respuesta: ¿Cuándo usar extracción síncrona en lugar de asíncrona?
Usa extracción síncrona para operaciones críticas que dependen inmediatamente de la memoria (ej. ejecutar pagos). Por defecto, asíncrono para mejor UX y menor latencia, con checkpoints síncronos donde haga falta.
Respuesta: ¿Cómo mitigo race conditions en actualizaciones de memoria?
Patrones efectivos: versionado por evento (version_id), locks optimistas (comparar timestamps), event sourcing ligero y, si necesitas garantías fuertes, transacciones y bloqueo por llave en Postgres.
Respuesta: ¿Qué métricas debo monitorizar?
Métricas clave sugeridas: TTFT, tiempo de extracción, tasa de conflictos y porcentaje de respuestas incoherentes relacionadas con memoria. Además, loggear inputs, salidas JSON y ops aplicadas para trazabilidad.
Respuesta: ¿Qué precauciones de privacidad aplicar?
Nunca almacenar datos sensibles sin cifrado y consentimiento. Tokenizar o anonimizar cuando sea posible, controlar accesos y definir políticas de retención claras.

Leave a Reply