/always-on-agent-architecture — Construyendo Agentes Que Nunca Olvidan
Estás diseñando la arquitectura para un agente de IA siempre activo con memoria episódica. Esto no es un chatbot con una ventana de contexto larga. Es un sistema que persiste el estado entre sesiones, gestiona su propia jerarquía de memoria, se ejecuta como un servicio y mantiene la identidad durante semanas y meses. La idea central: tratar al LLM como una CPU que opera sobre memoria gestionada, no como una función sin estado.
Puntos de Decisión
Árbol de Selección del Framework de Memoria
Q1: ¿Quieres un runtime de agente completo (servidor, APIs, herramientas)?
├─ Sí → Usa Letta (el más completo, listo para producción)
└─ No, tengo mi propio bucle de agente
├─ Q2: ¿Necesitas seguimiento temporal/de relaciones?
│ ├─ Sí → Usa Zep/Graphiti (mejor grafo de conocimiento temporal)
│ └─ No → Ve a Q3
│ ├─ Q3: ¿Necesitas híbrido grafo + vectorial?
│ │ ├─ Sí → Usa Mem0 (modo grafo)
│ │ └─ No → Ve a Q4
│ │ ├─ Q4: ¿Ya estás en LangGraph?
│ │ │ ├─ Sí → Usa LangMem
│ │ │ └─ No → Usa pgvector o Chroma
└─ ¿Quieres cero dependencias? → SQLite personalizado + embeddings locales
Disparadores de Desalojo de Memoria Central
| Disparador | Umbral | Acción |
|---|---|---|
| Desbordamiento de Tamaño | Memoria central > 4KB | Resumir el bloque menos reciente, mover resumen a archivo |
| Decaimiento por Edad | Datos sin usar > 30 días | Marcar para revisión de compactación |
| Caída de Relevancia | Puntuación de acceso < 0.3 | Mover a memoria de archivo con etiqueta de decaimiento |
| Anulación del Usuario | Usuario dice "olvida X" | Eliminación inmediata + tumba de archivo |
| Detección de Conflictos | Hechos contradictorios almacenados | Pedir al agente que reconcilie o pregunte al usuario |
Criterios de Selección de Base de Datos Vectorial
Si requisito_de_latencia_de_consulta < 10ms Y tamaño_de_datos > 100M vectores:
→ Usa Qdrant (optimizado para velocidad)
Sino si ya_usas_postgresql:
→ Usa pgvector (una sola BD, operaciones más simples)
Sino si necesitas_búsqueda_híbrida (keyword + semántica):
→ Usa Weaviate (mejor híbrido)
Sino si prefieres_cero_operaciones:
→ Usa Pinecone (completamente gestionado)
Sino:
→ Usa Chroma (local primero, API simple)
Decisión de Enrutamiento de Niveles de Memoria
Entrada: Mensaje del usuario u observación del agente
│
├─ ¿Contiene actualización de identidad/preferencia?
│ └─ Sí → Actualizar memoria central, persistir inmediatamente
├─ ¿Requiere contexto de conversación?
│ └─ Sí → Buscar en memoria de recuperación (historial de conversación)
├─ ¿Necesita conocimiento factual?
│ └─ Sí → Buscar en memoria de archivo (almacén vectorial)
└─ ¿Se necesitan datos externos?
└─ Sí → Usar herramientas externas (APIs, archivos, etc.)
Modos de Fallo
Cascada de Corrupción de Memoria
Síntomas: Deriva de personalidad del agente, respuestas contradictorias, conflictos en memoria central Causa Raíz: Escrituras concurrentes a la memoria central sin bloqueo, o actualizaciones parciales fallidas Regla de Detección: Si el tamaño de la memoria central cae repentinamente >50% o contiene JSON/YAML malformado Procedimiento de Recuperación:
- Detener el agente inmediatamente para evitar más corrupción
- Restaurar la memoria central desde la última copia de seguridad buena conocida (< 1 hora de antigüedad)
- Reproducir el registro de conversación desde la copia de seguridad para reconstruir las actualizaciones perdidas
- Implementar bloqueos de escritura en las actualizaciones de memoria central antes de reiniciar
Degradación de Búsqueda Vectorial
Síntomas: Resultados de búsqueda cada vez más irrelevantes, el agente no puede encontrar hechos almacenados recientemente Causa Raíz: Deriva del modelo de embeddings, corrupción del índice, o falta de compactación de memoria Regla de Detección: Si la similitud coseno promedio de los 3 mejores resultados es < 0.7 para consultas conocidas Procedimiento de Recuperación:
- Ejecutar una comprobación de consistencia de embeddings en una muestra aleatoria de 100 vectores
- Si >10% muestran embeddings anómalos, reconstruir todo el índice
- Implementar fijación de versión del modelo de embeddings
- Agregar monitoreo de deriva de embeddings para prevenir recurrencia
Punto Muerto de la Capa de Persistencia
Síntomas: El agente se cuelga en operaciones de memoria, tiempos de espera de conexión a la base de datos Causa Raíz: Lectura/escritura simultánea en los mismos bloques de memoria, pooling de conexiones insuficiente Regla de Detección: Si una operación de memoria tarda >30s o la base de datos muestra tiempos de espera de bloqueo Procedimiento de Recuperación:
- Matar conexiones colgadas para liberar bloqueos
- Implementar lógica de reintento con retroceso exponencial para operaciones de memoria
- Agregar pooling de conexiones con límites máximos de conexiones
- Revisar niveles de aislamiento de transacciones para actualizaciones de memoria
Explosión de Ventana de Contexto
Síntomas: Los costos de API se disparan, la latencia de respuesta aumenta, errores de límite de tokens Causa Raíz: Hinchazón de la memoria central, recuperación de demasiados fragmentos de archivo por consulta Regla de Detección: Si el promedio de tokens por solicitud supera el 80% del límite de contexto del modelo Procedimiento de Recuperación:
- Auditar el tamaño de la memoria central: comprimir o archivar bloques sobredimensionados
- Reducir el número de resultados de búsqueda de archivo de 10 a 5
- Implementar conteo de tokens antes de las llamadas al LLM
- Agregar alertas de monitoreo de costos para >$1/conversación
Fuga de Memoria — Crecimiento Ilimitado
Síntomas: El tamaño de la base de datos crece linealmente, el rendimiento de búsqueda se degrada con el tiempo Causa Raíz: Sin compactación de memoria, inserción de hechos duplicados, falta de recolección de basura Regla de Detección: Si el tamaño total de memoria crece >100MB/mes con uso normal Procedimiento de Recuperación:
- Ejecutar deduplicación de hechos en la memoria de archivo (similitud coseno > 0.92)
- Implementar resumen de conversaciones para la memoria de recuperación >7 días de antigüedad
- Agregar puntuación de relevancia con poda automática de memorias de baja puntuación
- Programar trabajos de compactación semanales
Ejemplos Prácticos
Ejemplo: Construcción de un Asistente de Investigación Personal
Escenario: Diseñar la arquitectura para un agente que ayuda con investigación técnica, recuerda tus preferencias y construye conocimiento a lo largo de meses.
Paso 1 - Diseño de Niveles de Memoria
Memoria Central (2KB):
- Nombre del usuario: "Sarah"
- Dominios de investigación: ["machine learning", "sistemas distribuidos"]
- Fuentes de documentos preferidas: ["arxiv", "acm digital library"]
- Estilo de escritura: "detallado con ejemplos de código"
- Proyecto actual: "optimización de entrenamiento distribuido"
Memoria de Recuperación:
- Todas las conversaciones en PostgreSQL con búsqueda de texto completo
- Ventana de retención de 30 días, luego resumidas
Memoria de Archivo:
- Resúmenes de documentos, ideas extraídas, fragmentos de código
- pgvector en PostgreSQL (ya lo usamos para recuperación)
- nomic-embed-text para embeddings local (privacidad + costo)
Paso 2 - Decisión de Selección de Framework Siguiendo el árbol de decisión:
- ¿Necesitas runtime completo de agente? No (construyendo uno personalizado)
- ¿Necesitas seguimiento temporal? No (los hechos de investigación son mayormente atemporales)
- ¿Necesitas grafo+vectorial? No (búsqueda semántica simple es suficiente)
- ¿Ya estás en LangGraph? No
- → Decisión: pgvector + PostgreSQL
Paso 3 - Implementación del Bucle del Agente
async def paso_de_investigacion(consulta_usuario: str):
# Cargar memoria central
central = cargar_memoria_central() # Preferencias del usuario, proyecto activo
# Verificar si la consulta se relaciona con el proyecto actual
if "optimización" in consulta_usuario.lower():
# Buscar en archivo conocimiento específico del proyecto
documentos_relevantes = buscar_en_archivo("optimización de entrenamiento distribuido")
contexto = f"Contexto del proyecto actual: {documentos_relevantes}"
else:
# Buscar conocimiento general del dominio
contexto = buscar_en_archivo(consulta_usuario)
# Construir prompt con memoria central + contexto recuperado
prompt_sistema = f"""
Eres el asistente de investigación de Sarah.
Preferencias del usuario: {central['preferencias']}
Proyecto actual: {central['proyecto_actual']}
Contexto recuperado: {contexto}
"""
respuesta = await llm.chat([
{"role": "system", "content": prompt_sistema},
{"role": "user", "content": consulta_usuario}
])
# Persistir interacción
guardar_en_recuperacion(consulta_usuario, respuesta)
return respuesta
Lo que un novato pasaría por alto:
- Almacenar documentos completos en lugar de ideas extraídas en la memoria de archivo
- No implementar búsqueda de conversaciones (memoria de recuperación)
- Poner demasiado en la memoria central (lista de dominios de investigación con 50 entradas)
- Sin estrategia de compactación de memoria
Lo que un experto capta:
- La memoria central se centra en la "identidad de trabajo", no en el conocimiento
- La memoria de archivo almacena hechos depurados, no documentos completos
- Implementa búsqueda antes de la recuperación (el agente decide qué es relevante)
- Planifica el crecimiento de la memoria desde el primer día
Puertas de Calidad
Lista de Verificación de Validación de Despliegue
- SLO de Latencia de Memoria: La memoria central carga en <100ms, la búsqueda en archivo completa en <500ms
- Consistencia de Memoria: La memoria central sobrevive al reinicio del agente sin corrupción (probar con matanza deliberada)
- Relevancia de Búsqueda: Los 3 mejores resultados de archivo tienen similitud coseno >0.6 para consultas conocidas
- Reglas de Tamaño de Memoria: Memoria central ≤4KB, retención de recuperación ≤30 días, fragmentos de archivo ≤1KB cada uno
- Durabilidad de Persistencia: Todas las actualizaciones de memoria sobreviven al reinicio de la base de datos (cumplimiento ACID verificado)
- Controles de Costo: Las operaciones de memoria cuestan <$0.01/conversación a 100 conversaciones/día
- Programación de Compactación: La compactación de memoria se ejecuta semanalmente y reduce el tamaño total en ≥10%
- Consistencia de Identidad: La personalidad del agente se mantiene estable en más de 50 sesiones de conversación
- Recuperación en Frío: El agente maneja correctamente el estado vacío de memoria (el flujo de incorporación funciona)
- Verificación de Copia de Seguridad: La copia de seguridad de memoria se restaura correctamente y preserva la identidad del agente
Límites NO-APLICA
NO uses este skill para:
- Elegir datos de entrenamiento del agente → Usa
/always-on-agent-inputsen su lugar: ese skill cubre qué datos alimentar al agente, este cubre cómo almacenarlos y recuperarlos - Generar ideas de aplicaciones del agente → Usa
/always-on-agent-applicationsen su lugar: ese skill cubre ideación de casos de uso, este cubre implementación técnica - Seguridad y privacidad del agente → Usa
/always-on-agent-safetyen su lugar: ese skill cubre gobernanza de datos, consentimiento y seguridad; este asume que ya están diseñados - Patrones generales de agente → Usa
/agentic-patternsen su lugar: ese skill cubre bucles ReAct, uso de herramientas, planificación; este cubre la capa de persistencia subyacente - Tareas de agente de una sola vez → Usa
/agent-creatoren su lugar: si el agente no necesita recordar entre sesiones, no necesitas arquitectura siempre activa - Diseño de esquemas de base de datos → Este skill asume que entiendes conceptos básicos de bases de datos; usa skills específicos de base de datos para optimización de esquemas
- Estrategias de optimización de costos → Este skill menciona consideraciones de costos pero no profundiza en optimización; delega a skills específicos de costos