Ako udržať obrazovo náročné kroky agenta v pamäti
Jeden krok agenta v produkcii minul pamäť pri 952 MB, keď z šiestich skenov katalógu vystrihoval produkty a pozeral si ich výrezy. Nebol to jeden únik – boli tri. Každé volanie modelu znova posielalo obrázky kroku v plnej veľkosti; knižnica, ktorú používame na volanie modelu, držala každú požiadavku živú až do konca kroku; a trasovanie agentského frameworku uchovávalo vstupy každého volania, vrátane obrázkov, počas celého kroku. Opravili sme všetky tri: obrázky sa pred odoslaním zmenšia a obrázky každého volania sa uvoľnia hneď, ako volanie skončí.
Ako agent vidí obrázky
Keď vytvárate v Mythexe, agent pracuje v cloudovom sandboxe vášho projektu. Dokáže sa pozrieť na obrázky – na snímku obrazovky, ktorú pripojíte, na maketu, na súbor vo vašom projekte alebo na obrázok, ktorý sám práve vytvoril – tak, že ich spolu s konverzáciou pošle modelu.
Krok je všetko, čo agent urobí ako odpoveď na jednu vašu správu. V rámci kroku agent modelu volá mnohokrát: premýšľa, spustí nástroj, pozrie sa na výsledok, znova premýšľa. Každé z týchto volaní posiela doterajšiu konverzáciu, a to vrátane obrázkov kroku zakódovaných ako text (base64, čo ich zväčší zhruba o tretinu).
Krok, ktorý spadol, robil niečo rozumné. Vzal šesť skenov katalógu, každý približne 2,4 MB, vystrihol z nich jednotlivé produkty a opakovane si výrezy prečítal, aby ich skontroloval. To znamená veľa volaní modelu, pričom každé nesie niekoľko veľkých obrázkov.
Príčina 1: každé volanie znova posielalo obrázky v plnej veľkosti
Každé volanie modelu znova zostavilo telo požiadavky s obrázkami kroku v plnej veľkosti – približne 20 MB base64 na jedno volanie. Telo sa zostavuje ako jeden reťazec v pamäti agenta, takže každé volanie alokovalo ďalších približne 20 MB.
Posielanie v plnej veľkosti nám navyše nič nedalo. Model si obrázky sám zmenší na zhruba 1 300 pixelov na dlhšej strane, takže dodatočné pixely len zaberali pamäť a čas nahrávania.
Oprava: zmenšiť raz, posielať malé
- Obrázky väčšie ako 400 KB sa pred odoslaním prevedú do JPEG s dlhšou stranou najviac 1 568 pixelov. Menšie obrázky sa posielajú tak, ako sú.
- Prevod robí ImageMagick, ktorý je v každom sandboxe Mythexu, a beží raz na súbor. Krok, ktorý pri každom volaní zobrazuje tie isté skeny, použije znovu zmenšenú kópiu. Cache je viazaná na cestu súboru, veľkosť a čas poslednej úpravy, takže upravený súbor sa prevedie znova, a má vlastný limit veľkosti, aby sa sám nestal príčinou zaplnenej pamäte.
- Rozpočet obrázkov v jednom volaní modelu klesol z 16 MB na 6 MB.
Rovnakých šesť skenov teraz stojí 4,4 MB na volanie namiesto 19,7 MB.
Príčina 2: klient modelu nikdy nepustil požiadavku
Veľkosť každej požiadavky bola len časťou problému. Pamäť tiež rástla volanie za volaním. Na našom staging prostredí ten istý typ kroku držal aj po úplnom garbage collection – bode, kde sa uvoľní všetko, na čo sa nedá dostať – 369 MB živej pamäte. Vzorkovanie haldy pripísalo všetok rast tej časti knižnice klienta modelu, ktorá kóduje telá požiadaviek.
Príčinou bol poslucháč prerušenia. Keď stlačíte Stop, signál prerušenia kroku sa spustí a každá požiadavka, ktorá ho počúva, sa zruší. Tento jeden signál pre celý krok sme odovzdávali každej požiadavke. Klientska knižnica pridá k signálu, ktorý dostane, poslucháča „abort“ – a nikdy ho neodstráni.
Každá požiadavka kroku tak zostala dosiahnuteľná zo signálu kroku, dokým krok trval: poslucháč držal radič požiadavky, radič držal požiadavku a požiadavka držala celé telo s obrázkami.
Oprava: jeden signál na požiadavku
Každá požiadavka teraz dostane vlastný signál. Prepojí sa so signálom kroku iba počas svojho behu – pri streamovanej odpovedi až do prečítania posledného kúska – a hneď potom sa odpojí. Stop stále dosiahne každú požiadavku, ktorá beží, no signál kroku naraz drží najviac jedného poslucháča.
Testy pokrývajú všetky tri časti:
- Po 12 volaniach na signáli kroku nezostanú žiadni poslucháči. Pred opravou ich bolo 12.
- Pri 15 požiadavkách po 8 MB pamäť zostáva vyrovnaná. Predtým rástla o 128 MB.
- Stop stále preruší požiadavku uprostred jej streamu.
Príčina 3: trasovanie držalo vstupy každého volania
Snímka haldy ukázala tretieho držiteľa: približne 6 MB na každé volanie modelu. Pochádzalo to zo streamovania udalostí agentského frameworku. Ten zaznamenáva každé volanie modelu v kroku ako potomka kroku, vrátane vstupov, a to až do konca kroku. Každý obrázok pripojený ku každému volaniu zostával s ním v pamäti.
Oprava: vyprázdniť obrázky, keď volanie vráti výsledok
Obrázky sú pripojené iba k správam zostaveným pre konkrétne volanie modelu. Nikdy sa neukladajú do uloženého stavu konverzácie. Keď sa teda volanie vráti, je bezpečné vyprázdniť dáta obrázkov v týchto správach. Trasovanie si ponechá textový záznam volania; pixely sa uvoľnia.
Dôležitý bol jeden detail: obrázky sa musia vyprázdniť na mieste. Trasovač sa môže k tým istým dátam obrázka dostať cez viac než jednu referenciu v správe, takže nahradenie novým, prázdnym zoznamom by pôvodný obsah – aj s pixelmi – nechalo dosiahnuteľný. Uložený stav konverzácie sa nikdy nemení.
Test spúšťa graf agenta pod rovnakým streamovaním udalostí s obrázkom 4 MB pri každom volaní. Bez opravy pamäť za 16 volaní vzrástla o 77 MB. S ňou pamäť zostáva vyrovnaná.
Čo sme si z toho odniesli
- Problémy s pamäťou môžu byť vrstvené. Tri samostatné príčiny držali obrázky príliš dlho a všetky tri bolo treba odstrániť, aby krok zostal v rámci pamäte.
- Čokoľvek odovzdáte knižnici, si môže ponechať. Signál aj trasovanie prežili volania, ktorým boli odovzdané. Keď pamäť rastie s každým volaním, pozrite sa, ktoré dlhožijúce objekty volanie používa.
- Neposielajte to, čo druhá strana aj tak zahodí. Pixely, ktoré model i tak vyradí, nás pri každom volaní stáli pamäť.
- Testujte pamäť priamo. Každá oprava prišla s testom, ktorý meria rast haldy alebo počet poslucháčov, takže regresia sa prejaví ako číslo, nie ako pád.
Toto je druhý príbeh o pamäti agenta za krátky čas; prvý bol popisok priebehu poslaný znova 41 000-krát. Ak chcete vedieť viac o tom, čo agent je a ako funguje, pozrite náš sprievodca AI agenti a dokumentáciu k chatu.