ब्लॉग

इमेज-भारी एजेंट टर्न को मेमोरी के भीतर रखना

Production में एक एजेंट टर्न 952 MB पर मेमोरी से बाहर हो गया, जब वह छह catalogue scans से उत्पादों को crop कर रहा था और अपने crops देख रहा था। कोई एक leak नहीं था, तीन थे। मॉडल को हर कॉल में टर्न की इमेज पूरे आकार में दोबारा भेजी जा रही थी; मॉडल कॉल करने वाली library हर request को टर्न खत्म होने तक ज़िंदा रखती थी; और एजेंट फ़्रेमवर्क की tracing हर कॉल के inputs को, इमेज सहित, पूरे टर्न भर रखती थी। हमने तीनों ठीक किए: इमेज भेजने से पहले छोटी की जाती हैं, और हर कॉल की इमेज कॉल पूरी होते ही छोड़ दी जाती है।

एजेंट इमेज कैसे देखता है

Mythex पर बनाते समय एजेंट आपके प्रोजेक्ट के cloud sandbox के भीतर काम करता है। वह इमेज देख सकता है: आपका अटैच किया स्क्रीनशॉट, कोई mockup, प्रोजेक्ट की कोई फ़ाइल, या वह इमेज जो उसने खुद अभी बनाई हो। वह इन्हें बातचीत के साथ मॉडल को भेजकर देखता है।

एक टर्न वह सब है जो एजेंट आपके एक संदेश के जवाब में करता है। एक टर्न के भीतर एजेंट मॉडल को कई बार कॉल करता है: सोचना, एक tool चलाना, नतीजा देखना, फिर सोचना। हर कॉल अब तक की बातचीत भेजती है, और उसमें टर्न की इमेज भी शामिल होती हैं, base64 में टेक्स्ट के रूप में (जो लगभग एक-तिहाई बड़ा हो जाता है)।

जो टर्न क्रैश हुआ, वह एक उचित काम कर रहा था। उसने छह catalogue scans लिए, हर एक लगभग 2.4 MB, उनमें से अलग-अलग उत्पाद काटे, और अपने crops को वापस पढ़ कर जाँचता रहा। यानी कई मॉडल कॉल, और हर एक में कई बड़ी इमेज।

कारण 1: हर कॉल में पूरे आकार की इमेज दोबारा भेजी जा रही थीं

हर मॉडल कॉल अपनी request body को टर्न की इमेज पूरे आकार में रखकर दोबारा बनाती थी, यानी हर कॉल में लगभग 20 MB base64। Body एजेंट की मेमोरी में एक string के रूप में बनती है, इसलिए हर कॉल लगभग 20 MB और आवंटित करती थी।

पूरे आकार में भेजने से कुछ फ़ायदा भी नहीं था। मॉडल खुद इमेज को लंबी भुजा पर लगभग 1,300 pixels तक छोटा कर देता है, इसलिए अतिरिक्त pixels सिर्फ़ मेमोरी और अपलोड का समय खाते थे।

समाधान: एक बार छोटा करो, छोटा भेजो

  • 400 KB से बड़ी इमेज भेजने से पहले JPEG में बदली जाती हैं, जिसकी लंबी भुजा अधिकतम 1,568 pixels होती है। छोटी इमेज जैसी हैं वैसी ही जाती हैं।
  • रूपांतरण ImageMagick से होता है, जो हर Mythex sandbox में पहले से है, और हर फ़ाइल के लिए एक बार चलता है। जो टर्न हर कॉल में वही scans दिखाता है, वह छोटी की गई प्रति दोबारा इस्तेमाल करता है। यह cache फ़ाइल के path, आकार और modification time से पहचाना जाता है, इसलिए बदली गई फ़ाइल फिर से बदली जाती है, और cache की अपनी आकार-सीमा है ताकि वह खुद मेमोरी न भर दे।
  • एक मॉडल कॉल में इमेज के लिए बजट 16 MB से घटकर 6 MB हो गया।

वही छह scans अब हर कॉल में 19.7 MB की जगह 4.4 MB लेते हैं।

कारण 2: मॉडल client ने request को कभी छोड़ा नहीं

हर request का आकार सिर्फ़ एक हिस्सा था। मेमोरी भी कॉल दर कॉल बढ़ती जा रही थी। हमारे staging environment पर वही तरह का टर्न पूरी garbage collection के बाद भी 369 MB ज़िंदा मेमोरी रखे हुए था, यानी वह बिंदु जहाँ जो पहुँच में नहीं है वह मुक्त हो चुका होता है। Heap sampling ने सारी बढ़त उस हिस्से में दिखाई जो model client library का request body encode करने वाला हिस्सा है।

