Mantenir els torns llargs de l'agent dins de la finestra de context
Un model només pot llegir una certa quantitat alhora —la seva finestra de context. El agent de Mythex fa treball llarg: llegeix molts fitxers, executa ordres, i delega tasques acotades a subagents. Hem trobat tres maneres en què el treball llarg es trencava: els subagents creixien fins que el model rebutjava totes les peticions, un subagent s'aturava d'hora perquè creia que no tenia prou espai, i el nostre recompte de tokens era molt erroni per al text en rus, xinès i japonès. Aquí explicam què hem canviat.
Primer, alguns termes
- Els tokens són els fragments que llegeix un model. Els límits i els costos es compten en tokens, no en caràcters ni en paraules.
- La finestra de context és el màxim que un model pot llegir en una sola petició. Nosaltres també fixem un pressupost propi, més baix, per a cada petició, perquè els costos i la velocitat siguin raonables.
- Els resultats d'eines són el que l'agent rep de les seves eines: el contingut d'un fitxer que ha llegit, la sortida d'una ordre que ha executat. En el treball llarg són la major part del que s'envia.
- Un subagent és un ajudant que l'agent principal inicia per a una tasca autònoma, com ara «revisa aquests capítols contra les notes». Rep una sola instrucció i després treballa per si mateix a través de moltes crides a eines.
Problema 1: els subagents creixien fins que el model els rebutjava
A cada pas, l'agent envia al model la conversa fins aquell moment. Quan això es feia massa gran, el nostre codi la retallava —però només al començament d'un missatge d'usuari, de manera que una crida a una eina i el seu resultat mai no es separaven. Es quedava el primer missatge, afegia una nota que indicava que la conversa anterior s'havia retallat, i mantenia els torns més recents complets que hi cabien.
Un subagent té exactament un missatge d'usuari: la seva instrucció. No hi havia on tallar. Així que enviava tot el seu historial a cada pas, creixent cada vegada, fins que la petició era més gran que el que el model accepta —uns deu-cents mil tokens. En una prova amb 8 subagents d'aquest tipus, els 8 van ser rebutjats.
La solució: primer buidar els resultats d'eines antics
Ara les peticions s'ajusten al pressupost en tres passos, provant cada un només si l'anterior no n'hi havia prou:
- Buidar els resultats d'eines més antics. El seu contingut es substitueix per una nota breu: el resultat s'ha buidat per mantenir la conversa dins de la finestra del model, i l'agent pot tornar a executar l'eina si la necessita. Un fitxer llegit fa una hora sol ser el més gran i el menys útil de la petició, i el fitxer continua allà per tornar-lo a llegir. Els resultats més recents es mantenen complets.
- Mantenir els torns d'usuari complets. Com abans: el primer missatge, una nota, i els torns complets més recents que hi caben.
- Mantenir les rondes d'eines completes. Dins d'un torn llarg —l'únic tipus que té un subagent— es manté el primer missatge, una nota, i les rondes més recents completes de «crida una eina, obtén el seu resultat».
Això només dona forma al que s'envia. L'historial desat de l'agent ho guarda tot. A la mateixa prova, 0 de 8 van ser rebutjats i tots 8 van acabar.
Buidar per lots, perquè la memòria cau continuï funcionant
Els proveïdors de models poden reutilitzar treball del començament d'una petició si és idèntica a l'anterior —una memòria cau de prefix. Si buidéssim un resultat més a cada crida, el començament de la petició canviaria a cada crida i la memòria cau mai no ajudaria.
Per això, els resultats més antics es buiden de quatre en quatre, no d'un en un. La part buidada es manté igual durant diverses crides. Un resultat no gaire més gran que la nota es deixa tal com és: buidar-lo estalviaria gairebé res i encara canviaria el començament de la petició. Quant es manté complet ho decideix la mida, no el recompte: els resultats més recents que caben en un quart del pressupost es mantenen, i sempre almenys un. Una versió anterior mantenia sis de complets fixos, cosa que era correcta per a sortides d'ordres curtes, però amb lectures de fitxers llargs deixava la majoria del pressupost per a resultats antics.
Els rebutjos ara ho diuen
Una petició que el model rebutja com a no vàlida ja no es torna a intentar; tornar-la a enviar obtindria la mateixa resposta. Si la conversa és massa llarga per al model, la persona veu: «Aquesta conversa s'ha fet massa llarga perquè el model la pugui llegir d'una vegada. Comença un xat nou per al següent pas —tot el que s'ha construït fins ara es conserva.» És una cosa que la persona ha de decidir, no una caiguda, i per això no avisa a l'equip de guàrdia.
Problema 2: l'agent s'aturava per «guardar espai»
Un subagent al qual se li va demanar que llegís 40 capítols llargs es va aturar després de 2, dient que volia guardar espai. Havia usat uns 100.000 tokens d'un pressupost de 400.000.
No tenia manera de saber que els resultats antics ara es buidarien per a ell. Així que li ho vam dir. Les instruccions de l'agent ara diuen que quan una conversa creix més enllà del que el model pot prendre, els resultats d'eines més antics es buiden i els més recents es mantenen complets —així que no aturis una tasca llarga per guardar espai; continua, i torna a llegir un fitxer si necessites el que s'ha buidat.
Una solució que el model no pot veure no és una solució des del punt de vista del model. El mecanisme només ajuda si l'agent hi confia.
Problema 3: comptar tokens com si tot fos anglès
Estimàvem els tokens sense executar un tokenitzador, com a caràcters dividits per quatre. És una regla de polze raonable per a l'anglès. Però no per a altres escriptures: el rus té uns 2,2 caràcters per token, i el xinès o el japonès, uns 1.
Així, un subagent que llegia capítols en rus enviava una petició de uns 640.000 tokens mentre la nostra estimació deia que era per sota del pressupost de 400.000. L'estimació podia igualment haver posat una petició per sobre del límit dur del model.
L'estimació ara compta per escriptura: l'ASCII simple a quatre caràcters per token, el xinès, el japonès i el coreà a un, i tot el demés —ciríl·lic, grec, àrab, lletres accentuades, emoji— a dos. Està pensada per errar per dalt. En un capítol en rus ara estima 43.423 tokens, contra uns 44.600 mesurats; abans deia 25.023. Com que un missatge mai no canvia un cop escrit, la seva estimació es calcula una vegada i es recorda, en lloc de fer-ho a cada pas.
Què n'hem après
- Retalla on és realment la mida. En el treball amb agents, és als resultats d'eines, no als missatges d'usuari.
- Explica a l'agent les seves pròpies xarxes de seguretat. Si no, planifica al voltant de límits que ja no s'apliquen.
- «Caràcters ÷ 4» és una suposició anglesa. Qualsevol cosa que compti tokens per a usuaris multilingües ha de comptar per escriptura, o usar un tokenitzador real.
- Cuida la memòria cau. Una petició que canvia al davant a cada crida costa més i va més lenta.
Si estàs integrant funcions d'IA a la teva pròpia app, les nostres guies sobre què és un LLM i com utilitzar les APIs de LLM cobreixen des del principi les finestres de context i els tokens. Més sobre com funcionen els subagents a Mythex és a la documentació sobre subagents.