Blog

Mantener los turnos largos del agente dentro de la ventana de contexto

Un modelo solo puede leer cierta cantidad a la vez: su ventana de contexto. El agente de Mythex hace trabajos largos: lee muchos archivos, ejecuta comandos y delega tareas acotadas en subagentes. Encontramos tres formas en que el trabajo largo se rompía: los subagentes crecían hasta que el modelo rechazaba todas sus peticiones, un subagente paraba antes de tiempo porque creía que no le quedaba espacio, y nuestro recuento de tokens era muy incorrecto para textos en ruso, chino y japonés. Esto es lo que cambiamos.

Algunos términos primero

  • Los tokens son los fragmentos que lee un modelo. Los límites y los costes se cuentan en ellos, no en caracteres ni en palabras.
  • La ventana de contexto es lo máximo que un modelo puede leer en una petición. Nosotros además fijamos un presupuesto propio más bajo para cada petición, para que los costes y la velocidad sigan siendo razonables.
  • Los resultados de herramientas son lo que el agente recibe de sus herramientas: el contenido de un archivo que leyó, la salida de un comando que ejecutó. En un trabajo largo, son la mayor parte de lo que se envía.
  • Un subagente es un ayudante que el agente principal lanza para una tarea autocontenida, como «comprueba estos capítulos contra las notas». Recibe una sola instrucción y luego trabaja con muchas llamadas a herramientas por su cuenta.

Problema 1: los subagentes crecían hasta que el modelo los rechazaba

En cada paso, el agente envía al modelo la conversación hasta ese momento. Cuando se volvía demasiado grande, nuestro código la recortaba, pero solo al principio de un mensaje de usuario, para que una llamada a herramienta y su resultado nunca se separaran. Conservaba el primer mensaje, añadía una nota indicando que la conversación anterior se había recortado, y mantenía los turnos completos más recientes que cabían.

Un subagente tiene exactamente un mensaje de usuario: su instrucción. No había dónde cortar. Así que enviaba su historial completo en cada paso, creciendo cada vez, hasta que la petición superaba lo que el modelo acepta en absoluto: alrededor de un millón de tokens. En una prueba con 8 de esos subagentes, los 8 fueron rechazados.

La solución: borrar primero los resultados de herramientas antiguos

Ahora las peticiones encajan en el presupuesto en tres pasos, probando cada uno solo si el anterior no bastó:

  1. Borrar los resultados de herramientas más antiguos. Su contenido se sustituye por una nota breve: el resultado se borró para mantener la conversación dentro del contexto del modelo, y el agente puede volver a ejecutar la herramienta si lo necesita. Un archivo leído hace una hora suele ser lo más grande y lo menos útil de la petición, y el archivo sigue ahí para volver a leerlo. Los resultados más nuevos se conservan enteros.
  2. Mantener turnos de usuario completos. Como antes: el primer mensaje, una nota y los turnos completos más recientes que quepan.
  3. Mantener rondas de herramienta completas. Dentro de un turno largo —el único tipo que tiene un subagente—, conservar el primer mensaje, una nota y las rondas más recientes completas de «llama a una herramienta, obtén su resultado».

Esto solo da forma a lo que se envía. El historial guardado del agente conserva todo. En la misma prueba, 0 de 8 fueron rechazados y los 8 terminaron.

Borrar por lotes, para que la caché siga funcionando

Los proveedores de modelos pueden reutilizar trabajo del inicio de una petición si es idéntico a la última: una caché de prefijos. Si borráramos un resultado más en cada llamada, el inicio de la petición cambiaría en cada llamada y la caché nunca serviría de nada.

Por eso los resultados más antiguos se borran de cuatro en cuatro, no de uno en uno. La parte borrada se mantiene igual durante varias llamadas. Un resultado que no es mucho más grande que la nota se deja en paz: borrarlo ahorraría casi nada y aun así cambiaría el inicio de la petición. Lo que se conserva entero se decide por tamaño, no por número: los resultados más recientes que quepan en una cuarta parte del presupuesto se mantienen, y siempre al menos uno. Una versión anterior mantenía fijos seis enteros, lo cual era correcto para salidas cortas de comandos, pero con lecturas de archivos largas dejaba la mayor parte del presupuesto en resultados antiguos.

Los rechazos ahora lo dicen

Una petición que el modelo rechaza como no válida ya no se reintenta; volver a enviar la misma petición da la misma respuesta. Si la conversación es demasiado larga para el modelo, la persona ve: «Esta conversación es demasiado larga para que el modelo la lea de una vez. Empieza un chat nuevo para el siguiente paso; todo lo construido hasta ahora se conserva.» Eso es algo que corresponde decidir a la persona, no una caída, así que no nos avisa.

Problema 2: el agente paraba para «ahorrar espacio»

Un subagente al que se le pidió leer 40 capítulos largos se detuvo tras 2, diciendo que quería ahorrar espacio. Había usado unos 100.000 tokens de un presupuesto de 400.000.

No tenía forma de saber que los resultados antiguos se borrarían ahora por él. Así que se lo dijimos. Las instrucciones del agente ahora indican que, cuando una conversación crece más allá de lo que el modelo puede aceptar, los resultados de herramientas más antiguos se borran y los más recientes se conservan enteros; así que no detengas una tarea larga para ahorrar espacio: sigue, y vuelve a leer un archivo si necesitas lo que se borró.

Un arreglo que el modelo no puede ver no es un arreglo desde el punto de vista del modelo. El mecanismo solo ayuda si el agente confía en él.

Problema 3: contar tokens como si todo fuera inglés

Estimábamos los tokens sin ejecutar un tokenizador, como caracteres divididos entre cuatro. Es una regla práctica razonable para el inglés. No lo es para otros alfabetos: el ruso tiene unos 2,2 caracteres por token, y el chino o el japonés, alrededor de uno.

Así que un subagente que leía capítulos en ruso enviaba una petición de unos 640.000 tokens mientras nuestra estimación decía que estaba por debajo del presupuesto de 400.000. La estimación podría igualmente haber puesto una petición por encima del límite duro del modelo.

Ahora la estimación cuenta por alfabeto: el ASCII normal a cuatro caracteres por token, el chino, el japonés y el coreano a uno, y todo lo demás —cirílico, griego, árabe, letras acentuadas, emoji— a dos. Está pensada para equivocarse por exceso. En un capítulo en ruso, ahora estima 43.423 tokens frente a unos 44.600 medidos; antes decía 25.023. Como un mensaje nunca cambia una vez escrito, su estimación se calcula una vez y se recuerda, en lugar de hacerlo en cada paso.

Lo que aprendimos

  • Recorta donde está realmente el tamaño. En el trabajo del agente, eso son los resultados de herramientas, no los mensajes de usuario.
  • Cuéntale al agente sobre sus propias redes de seguridad. Si no, planifica alrededor de límites que ya no se aplican.
  • «Caracteres entre 4» es una suposición del inglés. Cualquier cosa que cuente tokens para usuarios multilingües necesita contar por alfabeto, o usar un tokenizador real.
  • Cuida la caché. Una petición que cambia al principio en cada llamada cuesta más y va más lenta.

Si estás añadiendo funciones de IA a tu propia app, nuestras guías sobre qué es un LLM y cómo usar las APIs de LLM explican las ventanas de contexto y los tokens desde el principio. Más sobre cómo funcionan los subagentes en Mythex está en la documentación de subagentes.

Mythex · Pricing · Crea lo que quieras con IA · Plantillas de sitios web y apps · Mythex comparado · Glosario de creación de apps con IA · Herramientas gratuitas para crear apps con IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)