Blogue

Garder les longs tours d'agent dans la fenêtre de contexte

Un modèle ne peut lire qu'une quantité limitée à la fois : sa fenêtre de contexte. Le travail de l'agent de Mythex est souvent long : lire de nombreux fichiers, exécuter des commandes, confier des tâches bornées à des sous-agents. Nous avons constaté trois façons dont un long travail se brisait : des sous-agents grossissaient jusqu'à ce que le modèle refuse toutes leurs requêtes, un sous-agent s'arrêtait tôt parce qu'il croyait ne plus avoir de place, et notre décompte de jetons était très faux pour le texte en russe, en chinois et en japonais. Voici ce que nous avons changé.

Quelques termes d'abord

  • Les jetons sont les morceaux que lit un modèle. Les limites et les coûts se comptent en jetons, et non en caractères ou en mots.
  • La fenêtre de contexte est la quantité maximale qu'un modèle peut lire dans une seule requête. Nous fixons aussi notre propre budget plus bas pour chaque requête, afin de garder des coûts et une vitesse raisonnables.
  • Les résultats d'outils sont ce que l'agent reçoit de ses outils : le contenu d'un fichier lu, la sortie d'une commande exécutée. Dans un long travail, ce sont la plus grande partie de ce qui est envoyé.
  • Un sous-agent est un assistant que l'agent principal lance pour une tâche autonome, par exemple « vérifie ces chapitres par rapport aux notes ». Il reçoit une seule consigne, puis travaille de son côté à travers de nombreux appels d'outils.

Problème 1 : des sous-agents grossissaient jusqu'au refus du modèle

À chaque étape, l'agent envoie au modèle la conversation jusqu'ici. Quand elle devenait trop grosse, notre code la tronquait, mais seulement au début d'un message utilisateur, afin qu'un appel d'outil et son résultat ne soient jamais séparés. Il gardait le premier message, ajoutait une note indiquant que la conversation antérieure avait été tronquée, et conservait les tours utilisateur les plus récents qui tenaient.

Un sous-agent n'a qu'un seul message utilisateur : sa consigne. Il n'y avait donc aucun endroit où couper. Il envoyait donc tout son historique à chaque étape, en grossissant chaque fois, jusqu'à ce que la requête dépasse ce que le modèle accepte du tout, soit environ un million de jetons. Dans un test avec 8 sous-agents de ce type, les 8 ont été refusés.

La correction : vider d'abord les anciens résultats d'outils

Les requêtes tiennent maintenant dans le budget en trois étapes, chacune étant tentée seulement si la précédente n'a pas suffi :

  1. Vider les plus anciens résultats d'outils. Leur contenu est remplacé par une courte note : le résultat a été vidé pour garder la conversation dans le contexte du modèle, et l'agent peut relancer l'outil s'il en a besoin. Un fichier lu il y a une heure est généralement le contenu le plus volumineux et le moins utile de la requête, et le fichier est toujours là pour être relu. Les résultats les plus récents restent intégraux.
  2. Garder des tours utilisateur complets. Comme auparavant : le premier message, une note, et les tours complets les plus récents qui tiennent.
  3. Garder des cycles d'outils complets. À l'intérieur d'un long tour, le seul type que possède un sous-agent, conserver le premier message, une note, et les cycles récents complets de « appeler un outil, obtenir son résultat ».

Cela ne fait que façonner ce qui est envoyé. L'historique enregistré de l'agent conserve tout. Dans le même test, 0 des 8 ont été refusés et les 8 ont été menés à terme.

Vider par lots, pour que la mise en cache reste efficace

Les fournisseurs de modèles peuvent réutiliser le travail effectué sur le début d'une requête si elle est identique à la précédente : c'est un cache de préfixe. Si nous vidions un résultat de plus à chaque appel, le début de la requête changerait à chaque fois et le cache ne servirait jamais.

Les plus anciens résultats sont donc vidés quatre à la fois, et non un par un. La partie vidée reste identique pendant plusieurs appels. Un résultat à peine plus gros que la note n'est pas touché : le vider économiserait presque rien tout en modifiant le début de la requête. La part conservée intégralement est déterminée par la taille, et non par le nombre : les résultats les plus récents qui tiennent dans un quart du budget restent, avec toujours au moins un. Une version précédente gardait six résultats complets, ce qui convenait aux courtes sorties de commandes, mais, avec de longues lectures de fichiers, laissait l'essentiel du budget aux anciens résultats.

