მეხსიერების ამოწურვის შეცდომა, რომელიც პროგრესის ეტიკეტში იმალებოდა
სექტემბრის ბოლოს, საღამოს, ერთ-ერთ მომხმარებლის სამუშაო სივრცეში AI აგენტმა გაშვების შუაში მეხსიერების ამოწურვის შეცდომით გაითიშა. აშკარა ეჭვმიტანილები — ერთდროულად ძალიან ბევრი ქვეაგენტი ან კონტექსტი, რომელიც ზედმეტად გაიზარდა — ორივე მცდარი აღმოჩნდა. ნამდვილი მიზეზი სტატუსის ეტიკეტი იყო: მოდელი დიდ shell ბრძანებას რამდენიმე სიმბოლოდ წერდა, ჩვენ კი ყოველ ნაწილზე მთლიან, მანამდე დაწერილ ბრძანებას ვაგზავნიდით პროგრესის ეტიკეტად. 124 KB-იანი ბრძანება დაახლოებით 41 000 ივენთად იქცა და დაახლოებით 690 MB რიგში მდგომი სტრინგად.
როგორ იწერს აგენტი სამუშაოს
როცა Mythex-ზე აგებთ, აგენტი თქვენი პროექტის კერძო ღრუბლის სანდბოქსში მუშაობს. მოდელის წერისას მისი გამოტანა თქვენს ბრაუზერში ნაკადურად მოდის: ტექსტი სიტყვა-სიტყვით ჩნდება, და როცა ის ხელსაწყოს გაუშვებს — მაგალითად shell ბრძანებას, რომელიც ფაილს წერს — ხედავთ ამ ხელსაწყოს ეტიკეტს, რომელიც ცოცხლად ახლდება, რომ იცოდეთ რას აკეთებს.
მოდელი მცირე ნაწილებად ნაკადურად გადმოსცემს. მოდელით, რომელსაც ვიყენებდით, ეს ნაწილები ხშირად მხოლოდ სამი სიმბოლო იყო.
პირველი ჰიპოთეზები არასწორი იყო
ავარია მასშტაბირების პრობლემას ჰგავდა, ამიტომ იქიდან დავიწყეთ.
- პარალელური ქვეაგენტები? გაშვებას მხოლოდ ორი ჰქონდა, თითო დაახლოებით 1.5 MB მდგომარეობით. ეს არ არის საკმარისი.
- შენახული ტრასები? ჩვენი თრეითინგი მეხსიერებაში ინახავდა გაშვების ხეს, მაგრამ ის არ იყო ახლოს იმ ზომასთან, რაც ავარიის დროს ჰიპის ზომა იყო.
ორივე სარწმუნო ამბავი იყო, და ორივე იაფად დასაჯერებელი. არც ერთი არ გამოიწვევდა ავარიას. გაკვეთილი, რომელსაც ხელახლა და ხელახლა ვსწავლობთ: ჰიპოთეზა მიზეზი არ არის, სანამ ავარიას არ გამოიწვევს.
რეალურად გამოწვევა
გავაკეთეთ ცალკე სანდბოქსი იმავე მეხსიერების ლიმიტებით, რაც production-ზეა, და ყალბი მოდელი, რომელიც დიდ ფაილს რეალისტურ სამსიმბოლოიან ნაწილებად ნაკადურად გადმოსცემდა. ასევე ნელი გავხადეთ მკითხველი სოკეტის მეორე მხარეს, როგორც რეალური ქსელი.
ამან გაამართლა. ჰიპი გაიზარდა და პროცესი იგივე შეცდომით დაიღუპა.
მექანიზმი მარტივი აღმოჩნდა, როცა შეგვეძლო მისი ყურება. მოდელი დიდ ბრძანებას წერდა — ამ შემთხვევაში heredoc-ს, რომელიც 124 KB ფაილს წერდა — და ჩვენი ნაკადის კოდი ხელსაწყოს ეტიკეტს ყოველ ნაწილზე განაახლებდა. ეტიკეტი არ იყო ახალი სამი სიმბოლო; ეს იყო მთლიანი, მანამდე დაწერილი ბრძანება. ამიტომ ივენთები იზრდებოდა: 3 სიმბოლო, შემდეგ 6, შემდეგ 9, … 124 KB-მდე, დაახლოებით 41 000-ჯერ. სოკეტს ვერ ასწრებდა გაგზავნას ისე სწრაფად, როგორც იწარმოებოდა, ამიტომ ისინი მის ჩასაწერ ბუფერში სტრინგებად გროვდებოდა — დაახლოებით 690 MB.
გამოსწორება
- ეტიკეტის შეზღუდვა. სტატუსის ეტიკეტს მხოლოდ იმის თქმა სჭირდება, რა ხდება. ახლა ის 200 სიმბოლოთი შემოიფარგლება, ხოლო ნაწილობრივი ბრძანების თავიდან სკანირების სიხშირე შეზღუდულია.
- კვადრატული კონკატენაციის თავიდან აცილება. ნაკადური ნაწილების შეერთება განმეორებითი სტრინგური კონკატენაციით დიდი გამოტანისთვის O(n²) არის. გადავედით ნაწილებზე დაფუძნებულ მიდგომაზე, რომელიც ხაზოვან დროში ამატებს.
ამის შემდეგ ვეძებეთ სხვა რამე, რაც შეიძლება შეუზღუდავად გაიზარდოს გამოტანის ნაკადზე, და შევზღუდეთ:
- ჩატში ნაჩვენები ცოცხალი ბრძანების გამოტანა იკრიბება და ინახება ბოლო 8 000 სიმბოლო.
- ცალკეული ივენთის ხაზები შეზღუდულია 4 MB-ით.
- რეპლეის ბუფერი, რომლითაც ბრაუზერი აწყობს კავშირის აღდგენის შემდეგ, შეზღუდულია 8 MB-ით პროექტზე.
- ძველი checkpoint-ები იშლება, როცა გაშვება მიდის — ინახება უახლესი მდგომარეობა და წინა გაშვებებისთვის საჭირო წერტილები.
გადაცემების ნამდვილი ტესტირება
ორმა რამ ამ შემოწმებას უფრო რთულს ხდიდა, ვიდრე უნდა ყოფილიყო:
- რეალური მოდელები არ თანამშრომლობს. თუ მოდელს გიგანტური ფაილის დაბეჭდვას სთხოვთ, ის ჩვეულებრივ უარს იტყვის, შეაჯამებს ან უფრო გონივრულად დაწერს. ნაკადების ტესტირებისთვის გჭირდებათ სკრიპტირებული მოდელი, რომელიც ზუსტად ის აკეთებს, რაც უთხარით, რეალური აგენტის კოდით გაშვებული.
- სკრიპტები მოდელივით უნდა იქცეოდეს. ჩვენი პირველი სკრიპტირებული მოდელი ყოველ პასუხზე ერთსა და იმავე პასუხის ID-ს იყენებდა, ამიტომ აგენტის ჩარჩო ყოველ პასუხს წინას ჩანაცვლებად აღიქვამდა და გაშვებებს ადრე ამთავრებდა. ეს UI-ის განახლების ბაგად გამოიყურებოდა. არ იყო ასე — ტესტის ჰარნესი გვატყუებდა. ასევე მოგვიწია სკრიპტში მოდელის რეალური კონტექსტის ლიმიტის აღსრულება, თორემ მეხსიერების რიცხვები არარეალისტური იქნებოდა.
რა ვისწავლეთ
- ნაკადური ინტერფეისები მცირე შეცდომებს ამრავლებს. ყველაფერი, რაც „ნაწილზე“ იგზავნება, ათიათასობით ჯერ იგზავნება. გაგზავნეთ დელტები, ან შეზღუდეთ დატვირთვა.
- შეზღუდეთ ყოველი ბუფერი, რომელიც ნელ საზღვარს კვეთს. სოკეტებს, რეპლეის ლოგებსა და checkpoint-ებს ყველას სჭირდება ზღვარი.
- გაასწორეთ მანამ, სანამ ხელახლა არ გააკეთებთ. ჩვენი პირველი ორი ახსნა სწორად ჟღერდა და არასწორი აღმოჩნდა.
თუ ბოლო ხანს Mythex-ის ჩატში ძალიან გრძელი ფაილი გამოჩნდა აგენტის შეჩერების გარეშე, ეს ნაწილობრივ ამის გამოა.