Cómo mantengo el contexto de una conversación con IA usando una ventana deslizante
Mientras desarrollaba Domira me encontré con un problema: ¿cómo mantener el contexto de una conversación con IA sin enviar todo el historial en cada llamada?
La solución fue crear una ventana cruda deslizante y un resumen acumulativo. En este artículo explico cómo la implementé y algunas decisiones que tuve que tomar en el camino.
El problema
Las APIs de IA (OpenAI, Claude, Gemini) que uso para Domira son “stateless”, es decir, no guardan estado. Esto significa que cuando mando una petición, la IA me responde y se olvida de la conversación, algo como esto:
Primera llamada
- Hola, me llamo Pablo.
- Hola Pablo, ¿cómo estás hoy?
Segunda llamada
- Hola, ¿cómo me llamo?
- Hola, no tengo esta información.
Entonces con cada llamada es necesario enviar el contexto de la conversación. Mi primer pensamiento fue almacenar cada pregunta con su respectiva respuesta, y en cada nueva llamada enviar todas juntas. Esto técnicamente funcionaría, pero entonces estaría inflando la cantidad de tokens y el tiempo de respuesta, e incluso podría llegar al límite de contexto del modelo.
¿Cómo lo resolví?
La decisión correcta fue separar la memoria reciente de la memoria vieja. En vez de mandar el historial completo, envío:
- Ventana cruda deslizante. Los últimos N intercambios tal cual ocurrieron, sin cambios.
- Resumen acumulativo. Todo lo que salió de esa ventana lo resumo (con otra llamada a la IA) y lo mando junto con la ventana. A este resumen le voy añadiendo lo que va saliendo de la ventana en cada iteración.
Con esto logré enviarle a la IA el detalle fino de lo reciente y una memoria resumida de lo viejo, y además mi prompt nunca continúa creciendo sin control.
Sobre la señal y el ruido
- Señal. Es la información útil de una transmisión, la que tiene propósito y significado.
- Ruido. Es cualquier interferencia, dato irrelevante, distorsión o datos corruptos.
Si la llamada a la IA generó ruido, entonces lo identifico con ciertas reglas, para no considerarlo ni en la ventana ni en el resumen.
El checkpoint
El checkpoint me dice qué ya está resumido y qué sigue pendiente. La ventana, en cambio, se calcula aparte (siempre son los últimos N con señal, sin depender del checkpoint) para que siga siendo correcta aunque cambie el tamaño de la ventana más adelante.
Los elementos dentro de la ventana se envían a la IA como pares usuario/asistente para darle a la IA la estructura de una conversación real. El resumen acumulativo se construye como texto plano.
El fold-in
El fold-in es el proceso de realizar el resumen acumulativo que normalmente consistirá en añadir un solo elemento. Como crear un resumen es un proceso relativamente sencillo para la IA, utilicé un modelo más económico para esta tarea.
En el prompt que uso para crear el resumen, le indico a la IA que no pierda información crítica, tomando en cuenta cosas como preservar textualmente fechas/montos/decisiones/compromisos, organizar cronológicamente, no repetir contenido redundante, no inventar nada que no esté en el resumen o en lo nuevo, y si hay que acortar, priorizar hechos concretos sobre información genérica.
Una pequeña trampa
En Domira hay un ajuste que indica si la IA debe entregarte textos hablando “de tú” o “de usted” a tu cliente. Al principio estaba enviando como parte del contexto lo siguiente: “Tratamiento: de usted”. El modelo lo interpretó como que me debía hablar “de usted” a mí, en vez de entender que debía incorporarlo en los textos hacia mis clientes.
La solución fue simplemente ser más específico: “Tratamiento que el VENDEDOR debe usar con ESTE PROSPECTO (esto no describe cómo te diriges tú, el asistente, al vendedor): de usted”.
Modo depuración
Mientras construía esta función, antes de evaluar la respuesta de la IA, tuve que hacer muchas pruebas para ver cómo se estaba enviando la información. Con una bandera “modo” puedo encender una función en la que no mando nada a la IA, pero se muestran en pantalla la ventana y el resumen acumulativo, además de otra información importante para depurar. Esto es útil para no gastar tiempo ni tokens.
Conclusión
Esta solución me permitió mantener conversaciones con contexto sin tener que enviar todo el historial en cada llamada. La ventana cruda deslizante conserva el detalle de lo reciente y el resumen acumulativo mantiene lo importante de todo lo anterior.
Más que encontrar una solución sofisticada, el objetivo fue encontrar una que pudiera entender, depurar y mantener de forma sencilla.