Memoria del cliente para agentes de IA con un presupuesto estricto de tokens.
Cómo la capa de memoria de un agente extrae hechos, evalúa su importancia, elimina duplicados mediante un coeficiente de coseno de 0.92, almacena vectores en pgvector y recupera información dentro de un límite de 2,048 tokens con mecanismo de expulsión.
Fuentes: Engineering a Multi-Agent AI Platform — Part 6: Memory Under Token Constraints
Un agente de soporte habla con un cliente, y todo lo necesario debe caber en una sola ventana de contexto. GPT-4o ofrece 128K tokens, mientras que los modelos más pequeños pueden ofrecer 32K o menos. Esa ventana debe contener el prompt del sistema, las definiciones de las herramientas, el conocimiento recuperado, la conversación en curso y todo lo que el agente recuerda sobre esa persona en particular. Este texto describe un diseño de memoria para ese escenario: cómo se extraen los hechos de las conversaciones ya finalizadas, se califican, se deduplican, se almacenan como vectores y se recuperan nuevamente bajo un límite estricto de tokens.
La ventana es un presupuesto, no un recipiente ilimitado
Al incluir todo lo que se sabe sobre un cliente en el prompt, los demás datos se ven reducidos. La recuperación de conocimiento se ve truncada, el historial de conversaciones se acorta, y el prompt del sistema puede retroceder tanto que el modelo pierde de vista sus propias instrucciones.
Al no incluirse nada, el agente trata cada conversación como si fuera la primera. Un cliente que pregunta por la hora de su cita recibe la respuesta “No tengo esa información”, aunque ya la proporcionó el martes pasado.
La solución consiste en establecer un límite fijo para la memoria del cliente. En el diseño descrito aquí ese límite es de 2,048 tokens. Dentro de ese límite, el sistema incluye solo los datos más relevantes para ese cliente en esa conversación. No todos los datos, ni los aleatorios, sino únicamente los adecuados.
Extracción de datos de conversaciones finalizadas
Una vez que termina una conversación, un proceso de consolidación la analiza en busca de datos que valga la pena conservar. La extracción se realiza con un LLM (GPT-4o-mini) mediante una instrucción estructurada que pregunta qué información factual sobre el cliente se puede obtener, y que evalúe cada dato del 0 al 1 en cuanto a especificidad, utilidad práctica y frecuencia de aparición.
“Específico” es la palabra clave. Los hechos deben describir a este cliente y no ofrecer observaciones genéricas. “Prefiere citas por la mañana” es un hecho. “Hizo una pregunta” no lo es.
El modelo responde con un array JSON, donde cada elemento contiene una cadena de texto y una puntuación de importancia. El proceso solo transmite aquellos hechos con una puntuación de al menos 0.5. Este umbral descarta las observaciones irrelevantes, cuyas puntuaciones suelen estar entre 0.2 y 0.3, y mantiene todo lo que podría ser útil posteriormente.
Un intercambio típico de diez mensajes genera de dos a cuatro hechos que cumplen los requisitos, mientras que una larga sesión de resolución de problemas puede dar de seis a ocho. La mayoría de las conversaciones producen al menos uno.
Qué representa la puntuación de importancia
El único número del rango 0.0 a 1.0 combina tres cualidades.
- Especificidad. ¿Hasta qué punto es relevante este dato para este cliente? “Prefiere el correo electrónico sobre el teléfono” lo es, mientras que “Es un cliente” no lo es.
- Utilidad para la acción. ¿Puede el agente utilizarlo para responder mejor la próxima vez? “Tiene un problema recurrente con la factura n.º 4821” cumple con este criterio, en contraste con “Dijo hola”, que no lo hace.
- Recurrente. ¿Tendrá importancia en varias conversaciones? La zona horaria UTC+3 aparece cada vez que se habla de programación, pero una pregunta sobre el clima de hoy ocurre solo una vez.
El equipo responsable del diseño probó asignar calificaciones separadas por dimensión y descubrió que una calificación combinada se ajustaba mejor, manteniendo al mismo tiempo la pregunta más simple. Según sus mediciones, el umbral de 0.5 descarta aproximadamente el 60% de los datos extraídos, dejando solo aquellos de mayor relevancia.
Embebidos y control de duplicados
Cada hecho que se conserva está incrustado como un vector de 3072 dimensiones, que corresponde simplemente al tamaño de salida del modelo de incrustación utilizado, OpenAI’s text-embedding-3-large. Más dimensiones permiten distinguir con mayor precisión las similitudes, lo cual es útil cuando hay que diferenciar una repetición reformulada de una información realmente nueva.
Antes de guardar un nuevo hecho, se compara con todos los hechos existentes de ese cliente. Una similitud coseno superior a 0.92 significa “duplicado, omitir”.
¿Por qué ese número? La gente expresa las mismas cosas de muchas maneras. “Prefiere la comunicación por correo electrónico”, “Quiere que se le contacte por correo electrónico” y “Dijo que no revisa mucho su teléfono, prefiere usar el correo electrónico” describen todos un mismo hecho subyacente. Con un valor de 0.92, el sistema detecta de manera fiable estas repeticiones semánticas. Valores más bajos como 0.85 o 0.88 comenzaban a combinar hechos que en realidad eran diferentes, mientras que valores más altos como 0.95 o 0.97 permitían que se acumularan demasiadas reformulaciones.
Esta verificación se realiza en cada ciclo de consolidación. Sin ella, un cliente que mencione su zona horaria en cada conversación generaría docenas de filas casi idénticas, consumiendo espacio de almacenamiento y recursos de búsqueda debido a las repeticiones.
¿Por qué Postgres con pgvector?
Los datos se almacenan en PostgreSQL, donde la extensión pgvector se encarga de las búsquedas de similitud. Una fila customer_memories contiene:
content, el hecho en texto planoembedding, una columna vectorial(3072) utilizada para búsquedas de similitudimportance, la puntuación asignada durante la extracciónsource_channel, el lugar donde se obtuvo el hecho (webchat, whatsapp, voz, etc.)created_at, la fecha y hora de la primera inserciónlast_accessed_at, la última vez que se utilizó en un chat
Un almacén especializado como Qdrant o Pinecone sería la alternativa habitual, pero hay tres razones en contra de ello.
- Las colecciones son muy pequeñas. Como máximo 500 hechos por cliente. Un servicio separado añade un salto en la red, tareas de gestión de conexiones y problemas de consistencia que no son necesarios con ese tamaño.
- Las transacciones son importantes. Los datos pertenecen al registro del cliente. Cuando un cliente se elimina según el GDPR, sus datos deben desaparecer junto con todo lo demás. En pgvector esto se logra con una sola transacción, mientras que un almacén de vectores separado requeriría consistencia distribuida.
- La consulta es sencilla. Se filtra por customer_id mediante una coincidencia exacta y luego se ordena por similitud de vectores, tarea que pgvector maneja eficientemente con un índice compuesto.
La base de conocimientos es otro asunto. Los documentos de productos, las Preguntas Frecuentes y los manuales de políticas se almacenan en Qdrant, ya que esa colección es grande, con miles de documentos por arrendatario, soporta un tráfico intenso y no necesita una relación transaccional con datos relacionales. Problema diferente, herramienta diferente.
Recuperación con límite de tokens
Cuando llega un nuevo mensaje y el agente debe responder, se activa la recuperación desde la memoria:
- Incrustar el mensaje recibido con el mismo modelo de 3072 dimensiones utilizado para el almacenamiento.
- Seleccionar las diez filas más cercanas de
customer_memoriescorrespondientes a ese customer_id, ordenadas según la distancia<=>entre cada incrustación almacenada y el vector de consulta. - Recorrer los resultados en orden de similitud, manteniendo un recuento acumulado de tokens.
- Estimar los tokens de cada hecho como
len(content) / 4, una cifra aproximada pero conservadora. - Detenerse en cuanto la adición del siguiente hecho supere los 2,048 tokens.
- Actualizar
last_accessed_aten cada hecho que se haya recuperado.
El operador <=> calcula la distancia de coseno, por lo que un valor más pequeño indica una coincidencia mayor con el mensaje actual.
El límite de tokens es estricto. El agente recibe los hechos más relevantes que caben en 2,048 tokens, ordenados por relevancia. Si el hecho más importante ocupa 800 tokens, quizás solo quepan dos o tres; y si cada hecho es breve, de 50 a 80 tokens, podrían caber entre quince y veinte. El presupuesto se adapta al contenido real sin necesidad de ajustes manuales. El valor predeterminado de diez filas rara vez es relevante en la práctica, ya que generalmente es el límite de tokens el que limita primero, pero evita que la consulta a la base de datos sea ilimitada.
La escritura en last_accessed_at cumple dos funciones: indica a la política de eliminación qué hechos siguen manteniendo su lugar y muestra qué memorias utiliza realmente el agente y cuáles permanecen sin usar.
El límite de 500 hechos y quiénes son eliminados
Un cliente puede tener un máximo de 500 hechos almacenados. Este límite permite un costo de almacenamiento predecible por cliente y mantiene una recuperación eficiente, ya que la similitud coseno con 500 vectores es rápida y significativa, mientras que con más de 50,000 se vuelve poco fiable.
Cuando la consolidación desea guardar un hecho y el cliente ya tiene 500, comienza el proceso de eliminación. El orden de eliminación es el siguiente:
- Hechos que no han sido modificados durante 90 días o más, ya obsoletos y probablemente irrelevantes en la actualidad.
- Entre los que quedan, aquellos con la puntuación de importancia más baja.
- En caso de empate, se elimina el que tenga la fecha
created_atmás antigua.
Noventa días es un plazo adecuado para el contexto empresarial. Un dato aprendido hace tres meses y que nunca se ha utilizado desde entonces es poco probable que tenga importancia, pero uno aprendido hace seis meses y utilizado semanalmente, como una preferencia de zona horaria, permanece indefinidamente porque su last_accessed_at se actualiza constantemente. La eliminación de datos tiene lugar después de cualquier consolidación que alcance el límite establecido y solo elimina lo necesario, típicamente de uno a tres datos, y no una limpieza masiva.
La memoria y el conocimiento son cosas diferentes
Los dos sistemas resuelven problemas distintos y compiten por el mismo espacio de almacenamiento.
La memoria es por cliente, es pequeña, personal y se obtiene a través de las interacciones: el nombre de la hija es Amara, los informes deben estar en formato PDF, y una queja anterior sobre entregas se resolvió con un crédito del 15%. El conocimiento, en cambio, es por inquilino o es global, es amplio, se comparte y es creado por las personas: documentación del producto, tablas de precios, políticas de devolución y guías de solución de problemas.
Cada uno tiene su propio presupuesto de tokens: 2,048 para la memoria y uno mayor, generalmente de 4,096 a 8,192, para el conocimiento. Comparten la ventana de contexto del modelo sin afectarse mutuamente. Incluso si la memoria utiliza todo su límite, el conocimiento sigue teniendo su presupuesto completo.
Esa división evita un problema grave. Sin presupuestos separados, un cliente con 500 datos detallados podría saturar todas las operaciones de recuperación de conocimiento, y el agente recordaría todo sobre esa persona mientras olvidaba la documentación del producto que necesita para ayudarla.
Cómo la memoria influye en la profundidad del razonamiento
La memoria también alimenta, de dos maneras, al clasificador de complejidad que decide cuánto razonamiento merece una solicitud.
El primero es la señal de “dependencia del contexto”. Cuando la recuperación devuelve hechos altamente relevantes, es decir, una distancia de coseno baja con respecto al mensaje actual, la puntuación de context_dependency aumenta. El clasificador interpreta esto como “la respuesta correcta depende de datos específicos del cliente” y puede enviar la solicitud a un nivel de razonamiento superior. La pregunta “¿Puede verificar mi pedido?” obtiene una puntuación más alta cuando los hechos almacenados mencionan un pedido pendiente, en comparación con la misma pregunta de un cliente sin historial.
El segundo factor es la competencia con el presupuesto de razonamiento. En el modo de cadena de pensamiento completa, el modelo asigna 4,096 o 16,384 tokens para el razonamiento, según la complejidad. Los datos de memoria introducidos en el prompt utilizan tokens del mismo límite finito, por lo que un cliente con 2,048 tokens de memoria deja menos espacio que uno con 200. Estos presupuestos se gestionan de forma independiente y cada uno representa un techo fijo, por lo que el sistema nunca intercambia uno por el otro.
Las partes que siguen siendo difíciles
Hay dos dificultades que no se muestran en el diagrama de arquitectura.
Deriva de los datos. Las preferencias cambian. Lo que antes era “prefiere citas por la mañana” puede convertirse en “prefiere citas por la tarde” tres meses después. El sistema no detecta automáticamente las contradicciones entre los datos nuevos y los antiguos. El umbral del 0.92 a veces las identifica, cuando la nueva afirmación se parece lo suficiente a la antigua como para coincidir, pero no de forma fiable. Por ahora, los datos antiguos siguen activos gracias a la política de antigüedad y acceso, y se está trabajando en una mejor gestión de las contradicciones.
Alucinación por extracción. El LLM encargado de la extracción a veces infiere cosas que nadie dijo. Una pregunta neutral formulada de cierta manera podría almacenarse como “el cliente parece frustrado con el producto”. El umbral de 0.5 elimina las inferencias más débiles, pero no todas. La deduplicación ayuda de forma indirecta, ya que una inferencia inventada rara vez se repite, por lo que permanece como una fila poco utilizada hasta que su eliminación la elimina.
Nada de esto constituye una solución definitiva. Ambos problemas se gestionan mediante el límite máximo, la política de eliminación y la señal de frecuencia de acceso, los cuales, en conjunto, favorecen los hechos recientes, frecuentemente utilizados y de alta importancia. Las conjeturas obsoletas y las preferencias desactualizadas quedan en la parte inferior y se eliminan cuando se necesita espacio.
Dos flujos en resumen
Después de una conversación, el pipeline de consolidación extrae hechos con el LLM, califica su importancia, filtra aquellos con un umbral de 0.5, genera embeddings, elimina duplicados al alcanzar el umbral de coseno de 0.92, almacena lo nuevo y descarta los datos cuando se alcanza el límite de 500 hechos. Antes de generar una respuesta, el mensaje recibido se convierte en un embedding, se recuperan los hechos más relevantes mediante similitud de coseno, se recopilan dentro del límite de 2,048 tokens y se insertan en el contexto del agente.