تحليل على Habr: لماذا لا يوقف r.Context() نموذج LLM وكيف تُبنى مهام الذكاء الاصطناعي في Go
نشر موقع Habr تحليلاً لفخ شائع في خوادم Go الخلفية التي تتعامل مع LLM. النمط المعتاد يلغي العمل مع إلغاء طلب HTTP عبر r.Context(). لكن إذا أغلق المستخدم التبويب في منتصف تحليل مستند، فقد يواصل المزوّد التوليد ويحتسب رسوم الرموز (tokens). يقترح الكاتب نقل عمليات AI الطويلة إلى مهام خلفية على PostgreSQL، مع معالجة مستقلة للمعالجة المتماثلة (idempotency) وإعادة المحاولة (retry) والحماية من الخصم المتكرر. • سياق الطلب لا يساوي دورة حياة مهمة AI. • الأفضل حفظ حالة المهمة في PostgreSQL لا في ذاكرة العملية. • إعادة المحاولة دون معالجة متماثلة تعني الدفع مرتين مقابل API.
معالج بواسطة الذكاء الاصطناعي من Habr AI؛ بتحرير Hamidun News
إغلاق تبويب المتصفح يلغي طلب HTTP، لكنه لا يوقف بالضرورة النموذج على جانب المزوّد. يوضح كاتب تحليل حديث على Habr كيف يتحول هذا الفارق إلى نفقات وأخطاء في خادم Go خلفي عادي. إذا شغّل المستخدم تحليل مستند ثم غادر، فقد تبقى الخدمة دون نتيجة، ومع ذلك تصل فاتورة الرموز (tokens). ولعمليات AI الطويلة يقترح الكاتب مهاماً خلفية على PostgreSQL، ومعالجة متماثلة (idempotency) صارمة، وسياسة مدروسة لإعادة المحاولة.
أين ينكسر النموذج المعتاد
اعتاد مطورو Go على قاعدة بسيطة: يبقى العمل قائماً ما دام `r.Context()` حياً. إذا قطع العميل الاتصال أُلغي السياق، وانتهت الـ goroutines، وتحررت الموارد. وهذا مريح وصحيح عند الاستعلام من قاعدة بيانات أو من خدمة مصغّرة داخلية.
مع LLM يختلف الأمر. فقد يستغرق الاستدعاء عشرات الثواني أو دقائق، خصوصاً عند تحليل مستندات كبيرة أو سلاسل تضم عدة استدعاءات للنموذج. وتُحتسب التكلفة على الرموز المعالجة والمولَّدة، والإلغاء من جانبك لا يضمن أن يوقف المزوّد العمل فوراً. ويعتمد ذلك على واجهة API المحددة وعلى طريقة إغلاق الاتصال.
تظهر مشكلتان في آن واحد:
- أُلغي العمل ولا توجد نتيجة، لكن المال أُنفق؛
- يعود المستخدم ويضغط الزر مرة أخرى، فتبدأ العملية المدفوعة من جديد.
المهمة الخلفية ككيان مستقل
الفكرة الأساسية في التحليل أن عملية AI يجب ألا تتبع طلب HTTP. يستقبل المعالج المدخلات وينشئ مهمة ويردّ فوراً بمعرّف. بعد ذلك تعيش المهمة حياتها الخاصة، ويعرف العميل بشأنها عبر الاستطلاع (polling) أو SSE أو WebSocket.
يختار الكاتب PostgreSQL مخزناً. وهو خيار معقول لكثير من الفرق: فقاعدة البيانات موجودة أصلاً في البنية التقنية، والمعاملات مفهومة، ولا حاجة إلى وسيط رسائل منفصل. وتبدو المجموعة المعتادة لمثل هذا الطابور كما يلي:
- جدول مهام بحالات (أُنشئت، قيد التنفيذ، اكتملت، خطأ، أُلغيت)؛
- التقاط العمال (workers) للمهام عبر `FOR UPDATE SKIP LOCKED` حتى لا يأخذ عاملان المهمة نفسها؛
- وقت آخر heartbeat الذي تُعاد بموجبه المهام العالقة إلى الطابور؛
- عدّاد المحاولات ووقت المحاولة التالية؛
- النتيجة المحفوظة وبيانات الرموز المستخدمة.
المكسب الرئيسي أن الحالة تصمد أمام إعادة تشغيل الخدمة. فعند النشر أو سقوط الـ pod لا تختفي المهمة مع الـ goroutine، بل يلتقطها عامل آخر.
المعالجة المتماثلة والمال
أغلى نقطة في هذا النظام تقع عند تقاطع إعادة المحاولة (retry) والفوترة. فتكرار طلب إلى LLM يكلف مالاً، ولذلك لا ينبغي تنفيذه بشكل أعمى كما يُكرَّر الوصول إلى الذاكرة المؤقتة.
المبادئ العملية التي تنبع من منطق التحليل:
- يُنشأ مفتاح المعالجة المتماثلة على مستوى إجراء المستخدم، ويحمي من الضغط المزدوج على الزر؛
- لكل مهمة معرّف فريد تُسجَّل النتيجة بموجبه مرة واحدة فقط؛
- لا تُسمح إعادة المحاولة إلا للأخطاء التي يكون التكرار فيها مجدياً (انتهاء المهلة، 429، 5xx)، وليس للمدخلات غير الصالحة؛
- الخصم من رصيد المستخدم مرتبط بالمهمة، لا بكل محاولة على حدة؛
- يصبح إلغاء المستخدم حالة صريحة، لا أثراً جانبياً لانقطاع الاتصال.
من أين تبدأ
إذا كان استدعاء LLM في خدمتك يُنفَّذ مباشرة داخل المعالج، فتحقق من ثلاثة أمور. الأول: ماذا سيحدث للتوليد المدفوع إذا انقطع العميل في المنتصف. الثاني: هل يمكن لطلب مكرر أن ينشئ نسخة مكررة من العملية المدفوعة. الثالث: هل ستصمد المهمة أمام إعادة تشغيل العملية.
إذا كان الجواب عن سؤال واحد على الأقل غير مريح، فأنت بحاجة إلى نموذج مهمة مستقل. الحد الأدنى هو جدول بالحالات وعامل واحد، ويمكن إضافة `SKIP LOCKED` وheartbeat وسياسة الإعادة مع نمو الحِمل. ويكون إدخال وسيط رسائل منفصل منطقياً حين يعجز PostgreSQL عن مجاراة الطابور. وإلى ذلك الحين لا يفعل الوسيط في الغالب سوى تعقيد النظام.
هذه المادة ليست عن نموذج جديد أو إصدار جديد، بل عن الانضباط الهندسي حول LLM. وهنا بالذات يضيع الآن جزء ملحوظ من ميزانيات منتجات AI: فالأخطاء تنشأ في الطبقة المحيطة بالنموذج، لا في الـ prompts.
أسئلة وأجوبة حول الخبر
ما أبرز التفاصيل حول أين ينكسر النموذج المعتاد؟
اعتاد مطورو Go على قاعدة بسيطة: يبقى العمل قائماً ما دام `r.Context()` حياً. إذا قطع العميل الاتصال أُلغي السياق، وانتهت الـ goroutines، وتحررت الموارد. وهذا مريح وصحيح عند الاستعلام من قاعدة بيانات أو من خدمة مصغّرة داخلية. مع LLM يختلف الأمر. فقد يستغرق الاستدعاء عشرات الثواني أو دقائق، خصوصاً عند تحليل مستندات كبيرة أو سلاسل تضم عدة استدعاءات للنموذج. وتُحتسب التكلفة على الرموز المعالجة والمولَّدة، والإلغاء من جانبك لا يضمن أن يوقف المزوّد العمل فوراً. ويعتمد ذلك على واجهة API المحددة وعلى طريقة إغلاق الاتصال. تظهر مشكلتان في آن واحد: أُلغي العمل ولا توجد نتيجة، لكن الما
ما أبرز التفاصيل حول المهمة الخلفية ككيان مستقل؟
الفكرة الأساسية في التحليل أن عملية AI يجب ألا تتبع طلب HTTP. يستقبل المعالج المدخلات وينشئ مهمة ويردّ فوراً بمعرّف. بعد ذلك تعيش المهمة حياتها الخاصة، ويعرف العميل بشأنها عبر الاستطلاع (polling) أو SSE أو WebSocket. يختار الكاتب PostgreSQL مخزناً. وهو خيار معقول لكثير من الفرق: فقاعدة البيانات موجودة أصلاً في البنية التقنية، والمعاملات مفهومة، ولا حاجة إلى وسيط رسائل منفصل. وتبدو المجموعة المعتادة لمثل هذا الطابور كما يلي: جدول مهام بحالات (أُنشئت، قيد التنفيذ، اكتملت، خطأ، أُلغيت)؛ التقاط العمال (workers) للمهام عبر `FOR UPDATE SKIP LOCKED` حتى لا يأخذ عاملان المهمة نفسها
ما أبرز التفاصيل حول المعالجة المتماثلة والمال؟
أغلى نقطة في هذا النظام تقع عند تقاطع إعادة المحاولة (retry) والفوترة. فتكرار طلب إلى LLM يكلف مالاً، ولذلك لا ينبغي تنفيذه بشكل أعمى كما يُكرَّر الوصول إلى الذاكرة المؤقتة. المبادئ العملية التي تنبع من منطق التحليل: يُنشأ مفتاح المعالجة المتماثلة على مستوى إجراء المستخدم، ويحمي من الضغط المزدوج على الزر؛ لكل مهمة معرّف فريد تُسجَّل النتيجة بموجبه مرة واحدة فقط؛ لا تُسمح إعادة المحاولة إلا للأخطاء التي يكون التكرار فيها مجدياً (انتهاء المهلة، 429، 5xx)، وليس للمدخلات غير الصالحة؛ الخصم من رصيد المستخدم مرتبط بالمهمة، لا بكل محاولة على حدة؛ يصبح إلغاء المستخدم حالة صريحة، لا
Access Frontier LLMs & Multimodal AI in One Workspace
Discover NomadNet AI (nomadnet.ai) — unified access to frontier language models, research synthesis, and multimodal workflows.
أهم ما في عالم الذكاء الاصطناعي — مرة كل أسبوع
سبع قصص مهمة فعلاً هذا الأسبوع، مختارة بعناية. بلا ضجيج ولا بيانات صحفية.
تم! تحقق من بريدك للتأكيد.