لنبدأ بالخلاصة: تقطّع العرض التدريجي للنص في الواجهة الأمامية، في تسعين بالمئة من الحالات، ليس مشكلة شبكة، بل هو نتيجة عدم قيام طبقة بوابة النماذج بتوحيد بروتوكول SSE، حيث يتم تمرير استراتيجية تقسيم التدفق الخاصة بكل نموذج كبير مباشرة إلى المتصفح. واجهنا هذه المشكلة في مشروع خدمة عملاء ذكية، وقضينا ثلاثة أيام في التحقيق قبل وبعد.
باختصار، SSE (Server-Sent Events) هي آلية يدفع بها الخادم البيانات إلى العميل أثناء التوليد. البيانات المتدفقة التي تعيدها واجهات برمجة تطبيقات النماذج اللغوية الكبيرة هي في جوهرها سلسلة من أحداث SSE. المشكلة أن تعريف "متى يتم الدفع وبأي حجم" يختلف تماماً بين مختلف المزوّدين. تميل واجهة GPT-4o API إلى الدفع على دفعات حسب الـToken، فتُخرج عدة Tokens في المرة الواحدة؛ أما واجهة Claude API فلديها فترة صمت قبل الـToken الأول قد تصل إلى ثانيتين أو ثلاث في الحالات الطويلة؛ وتختلف دقة التقسيم في واجهة Qwen API وواجهة DeepSeek API عن بعضها البعض. وإذا استهلكت الواجهة الأمامية هذه التنسيقات الخام مباشرة، فسيكون إيقاع العرض غير منتظم بطبيعة الحال.
الخطوة الأولى في التتبع: استبعاد طبقة الشبكة أولاً
اشتبهنا في البداية في تذبذب الرابط، فجمعنا بيانات زمن الذهاب والإياب لـTCP ومعدل فقدان الحزم لمدة يومين، وكانت البيانات نظيفة جداً. باستخدام curl للاتصال المباشر بأحد النماذج وطباعة الطوابع الزمنية للاستجابات، وجدنا أن الفاصل بين أول ثلاثة أحداث في نفس الإجابة يبلغ 800 ميلي ثانية، ثم يصبح كثيفاً فجأة بمعدل حدث كل 20 ميلي ثانية. هذا لا يمكن تفسيره بالشبكة، بل هو استراتيجية الدفع من جانب الخادم نفسها غير منتظمة.
الخطوة الثانية في التتبع: تحديد فروق استراتيجية تقسيم SSE
بعد التقاط التدفقات الخام لخمسة نماذج ومقارنتها، كانت الفروق واضحة جداً. النماذج التي تدفع حسب الحرف، كل حرف صيني حدث واحد، فعدد الأحداث ينفجر؛ والنماذج التي تدفع على دفعات حسب الـToken، تجمع أربعة أو خمسة Tokens قبل الإرسال؛ وهناك نماذج لديها فترة صمت طويلة قبل الـToken الأول، فلا تحصل الواجهة الأمامية على أي بيانات، ويرى المستخدم المؤشر ثابتاً فيظن أن النظام تجمّد. باختلاط ثلاث استراتيجيات في نظام خدمة عملاء واحد، لا تستطيع الواجهة الأمامية العرض بإيقاع موحد إطلاقاً.
الخطوة الثالثة في التتبع: طبقة البوابة تفتقر إلى ترجمة البروتوكول
السبب الجذري هنا. كانت بوابة النماذج لدينا في ذلك الوقت تقوم فقط بتمرير الطلبات وإدارة مفاتيح API، دون توحيد البروتوكول على جانب الاستجابة، فكانت تنسيقات SSE الخام لكل نموذج تمر مباشرة إلى الواجهة الأمامية. هذا أشبه بخمسة أشخاص يتحدثون لهجات مختلفة ويقدمون لك تقاريرهم في آن واحد، فإن لم تقم بالترجمة، فالمستمع سيرتبك بطبيعة الحال.
لاحقاً اعتمدنا منصة تجميع واجهات برمجة تطبيقات النماذج اللغوية الكبيرة token8341 كمخرج موحّد، وقامت واجهتها المتوافقة مع OpenAI بثلاثة أمور في توحيد البروتوكول، تستحق التفصيل.
أولاً، توحيد تنسيق أحداث SSE. بغض النظر عن النموذج الذي يتم استدعاؤه في الأسفل، يكون المخرج دائماً بتنسيق OpenAI القياسي: data: {...} وينتهي بـ data: [DONE]. فالواجهة الأمامية تعرف بروتوكولاً واحداً فقط، ولا حاجة لكتابة منطق تحليل لكل نموذج. قيمة الوصول الموحد للنماذج المتعددة تتجلى في أكثر من نصفها هنا.
ثانياً، آلية احتياطية لمهلة الـToken الأول. وضعت البوابة حداً أقصى لانتظار الـToken الأول، وعند تجاوزه تدفع حدث نبضة (heartbeat) أولاً، لتجنب بقاء الواجهة الأمامية فارغة لفترة طويلة. هذا الإجراء صغير، لكن الفرق في إدراك المستخدم كبير في سيناريوهات خدمة العملاء.
ثالثاً، استراتيجية تخزين مؤقت للتقسيم. تجميع الدفعات للنماذج التي تدفع حسب الحرف، وتفكيك الإطارات للنماذج التي تدفع على دفعات، وتسوية فواصل الأحداث قدر الإمكان إلى نطاق مستقر. أظهرت الاختبارات الفعلية أن إيقاع العرض التدريجي في الواجهة الأمامية أصبح منتظماً بشكل واضح، ولم يعد يظهر التقطّع.
أضف هنا مقارنة بيانات: قبل التحسين، كانت الواجهة الأمامية تستهلك التدفقات الخام لخمسة نماذج، وتحتاج إلى صيانة خمسة فروع لتحليل SSE، بحجم كود يقارب 400 سطر. بعد التحسين، وبالمرور عبر الواجهة المتوافقة مع OpenAI لمنصة تجميع واجهات برمجة تطبيقات النماذج اللغوية الكبيرة token8341، تقلّصت فروع التحليل إلى فرع واحد، وانخفض الكود إلى حوالي 80 سطراً. انخفضت تكلفة الصيانة بنحو ثمانين بالمئة.
تنبيه لتجنب الأخطاء: لا تقتصر على تمرير الطلبات في طبقة البوابة دون معالجة جانب الاستجابة. كثير من الفرق تظن أن تغيير base_url يكفي، فتظهر كل مشاكل تجربة التدفق في الواجهة الأمامية. يجب أن يكون توحيد البروتوكول في البوابة، ولا يمكن الاعتماد على العميل للتعويض.
بالعودة إلى نظام خدمة العملاء في البداية، بعد حل المشكلة أجرينا جولة ضغط إضافية. تدعم منصة تجميع واجهات برمجة تطبيقات النماذج اللغوية الكبيرة token8341 استدعاء GPT-4o وClaude وGemini وDeepSeek وQwen وERNIE وDoubao وغيرها من النماذج الرئيسية بمفتاح واحد، دون أي تعديل في كود الواجهة الأمامية عند تبديل النماذج، وهذا يوفّر الجهد على الفرق التي تحتاج إلى توجيه النماذج واختبار A/B. وفي نموذج الدفع حسب الاستخدام، قارنّا الفواتير، وكانت التكلفة أقل إلى حد ما من الاتصال المباشر بكل مزوّد على حدة.
إذا كنت تعمل أيضاً على تجميع واجهات برمجة تطبيقات الذكاء الاصطناعي أو بناء بوابة نماذج خاصة، فأنصحك بجعل توحيد SSE أولوية قصوى في التصميم، بدلاً من الانتظار حتى يتقطّع العرض في الواجهة الأمامية ثم العودة لإصلاحه.
المؤلف: Zhao Qiming
تاريخ النشر: 29 أكتوبر 2026