لقد قمت ببناء عميل دردشة ذكاء اصطناعي بنظام البث (Streaming) دون أن أفقد صوابي
أردت بناء واجهة دردشة يستجيب فيها الذكاء الاصطناعي في الوقت الفعلي. أردت ذلك التأثير السلس لآلة الكتابة.
كان الأمر أصعب مما ظننت. لم تكن المشكلة في الذكاء الاصطناعي، بل كانت في خط نقل البيانات (pipeline) بين الـ API والمتصفح.
جربت ثلاث طرق مختلفة لحل هذه المشكلة.
طريقة الانتظار (The Wait Method) قمت باستدعاء الـ API وانتظرت الاستجابة الكاملة قبل عرضها. نجحت هذه الطريقة، لكن واجهة المستخدم (UI) تجمدت لعدة ثوانٍ. ظن المستخدمون أن التطبيق معطل، فقاموا بالنقر على "إرسال" مراراً وتكراراً. كانت تجربة مستخدم سيئة.
طريقة الاستطلاع (The Polling Method) فكرت في جعل الخادم يرسل معرف مهمة (job ID)، ثم يقوم العميل بطلب التحديثات كل ثانية. تطلب هذا إدارة ثقيلة للخادم، وظهرت التحديثات في أجزاء عشوائية، ولم تكن سلسة.
طريقة WebSocket جربت Socket.IO، مما أضاف تعقيداً هائلاً. كان عليّ إدارة عمليات إعادة الاتصال، و الـ heartbeats، ومزامنة الحالة (state synchronization). بالنسبة لتطبيق دردشة بسيط، كانت الـ WebSockets مبالغاً فيها.
كان الحل أبسط: Server-Sent Events (SSE).
معظم واجهات برمجة تطبيقات الذكاء الاصطناعي (AI APIs) ترسل الاستجابات بالفعل عبر SSE عبر HTTP. توقفت عن البحث عن أدوات معقدة واستخدمت الـ fetch API الأصلية.
باستخدام response.body.getReader()، قمت بقراءة تدفق البايتات (stream of bytes) مباشرة. قمت بتحليل بروتوكول SSE بنفسي. يحافظ هذا النهج على استجابة واجهة المستخدم ويستخدم بروتوكول HTTP القياسي.
لماذا ينجح هذا:
- لا حاجة لخادم WebSocket.
- لا يوجد منطق معقد لإعادة الاتصال.
- يعمل مع أي API يدعم SSE.
- يمكنك إيقاف البث بسهولة باستخدام AbortController.
هناك بعض المقايضات (trade-offs):
- لا يمكنك دفع التحديثات إلى العميل دون طلب (request).
- إذا انقطع الاتصال، ستفقد الاستجابة الجزئية.
إذا كنت تبني تطبيق دردشة، تجنب الـ WebSockets إلا إذا كنت بحاجة إلى اتصال ثنائي الاتجاه (bidirectional communication). التزم بالبث عبر HTTP؛ فهو أبسط وأكثر موثوقية.
ما هي استراتيجية البث الخاصة بك؟ هل تستخدم WebSockets أم SSE؟ أخبرني في التعليقات.
المصدر: https://dev.to/__c1b9e06dc90a7e0a676b/i-built-a-streaming-ai-chat-client-without-losing-my-mind-3gi0