Holde agentturer med mange bilder innenfor minnet
En agenttur i produksjon gikk tom for minne ved 952 MB mens den klippet ut produkter fra seks katalogskanninger og så på klippene sine. Det var ikke én lekkasje, det var tre. Hvert kall til modellen sendte turens bilder på nytt i full størrelse. Biblioteket vi bruker for å kalle modellen, beholdt hver forespørsel i live til turen var over. Sporingen i agentrammeverket beholdt hvert kalls inndata, bilder inkludert, gjennom hele turen. Vi fikset alle tre: bilder krympes før de sendes, og hvert kalls bilder slippes fri så snart kallet er ferdig.
Slik ser agenten bilder
Når du bygger på Mythex, jobber agenten i prosjektets sky-sandkasse. Den kan se på bilder, for eksempel et skjermbilde du legger ved, en mockup, en fil i prosjektet ditt eller et bilde den nettopp har laget selv, ved å sende dem til modellen sammen med samtalen.
En tur er alt agenten gjør som svar på én melding fra deg. Innenfor en tur kaller agenten modellen mange ganger: tenke, kjøre et verktøy, se på resultatet, tenke igjen. Hvert av disse kallene sender samtalen så langt, og det inkluderer turens bilder, kodet som tekst (base64, som gjør dem omtrent en tredjedel større).
Turen som krasjet, gjorde noe fornuftig. Den tok seks katalogskanninger på omtrent 2,4 MB hver, klippet ut enkeltprodukter fra dem og leste klippene tilbake for å kontrollere dem. Det er mange modellkall, og hvert bærer flere store bilder.
Årsak 1: hvert kall sendte fulle bilder på nytt
Hvert modellkall bygde forespørselskroppen på nytt med turens bilder i full størrelse, omtrent 20 MB base64 per kall. Kroppen bygges som én streng i agentens minne, så hvert kall allokerte ytterligere ~20 MB.
Å sende full størrelse ga heller ingenting. Modellen skalerer selv bilder ned til omtrent 1 300 piksler på lengste side, så de ekstra pikslene koster bare minne og opplastingstid.
Løsningen: krymp én gang, send lite
- Bilder over 400 KB konverteres nå til en JPEG med høyst 1 568 piksler på lengste side før de sendes. Mindre bilder sendes som de er.
- Konverteringen bruker ImageMagick, som følger med i hver Mythex-sandkasse, og kjøres én gang per fil. En tur som viser de samme skanningene i hvert kall, gjenbruker den krympede kopien. Hurtigbufferen er nøklet på filens sti, størrelse og endringstid, så en redigert fil konverteres på nytt. Den har også en egen størrelsesgrense, slik at den ikke kan bli det som fyller minnet.
- Budsjettet for bilder i ett modellkall går ned fra 16 MB til 6 MB.
De samme seks skanningene koster nå 4,4 MB per kall i stedet for 19,7 MB.
Årsak 2: modellklienten slapp aldri en forespørsel
Størrelsen på hver forespørsel var bare én del av det. Minnet vokste også kall for kall. På staging-miljøet vårt holdt samme type tur 369 MB med levende minne selv etter en full søppelinnsamling, altså punktet der alt som ikke kan nås, er frigjort. Heap-sampling plasserte all veksten i den delen av modellklientbiblioteket som koder forespørselskropper.
Årsaken var en abort-lytter. Når du trykker Stopp, fyres turens abort-signal av, og hver forespørsel som lytter, avbrytes. Vi sendte det ene signalet for hele turen til hver forespørsel. Klientbiblioteket legger til en «abort»-lytter på signalet det får, og fjerner den aldri.
Så hver forespørsel i en tur ble stående nåbar fra turens signal, så lenge turen varte: lytteren, som holdt kontrolleren, som holdt forespørselen, som holdt hele forespørselskroppen med bildene sine.
Løsningen: ett signal per forespørsel
Hver forespørsel får nå sitt eget signal. Det kobles til turens signal bare mens den forespørselen kjører, for en strømmet respons til siste del er lest, og kobles fra rett etterpå. Stopp når fortsatt den forespørselen som pågår, men turens signal holder bare én lytter om gangen.
Testene dekker alle tre delene:
- Etter 12 kall er det ingen lyttere igjen på turens signal. Før fiksen var det 12.
- Over 15 forespørsler på 8 MB hver holder minnet seg flatt. Før vokste det med 128 MB.
- Å trykke Stopp avbryter fortsatt en forespørsel midt i en strøm.
Årsak 3: sporing beholdt hvert kalls inndata
Et heap-øyeblikksbilde viste en tredje holder: omtrent 6 MB per modellkall. Dette kom fra agentrammeverkets hendelsesstrømming. Den registrerer hvert modellkall i en tur som et barn av turen, inndata inkludert, til turen er over. Hvert bilde knyttet til hvert kall ble liggende i minnet sammen med det.
Løsningen: tøm bildene når kallet er ferdig
Bilder knyttes bare til meldingene som bygges for et bestemt modellkall. De lagres aldri i samtalens lagrede tilstand. Så når et kall er ferdig, er det trygt å tømme bildedataene i disse meldingene. Sporingen beholder en tekstlig oppføring av kallet; pikslene forsvinner.
Én detalj var avgjørende: bildene må tømmes på stedet. Sporeren kan nå de samme bildedataene via mer enn én referanse på en melding. Hvis vi byttet inn en ny, tom liste, ville originalen, piksler og alt, fortsatt være nåbar. Den lagrede samtalestanden endres aldri.
En test kjører agentens graf under samme hendelsesstrømming med et 4 MB-bilde på hvert kall. Uten fiksen vokste minnet med 77 MB over 16 kall. Med den holder minnet seg flatt.
Det vi tok med oss
- Minneproblemer kan komme i lag. Tre separate årsaker holdt hver for seg bilder for lenge, og alle tre måtte bort før turen holdt seg innenfor minnet.
- Alt du gir til et bibliotek, kan bli beholdt. Et signal og en sporing overlevde kallene de ble gitt til. Når minnet vokser per kall, se på hvilke langlevde objekter kallet berører.
- Ikke send det motparten kaster. Piksler modellen uansett ville forkastet, kostet oss minne på hvert kall.
- Test minnet direkte. Hver fiks kom med en test som måler heap-vekst eller antall lyttere, slik at en regresjon viser seg som et tall, ikke et krasj.
Dette er den andre minnehistorien fra agenten på kort tid. Den første var en fremdriftsetikett som ble sendt på nytt 41 000 ganger. Hvis du vil vite mer om hva agenten er og hvordan den fungerer, se vår guide til AI-agenter og chat-dokumentasjonen.