Les refus disent maintenant pourquoi

Une requête que le modèle rejette comme invalide n'est plus réessayée ; renvoyer la même requête obtient la même réponse. Si la conversation est trop longue pour le modèle, la personne voit : « Cette conversation est devenue trop longue pour que le modèle la lise d'un seul coup. Commencez un nouveau clavardage pour l'étape suivante ; tout ce qui a été construit jusqu'ici reste. » C'est une décision qui revient à la personne, pas une panne, donc cela ne déclenche pas d'alerte chez nous.

Problème 2 : l'agent s'arrêtait pour « économiser de la place »

Un sous-agent chargé de lire 40 longs chapitres s'est arrêté après 2, en disant vouloir économiser de la place. Il avait utilisé environ 100 000 jetons sur un budget de 400 000.

Il ne pouvait pas savoir que les anciens résultats seraient maintenant vidés pour lui. Nous le lui avons donc dit. Les consignes de l'agent précisent maintenant que lorsque la conversation dépasse ce que le modèle peut accepter, les plus anciens résultats d'outils sont vidés et les plus récents restent intégraux ; il ne faut donc pas interrompre une longue tâche pour économiser de la place. Il faut continuer, et relire un fichier si l'on a besoin de ce qui a été vidé.

Une correction que le modèle ne voit pas n'en est pas une de son point de vue. Le mécanisme n'aide que si l'agent lui fait confiance.

Problème 3 : compter les jetons comme si tout était en anglais

Nous estimions les jetons sans passer par un tokenizer, en divisant le nombre de caractères par quatre. C'est une règle empirique raisonnable pour l'anglais, mais pas pour les autres écritures : le russe compte environ 2,2 caractères par jeton, et le chinois ou le japonais environ un.

Ainsi, un sous-agent qui lisait des chapitres en russe envoyait une requête d'environ 640 000 jetons, alors que notre estimation indiquait qu'elle restait sous le budget de 400 000. L'estimation aurait tout aussi bien pu placer une requête au-delà de la limite stricte du modèle.

L'estimation tient maintenant compte de l'écriture : l'ASCII ordinaire à quatre caractères par jeton, le chinois, le japonais et le coréen à un, et tout le reste (cyrillique, grec, arabe, lettres accentuées, emojis) à deux. Elle est conçue pour pécher par excès. Sur un chapitre en russe, elle estime maintenant 43 423 jetons contre environ 44 600 mesurés ; avant, elle en annonçait 25 023. Comme un message ne change jamais une fois écrit, son estimation est calculée une seule fois et mémorisée, au lieu de l'être à chaque étape.

Ce que nous en avons retenu

  • Tronquez là où se trouve réellement la taille. Dans le travail d'agent, c'est dans les résultats d'outils, et non dans les messages utilisateur.
  • Dites à l'agent quels filets de sécurité existent. Sinon, il planifie en fonction de limites qui ne s'appliquent plus.
  • « Caractères ÷ 4 » est une hypothèse qui vaut pour l'anglais. Tout ce qui compte les jetons pour des utilisateurs multilingues doit compter selon l'écriture, ou utiliser un vrai tokenizer.
  • Surveillez le cache. Une requête qui change au début à chaque appel coûte plus cher et s'exécute plus lentement.

Si vous intégrez des fonctions d'IA dans votre propre app, nos guides sur ce qu'est un LLM et comment utiliser les API de LLM expliquent dès le départ les fenêtres de contexte et les jetons. Pour en savoir plus sur le fonctionnement des sous-agents dans Mythex, consultez la documentation des sous-agents.

Mythex · Pricing · Créez n'importe quoi avec l'IA · Modèles de sites web et d'applications · Mythex comparé · Glossaire de la création d'applications avec l'IA · Outils gratuits pour créer des applications avec l'IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français ગુજરાતી हिन्दी 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 简体中文 繁體中文(香港) 繁體中文(台灣)