المدوّنة

انهيار نفاد الذاكرة المختبئ في تسمية تقدم

في أواخر سبتمبر، انهار الوكيل الذكي في مساحة عمل أحد المستخدمين بخطأ نفاد الذاكرة في منتصف دور. كانت الاشتباهات الواضحة، أي تشغيل عدد كبير جداً من الوكلاء الفرعيين في وقت واحد، أو سياق نما أكثر من اللازم، خاطئة كلتاهما. السبب الحقيقي كان تسمية حالة: أثناء بث النموذج لأمر shell كبير بضعة أحرف في كل مرة، كنا نعيد إرسال الأمر كاملاً حتى تلك اللحظة كتسمية تقدم مع كل قطعة. أمر واحد بحجم 124 KB تحوّل إلى نحو 41,000 حدث، وقرابة 690 MB من السلاسل النصية في الانتظار.

كيف يبث الوكيل عمله

عندما تبني على Mythex، يعمل الوكيل داخل بيئة التشغيل السحابية الخاصة بالمشروع. أثناء كتابة النموذج، يتدفق ناتجه إلى متصفحك: يظهر النص كلمة بكلمة، وعندما يشغّل أداة، مثل أمر shell يكتب ملفاً، ترى تسمية لها تتحدث مباشرة، فتعرف ما الذي يفعله.

يبث النموذج على شكل قطع صغيرة. مع النموذج الذي كنا نستخدمه، كانت تلك القطع غالباً ثلاثة أحرف فقط.

الفرضيات الأولى كانت خاطئة

بدا الانهيار كمشكلة في القياس، فبدأنا من هناك.

  • وكلاء فرعيون متوازون؟ استخدم الدور وكيلين فقط، يحمل كل منهما نحو 1.5 MB من الحالة. وهذا لا يكفي.
  • آثار محفوظة؟ كان التتبع لدينا يحتفظ بشجرة التشغيل في الذاكرة، لكنها لم تكن قريبة من حجم الكومة وقت الانهيار.

كلتا الحكايتين كانتا معقولتين، وكلتاهما كانتا سهلتين في التصديق. ولم تعيدا إنتاج الانهيار. الدرس الذي نتعلمه مراراً: الفرضية ليست سبباً حتى تعيد إنتاج الفشل.

إعادة الإنتاج فعلياً

بنينا بيئة تجريبية مؤقتة بنفس حدود الذاكرة الموجودة في الإنتاج، ونموذجاً مزيفاً يبث ملفاً كبيراً بقطع واقعية من ثلاثة أحرف. وجعلنا القارئ في الطرف الآخر من المقبس بطيئاً، كما هي الشبكة الحقيقية.

وهذا كان كافياً. ارتفعت الكومة وانتهت العملية بالخطأ نفسه.

الآلية كانت بسيطة بمجرد أن أمكن مراقبتها. أثناء كتابة النموذج لأمر كبير، وفي هذه الحالة heredoc يكتب ملفاً بحجم 124 KB، كان كود البث لدينا يحدّث تسمية الأداة مع كل قطعة. والتسمية لم تكن الأحرف الثلاثة الجديدة، بل الأمر كاملاً حتى تلك اللحظة. فنمت الأحداث: 3 أحرف، ثم 6، ثم 9، … حتى 124 KB، نحو 41,000 مرة. ولم يستطع المقبس إرسالها بسرعة إنتاجها، فتراكمت في مخزن الكتابة المؤقت لديه كسلاسل نصية، بنحو 690 MB منها.

الإصلاح

  • حدّ التسمية. تحتاج التسمية فقط إلى أن تقول ما يحدث. صارت الآن محصورة في 200 حرف، ونحدد وتيرة إعادة مسح الأمر الجزئي.
  • أوقف الدمج التربيعي. ربط القطع المبثوثة بتكرار دمج السلاسل النصية يكلف O(n²) للمخرجات الكبيرة. انتقلنا إلى نهج قائم على الكتل يُلحق بزمن خطي.

ثم بحثنا عن أي شيء آخر يمكن أن ينمو دون حدود مع سيل من المخرجات، وحدّدناه:

  • مخرجات الأوامر الحية المعروضة في الدردشة تُجمَّع وتُحفظ آخر 8,000 حرف منها.
  • أسطر الأحداث الفردية محدودة بـ 4 MB.
  • مخزن إعادة التشغيل الذي يستخدمه المتصفح للحاق بالأحداث بعد إعادة الاتصال محدود بـ 8 MB لكل مشروع.
  • تُقلَّم نقاط الحفظ القديمة أثناء سير الدور، مع الاحتفاظ بأحدث حالة والمراسي التي تحتاجها الأدوار السابقة.

اختبار الفيضانات بأمانة

شيئان جعلا الاختبار أصعب مما ينبغي:

  1. النماذج الحقيقية لا تتعاون. إذا طلبت من نموذج أن يطبع ملفاً ضخماً، فغالباً سيرفض أو يلخص أو يكتبه بطريقة أكثر عقلانية. لاختبار الفيضانات تحتاج إلى نموذج مبرمج يفعل بالضبط ما تقوله، ويعمل عبر كود الوكيل الحقيقي.
  2. يجب أن تتصرف السكربتات مثل النماذج. أعاد نموذجنا المبرمج الأول استخدام معرّف الاستجابة نفسه في كل رد، فعاملت إطار عمل الوكيل كل رد كبديل للرد الذي قبله، وأنهت الأدوار مبكراً. بدا الأمر كخلل في تحديث الواجهة، لكنه لم يكن كذلك، بل كان أداة الاختبار تكذب علينا. واضطررنا أيضاً إلى فرض حد السياق الحقيقي للنموذج في السكربت، وإلا كانت أرقام الذاكرة غير واقعية.

ما الذي استخلصناه

  • واجهات البث تضخّم الأخطاء الصغيرة. أي شيء ترسله «لكل قطعة» يُرسل عشرات الآلاف من المرات. أرسل الفروق، أو حدّد حجم الحمولة.
  • حدّد كل مخزن مؤقت يعبر حداً بطيئاً. المقابس وسجلات إعادة التشغيل ونقاط الحفظ كلها تحتاج إلى سقف.
  • أعد الإنتاج قبل الإصلاح. التفسيران الأولان بدا أنهما صحيحان، وكانا خاطئين.

إذا لاحظت ملفاً طويلاً جداً يظهر في دردشة Mythex مؤخراً دون أن يتوقف الوكيل، فهذا جزء من السبب.

Mythex · Pricing · ابنِ أي شيء بالذكاء الاصطناعي · قوالب المواقع والتطبيقات · مقارنات Mythex · مصطلحات بناء التطبيقات بالذكاء الاصطناعي · أدوات مجانية لبناء التطبيقات بالذكاء الاصطناعي · 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 简体中文 繁體中文(香港) 繁體中文(台灣)