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

في يوليو 2026 توقفت عدة ميزات عن العمل دفعة واحدة: دردشة الذكاء الاصطناعي، وردود الذكاء الاصطناعي في التذاكر، وملخصات التذاكر، ومنشئ السيرفرات، إضافةً إلى الإشراف على الأفكار وبلاغات الأخطاء وترجمتها.
لم يكن السبب في الكود الخاص بنا. فقد أحال مزوّد الذكاء الاصطناعي لدينا النموذج الذي كنا نستخدمه إلى التقاعد.
الجزء الأول: النموذج لم يعد موجودًا
هذا هو الجزء البديهي، وقد أُصلح بسرعة. يوقف المزوّد نموذجًا، فتُدخل النموذج الذي خلفه، وانتهى الأمر.
الحادثة الفعلية بدأت بعد ذلك.
الجزء الثاني: ردود فارغة، دون أخطاء
بعد التبديل عادت الردود. لكنها كانت أحيانًا فارغة. ليست مقطوعة، وليست مشوّهة، بل رد فارغ تمامًا دون أي خطأ على الإطلاق.
يكمن السبب في فرق لا يكشفه اسم النموذج: النموذج الخلف هو نموذج استدلال (Reasoning Model). قبل الإجابة الفعلية يكتب أولًا سلسلة تفكير داخلية في حقل منفصل. وكلاهما يسحب من ميزانية الرموز (Tokens) نفسها.
إذا استُهلكت الميزانية في التفكير، يعود رد سليم من الناحية الشكلية: يبلّغ المزوّد بأن «الحد الأقصى للطول قد بُلغ»، ويكون حقل المحتوى فارغًا. لا خطأ، ولا إشارة، ولا شيء يمكن أن يراه try/catch.
أعدنا إنتاج ذلك باختبار حقيقي: ميزانية من خمسة رموز تكفي وحدها لإنتاج رد فارغ في كل طلب.
الجزء الثالث: الفاتورة
في أغلى موضع استدعاء، أي منشئ السيرفرات بالذكاء الاصطناعي، كنا قد ضبطنا ميزانية سخية لأن الإجابات هناك طويلة. فلم يصطدم التفكير بحد، بل استمر ببساطة.
جاءت العواقب من اتجاهين في آن واحد. استغرقت الطلبات وقتًا طويلًا حتى تجاوزت المهلات الزمنية. وكلّفت أضعافًا، لأننا كنا ندفع في كل مرة ثمن سلسلة تفكير كاملة غير مرئية. وفي النهاية جاءت رسالة خطأ لم نخطط لها: الرصيد غير كافٍ.
الإصلاح سطر واحد. يمكن تعطيل التفكير في جسم الطلب، فيتصرف النموذج حينها مثل النموذج القديم مجددًا. ومنذ ذلك الحين ينتمي هذا السطر إلى كل موضع استدعاء، وهناك أكثر من حفنة منها في المستودع.
الجزء الرابع: ما وجدناه أثناء التنظيف
إذا كنت ستلمس كل موضع استدعاء للذكاء الاصطناعي على أي حال، فإنك تنظر إليها. وقد أظهر ذلك موضوعًا ثانيًا، لا علاقة له بالحادثة لكنه مكلف بالقدر نفسه.
يحاسب المزوّدون أقل بكثير على الموجّه (Prompt) الذي تبقى بدايته دون تغيير ويمكن تقديمه من ذاكرة تخزين مؤقت. والفرق بين الإصابة والإخفاق يبلغ نحو ثلاثين ضعفًا.
لا تحصل على هذا الخصم عبر خيار. اختبرنا ذلك تحديدًا: حقل في جسم الطلب مخصص لهذا الغرض لم يكن له أي أثر، فذاكرة التخزين المؤقت تعمل تلقائيًا في كل الأحوال. الرافعة الوحيدة هي الترتيب داخل الموجّه، من الثابت إلى المتغير.
أربعة مواضع فعلنا فيها العكس تمامًا:
قيمة متغيرة داخل كتلة التعليمات الثابتة. كان فحص التكرار لبلاغات الأخطاء يحتوي على اسم الوحدة في نص التعليمات. وهذا أعطى كتلة متطابقة في ما عدا ذلك سطرًا خاصًا بها في ذاكرة التخزين المؤقت لكل وحدة. مكان القيمة هو الجزء المتغير، حيث تتغير على أي حال.
الجديد قبل الثابت. الفحص نفسه كان يرسل بلاغ الخطأ الجديد قبل ما يصل إلى خمسين مرشحًا للمقارنة. وهذا جعل أكبر موجّه في الـ API إخفاقًا كاملًا دائمًا.
بيانات خاصة بكل مستخدم في الجزء الثابت. كانت دردشة الذكاء الاصطناعي العامة تضع الملاحظات عن المستخدم الفرد في كتلة التعليمات، أي قبل سجل القناة المشترك. وهذا أعطى كل مستخدم في القناة نفسها بدايته الخاصة، فكان السجل المشترك يُدفع ثمنه بشكل منفصل لكل مستخدم.
نافذة منزلقة على السجل. إرسال آخر N رسالة مع كل رسالة يزيح البداية مع كل رسالة. ويصبح السجل الكامل حينها إخفاقًا دائمًا. النهج الصحيح هو التقليص على شكل كتل، أي نادرًا وبشكل كبير.
يضاف إلى ذلك تفصيل يبدو تدقيقًا مبالغًا فيه وهو ليس كذلك: القائمة داخل الموجّه المرتّبة حسب معيار واحد فقط قد يتغير ترتيبها عند التساوي. سطر واحد يتبدّل في منتصف كتلة التعليمات يكلّف الإصابة لكل ما يأتي بعده. الترتيب داخل الموجّهات يحتاج إلى معيار حاسم لا لبس فيه لكسر التعادل.
ما الذي استخلصناه
تبديل النموذج ليس تغييرًا في الإعدادات. يبدو الاسم كقيمة في متغير. لكن خلفه كان سلوك مختلف، وهذا السلوك هو ما كسر الكود الخاص بنا، لا الواجهة.
العطل الخطير كان العطل الصامت. اختفاء النموذج القديم كان مرئيًا فورًا وأُصلح في دقائق. أما الردود الفارغة فعادت كاستجابات صالحة من الناحية الشكلية، وكان يمكن أن تبقى كذلك إلى أجل غير مسمى.
قابلية القياس مكانها موضع الاستدعاء. نسجّل الآن نسبة الإصابة في ذاكرة التخزين المؤقت عند كل موضع. الموضع المبني بشكل صحيح يستقر على نسبة عالية بعد الطلب الأول، والمبني بشكل سيئ يبقى عند الصفر. ترى ذلك في سطر سجل ولا مكان غيره، لأن كليهما يعمل.
والاستنتاج غير المريح: استخدام نموذج شخص آخر يعني أن جزءًا من منتجك يعتمد على قرار يُتخذ في مكان آخر. لهذا يمكن لأي سيرفر منذ أغسطس أن يوجّه ميزات الذكاء الاصطناعي إلى نقطة النهاية الخاصة به بدلًا من الاعتماد على نقطتنا.
مقالات أخرى
مراقبة 4000 سيرفر Discord: Grafana وPostHog وما أظهراه لنا
حلقة تسببت بصمت في نصف حركة البيانات لدينا، وثلاثة ملايين طلب عديم الفائدة يوميًا، وهجوم انتهى بعد دقيقة واحدة. ما الذي تراه مراقبتنا، وما الذي لا تراه عمدًا.
خلف الكواليسما الذي علّمنا إياه تشغيل بوت على أكثر من 2000 سيرفر Discord
أربعة أشياء تعمل على نطاق واسع بشكل مختلف عما تفترضه أثناء كتابة الكود.
خلف الكواليسالقانون داخل الكود الخاص بنا
زر إلغاء يجب أن يعمل دون تسجيل دخول. ونموذج يجب ألا يرفضك أبدًا. لماذا تُعد الالتزامات القانونية عندنا بنية تقنية، لا مجرد نصوص جاهزة.