कारण एक abort listener था। जब आप Stop दबाते हैं, तो टर्न का abort signal चलता है, और उस पर सुन रही हर request रद्द हो जाती है। हम हर request को टर्न का एक ही signal दे रहे थे। Client library किसी भी signal पर “abort” listener जोड़ती है, और उसे कभी हटाती नहीं।

तो टर्न की हर request टर्न के signal से तब तक जुड़ी रहती थी जब तक टर्न चलता था: listener, जो controller को पकड़े था, जो request को पकड़ता था, जो अपनी इमेज सहित पूरी request body को पकड़ती थी।

समाधान: हर request का अपना signal

अब हर request को अपना signal मिलता है। वह टर्न के signal से सिर्फ़ तब जुड़ता है जब वह request चल रही हो, और streamed response के लिए आखिरी chunk पढ़े जाने तक, और उसके तुरंत बाद अलग हो जाता है। Stop अब भी चल रही किसी भी request तक पहुँचता है, पर टर्न के signal पर एक समय में बस एक listener होता है।

Tests इन तीनों हिस्सों को कवर करते हैं:

  • 12 कॉल के बाद टर्न के signal पर कोई listener नहीं बचता। फ़िक्स से पहले 12 होते थे।
  • 8 MB वाली 15 requests पर मेमोरी स्थिर रहती है। पहले वह 128 MB बढ़ती थी।
  • Stop अब भी stream के बीच में चल रही request को रद्द करता है।

कारण 3: tracing हर कॉल के inputs रखे हुए थी

Heap snapshot में तीसरा धारक दिखा: हर मॉडल कॉल के लिए लगभग 6 MB। यह एजेंट फ़्रेमवर्क की event streaming से आ रहा था। वह टर्न में हर मॉडल कॉल को टर्न के child के रूप में रिकॉर्ड करती है, inputs सहित, टर्न खत्म होने तक। हर कॉल से जुड़ी हर इमेज उसके साथ मेमोरी में रहती थी।

समाधान: कॉल लौटते ही इमेज खाली करो

इमेज सिर्फ़ किसी खास मॉडल कॉल के लिए बनाए गए messages में जुड़ती हैं। वे कभी बातचीत की सेव की गई state में नहीं रहतीं। इसलिए कॉल लौटते ही उन messages की इमेज का डेटा खाली करना सुरक्षित है। Trace कॉल का टेक्स्ट रिकॉर्ड रखता है; pixels चले जाते हैं।

एक बात मायने रखती थी: इमेज को उसी जगह पर खाली करना होगा। Tracer एक ही इमेज डेटा तक एक message पर एक से ज़्यादा reference से पहुँच सकता है, इसलिए नई खाली list डाल देने से मूल, pixels सहित, फिर भी पहुँच में रहता। सेव की गई बातचीत की state कभी नहीं बदली जाती।

एक test एजेंट के graph को उसी event streaming के तहत चलाता है, हर कॉल पर 4 MB की इमेज के साथ। फ़िक्स के बिना 16 कॉल में मेमोरी 77 MB बढ़ी। फ़िक्स के साथ मेमोरी स्थिर रहती है।

हमने क्या सीखा

  • मेमोरी की समस्याएँ परतों में आ सकती हैं। तीन अलग कारणों ने हर एक इमेज को ज़रूरत से ज़्यादा रोका, और टर्न के मेमोरी के भीतर रहने से पहले तीनों हटाने पड़े।
  • किसी library को जो भी आप देते हैं, वह रखी जा सकती है। Signal और trace दोनों उन calls से ज़्यादा ज़िंदा रहे जिनके लिए वे दिए गए थे। जब मेमोरी हर कॉल के साथ बढ़े, तो देखें कि कॉल कौन-सी लंबी उम्र वाली चीज़ों को छूती है।
  • जो चीज़ दूसरी ओर फेंक दी जानी है, उसे न भेजें। Pixels जिन्हें मॉडल वैसे भी छोड़ देता, हर कॉल पर हमारी मेमोरी लेते थे।
  • मेमोरी की सीधे जाँच करें। हर फ़िक्स के साथ एक test आया जो heap की बढ़त या listeners की गिनती मापता है, ताकि regression एक crash के बजाय एक संख्या के रूप में दिखे।

यह एजेंट के आउटपुट से जुड़ी दूसरी मेमोरी कहानी है, थोड़े ही समय में; पहली थी एक progress label जो 41,000 बार दोबारा भेजा गया। अगर आप जानना चाहते हैं कि एजेंट क्या है और कैसे काम करता है, तो AI एजेंट गाइड और chat docs देखें।

Mythex · Pricing · AI से कुछ भी बनाएँ · वेबसाइट और ऐप टेम्पलेट · Mythex की तुलना · AI से ऐप बनाने की शब्दावली · AI से ऐप बनाने के फ्री टूल · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)