Atmiņas pārpildes avārija, kas slēpās progresa uzrakstā
Kādu septembra vakaru AI aģents lietotāja darbvietā avarēja ar atmiņas pārpildes kļūdu vidējā gājienā. Acīmredzamie aizdomīgie, pārāk daudz apakšaģentu vienlaicīgi vai konteksts, kas bija pārāk izaudzis, nebija pareizi. Īstais cēlonis bija statusa uzraksts: kamēr modelis straumēja lielu shell komandu pa dažiem rakstzīmēm, mēs katrā gabalā no jauna nosūtījām visu komandu līdz šim kā progresa uzrakstu. Viena 124 KB komanda kļuva par aptuveni 41 000 notikumiem un apmēram 690 MB rindā stāvošu virkņu.
Kā aģents straumē savu darbu
Kad veido Mythex, aģents darbojas tavas projekta privātajā mākoņa smilškastē. Kamēr modelis raksta, tā izvade tiek straumēta atpakaļ uz tavu pārlūku: teksts parādās vārds pēc vārda, un, kad tas izmanto rīku, piemēram, shell komandu, kas raksta failu, redzi tā uzrakstu, kas tiek atjaunināts dzīvi, lai zini, ko tas dara.
Modelis straumē nelielos gabalos. Ar modeli, ko lietojām, tie bieži bija tikai trīs rakstzīmes gari.
Pirmās hipotēzes bija nepareizas
Avārija izskatījās pēc mērogošanas problēmas, tāpēc sākām tur.
- Paralēli apakšaģenti? Gājienā bija izmantoti tikai divi, katrs ar apmēram 1,5 MB stāvokli. Par maz.
- Saglabātas trases? Mūsu izsekošana glabāja izpildes koku atmiņā, bet tas nebija tuvu krāvuma lielumam avārijas brīdī.
Abi stāsti bija ticami, un abus bija viegli ticēt. Neviens neatkārtoja avāriju. Mācība, ko atkal un atkal atklājam: hipotēze nav cēlonis, kamēr tā nav atkārtojusi kļūmi.
Atkārtošana patiesi
Uzbūvējām vienreizēju smilškasti ar tādiem pašiem atmiņas ierobežojumiem kā ražošanā un viltotu modeli, kas straumēja lielu failu realistiskos trīs rakstzīmju gabalos. Mēs arī padarījām lasītāju otrā ligzdas galā lēnu, kā reālu tīklu.
Tas strādāja. Heap auga, un process nomira ar to pašu kļūdu.
Mehānisms bija vienkāršs, kad varējām to noskatīties. Kamēr modelis rakstīja lielu komandu, šajā gadījumā heredoc, kas uzrakstīja 124 KB failu, mūsu straumēšanas kods atjaunināja rīka uzrakstu katrā gabalā. Uzraksts nebija jaunās trīs rakstzīmes; tas bija visa komanda līdz šim. Tātad notikumi auga: 3 rakstzīmes, tad 6, tad 9, līdz 124 KB, aptuveni 41 000 reižu. Ligzda nevarēja nosūtīt tik ātri, cik tie tika radīti, tāpēc tie sakrājās tās rakstīšanas buferī kā virknes, apmēram 690 MB.
Labojums
- Ierobežo uzrakstu. Statusa uzrakstam vajag tikai pateikt, kas notiek. Tagad tas ir ierobežots līdz 200 rakstzīmēm, un mēs ierobežojam, cik bieži atkārtoti skenējam daļējo komandu.
- Pārtrauc kvadrātisko savienošanu. Straumētu gabalu savienošana ar atkārtotu virkņu konkatenāciju lielām izvadēm ir O(n²). Pārgājām uz gabalos balstītu pieeju, kas pievieno lineārā laikā.
Pēc tam meklējām jebko citu, kas var augt bez ierobežojuma no plūdiem, un to ierobežojām:
- Tiešā komandas izvade tērzēšanā tiek grupēta un saglabāta tikai pēdējās 8000 rakstzīmes.
- Atsevišķas notikumu rindas ir ierobežotas līdz 4 MB.
- Atkārtošanas buferis, ko pārlūks izmanto, lai pēc atkal savienošanās paņemtu iepriekšējo, ir ierobežots līdz 8 MB uz projektu.
- Vecie kontrolpunkti tiek apgriezti, kamēr gājiens rit, saglabājot jaunāko stāvokli un enkurus, kas vajadzīgi iepriekšējiem gājieniem.
Plūdu testēšana godīgi
Divas lietas padarīja šo testēšanu grūtāku nekā vajadzētu:
- Īstie modeļi nesadarbojas. Ja lūgsi modelim izdrukāt milzīgu failu, tas parasti atteiksies, apkopos vai uzrakstīs to saprātīgāk. Lai testētu plūdus, vajag skriptotu modeli, kas dara tieši to, ko lūdz, darbojoties caur īsto aģenta kodu.
- Skriptiem jārīkojas kā modeļiem. Mūsu pirmais skriptotais modelis atkārtoti izmantoja to pašu atbildes ID katrā atbildē, tāpēc aģentu ietvars katru atbildi uztvēra kā iepriekšējās aizstāšanu un beidza gājienus pāragri. Izskatījās pēc UI atjaunināšanas kļūdas. Tā nebija; tas bija testa ietvars, kas mūs maldināja. Mums arī vajadzēja skriptā ievērot modeļa reālo konteksta ierobežojumu, citādi atmiņas skaitļi bija nereāli.
Ko no tā guvām
- Straumējošas saskarnes reizina sīkas kļūdas. Viss, ko sūti „katram gabalam“, tiek nosūtīts desmitiem tūkstošu reižu. Sūti izmaiņas vai ierobežo kravu.
- Ierobežo katru buferi, kas šķērso lēnu robežu. Ligzdas, atkārtošanas žurnāli un kontrolpunkti visi vajag griestus.
- Atkārto pirms labošanas. Mūsu pirmie divi skaidrojumi izklausījās pareizi un bija nepareizi.
Ja nesen esi redzējis ļoti garu failu, kas parādījās Mythex tērzēšanā bez aģenta apstāšanās, tā ir daļa no iemesla.