أولاً الخلاصة: إنفاق روبوت خدمة العملاء المفرط، في ثمانين بالمئة من الحالات، لا يعود إلى ارتفاع سعر الوحدة للنموذج، بل إلى مشكلة في طريقة الاستدعاء. لدينا داخلياً روبوت أسئلة وأجوبة لخدمة ما بعد البيع بعدد مستخدمين نشطين يومياً بالآلاف، وقد قفزت فاتورته في الشهر الأول مباشرة إلى ثلاثة أضعاف الميزانية. بعد الفحص تبيّن أن سعر وحدة النموذج لم يتغير قيد أنملة، بل كانت كلها تكاليف خفية في بنية الاستدعاء. هذه المقالة توثّق عملية المراجعة، ولمن يهتم بتحسين تكاليف API النماذج الكبيرة، يمكنه مراجعة فاتورته وفقاً لها.
كيف تبدو الفاتورة غير الطبيعية
السمة المميزة للخلل ليست "ارتفاع الإجمالي"، بل "غرابة البنية". سحبنا تفاصيل الاستدعاءات اليومية، فوجدنا ثلاثة أمور غير طبيعية: في الأيام الأعلى من حيث حجم الاستدعاءات، كان متوسط عدد الـ token لكل طلب في تصاعد؛ نسبة المحاولات المُعادة اقتربت من خمسين بالمئة؛ السؤال نفسه من المستخدم، تارة بضع مئات من الـ token وتارة تتجاوز عشرة آلاف، بتباين هائل. اجتماع هذه الثلاثة معاً يكفي لتحديد أن المشكلة ليست في جانب النموذج، بل في سلسلة الاستدعاء الخاصة بنا.
أربع تكاليف خفية، واحدة أخفى من الأخرى
أولاً، النموذج الرائد يقوم بالأعمال الخشنة. في البداية، طلباً للبساطة، وجّهنا جميع الطلبات موحّدة إلى النموذج الرائد. لكن في سيناريو خدمة العملاء، أكثر من سبعين بالمئة منها هي مهام مثل "أين وصل طلبي" و"كيف أرجع البضاعة" من قبيل التعرّف على النية والردود النصية الثابتة، وهذه المهام يكفي فيها نموذج صغير تماماً، بفارق تكلفة يبلغ رتبة كاملة. تكليف النموذج الرائد بالإجابة عن "ما هي ساعات العمل" يشبه استخدام شاحنة لتوصيل طلب طعام.
ثانياً، تضخم السياق بلا ضابط. في المحادثات متعددة الجولات كنا نُعيد إدراج كامل الرسائل التاريخية، فحين يصل المستخدم إلى الجولة العاشرة، يشغل التاريخ وحده معظم الـ token. والأكثر إزعاجاً أن كثيراً من التاريخ لا علاقة له بالسؤال الحالي إطلاقاً، ويشارك لمجرد المشاركة. السياق ليس أطولَ فأذكى؛ بعد طول معيّن، التحسّن في الدقة محدود، لكن التكلفة ترتفع خطياً.
ثالثاً، عاصفة المحاولات المُعادة. أعددنا إعادة محاولة بسيطة عند الفشل، لكن دون تراجع أو قاطع دائرة. عند حدوث مهلة عابرة في المنبع، كانت الدفعة نفسها من الطلبات تُرسَل مراراً، تفشل مرة فتُعاد، وتفشل الإعادة فتُعاد مجدداً. هذه الاستدعاءات في الفاتورة كانت كلها هدراً صافياً، وما يراه المستخدم ظل خطأً.
رابعاً، ازدواج الفاتورة بين التدفقي وغير التدفقي. هذا هو الأكثر عرضة للتجاهل. بعض سلاسلنا كانت تستدعي غير التدفقي مرة للحصول على النتيجة الكاملة للمعالجة اللاحقة؛ والواجهة الأمامية تريد تأثير الآلة الكاتبة فتستدعي التدفقي مرة أخرى. السؤال نفسه، مبلغان. لاحقاً وحّدناها على الاستقبال التدفقي والتجميع المحلي، وعندها فقط اختفت هذه التكلفة المزدوجة.
كيف نُطبّق التوجيه الطَبَقي
الفكرة ليست معقدة: توزيع حسب صعوبة المهمة. التعرّف على النية، واستخراج الخانات، والردود النصية الثابتة، تمر عبر نموذج خفيف؛ أما المحادثات المعقدة التي تحتاج فعلاً إلى استدلال وخطوات حكم متعددة وتهدئة المشاعر، فتُسلَّم إلى النموذج الرائد. نضيف في الوسط طبقة بوابة نماذج للفصل، يدخل الطلب أولاً إلى المصنّف، فيُوسَم بعلامة المهمة ثم يُقرَّر توجيهه إلى أي نموذج.
نحن نستخدم منطق الاختيار التلقائي للأمثل حسب المهمة، وقد أجرينا جولة مقارنة على التوجيه متعدد النماذج في SiCore TokenWorks، وبعد تحويل المهام البسيطة إلى النموذج الخفيف، انخفضت التكلفة الإجمالية بوضوح، وأصبح الاستجابة أسرع. المفتاح هنا ليس "أي نموذج نستخدم"، بل أن جدول الربط "أي مهمة مع أي نموذج" يحتاج ضبطاً مستمراً. في البداية ضبطناه بالخبرة، وبعد أسبوعين أعدنا معايرته وفق معدلات الإصابة الفعلية، فكانت النتيجة أفضل بكثير من الضبط العشوائي. وميزة الوصول الموحد متعدد النماذج تتجلّى هنا أيضاً: تغيير استراتيجية التوجيه لا يتطلب تعديل كود الأعمال، يكفي ضبط في طبقة البوابة.
مقارنة الفاتورة قبل التحسين وبعده
لن نذكر أرقاماً محددة، بل نِسَباً. إجمالي حجم الاستدعاءات لم يتغير، لأن عدد المستخدمين لم يتغير. انخفضت التكلفة الإجمالية بنحو ستين بالمئة، حيث تراجعت نسبة استدعاءات النموذج الرائد من قرابة مئة بالمئة إلى نحو ثلاثين بالمئة، وتوزّع الباقي على النماذج الخفيفة. تقلّصت الاستدعاءات المرتبطة بالمحاولات المُعادة من قرابة خمسين بالمئة إلى نسبة أحادية الخانة. انخفض متوسط عدد الـ token لكل طلب بنحو أربعين بالمئة، أساسه تقليم السياق. أما ازدواج الفاتورة التدفقية فقد صار صفراً مباشرة. وبالحساب الكلي، عدنا من تجاوز الميزانية ثلاث مرات إلى داخل الميزانية مع فائض.
كيف نُعدّ المراقبة والتنبيهات
المال الموفَّر يجب أن يُصان بالمراقبة، لا بالانضباط الذاتي. أعددنا أربعة تنبيهات: يُفعَّل عند تجاوز عدد الـ token لكل طلب حداً معيناً، لمنع انفلات السياق؛ يُفعَّل عند تجاوز نسبة المحاولات المُعادة حداً محدداً، لمنع عاصفة المحاولات؛ يُفعَّل عند الارتفاع غير الطبيعي في نسبة استدعاءات النموذج الرائد، مما يشير إلى احتمال فشل التوجيه؛ يُفعَّل عند تجاوز نسبة ارتفاع التكلفة اليومية على أساس المقارنة الدورية حداً معيناً. هذه الأربعة لا تحتاج تعقيداً كبيراً، يكفي التجميع اليومي والتنبيه عند تجاوز الخط. في نموذج الفاتورة بالـ token، التكلفة تتراكم لحظياً، وانتظار نهاية الشهر لرؤية الفاتورة ثم التحسين يعني أن المال قد أُنفق بالفعل.
باختصار في جملة: الثقل الأكبر في تكلفة روبوت خدمة العملاء يكمن في بنية الاستدعاء، لا في سعر وحدة النموذج. إذا أحكمنا أربعة أمور: التوجيه الطَبَقي، وتقليم السياق، والتحكم في المحاولات المُعادة، وتوحيد التدفق، فستهبط الفاتورة تلقائياً. وزيادة على ذلك، إن كان في سيناريوك استرجاع RAG أيضاً، فإن عدد العناصر المسترجَعة من قاعدة المتجهات يستحق بدوره مراجعة وفق هذا المنطق.