دوز مباشرة للمحتوى الرئيسي
دروس فالذكاء الاصطناعي

نصّب واستعمل OpenJev للتصنيف بتوكن واحد مع SGLang

تعلّم كيفاش تنصّب openjev-sglang فـ Modal، تصيفط تقييمات Noul وChoice وScore، تراقب صحة الخدمة، تهيّأ الحدود والمصادقة، وتربط الـAPI بباك-إند SGLang موجود من قبل.

نصّب واستعمل OpenJev للتصنيف بتوكن واحد مع SGLang

شنو هو openjev-sglang؟

openjev-sglang هو سيرفر كيطبّق TypeSafe/Jev HTTP API باستعمال Qwen3.6-35B-A3B فوق SGLang. كيحوّل أسئلة التصنيف لقراءات فعّالة لاحتمال التوكن اللول، بلا ما يولّد أجوبة طويلة.

النشر الافتراضي كيشغّل كونتينر SGLang واحد فكل GPU من نوع NVIDIA B200. SGLang 0.5.19 كيوفّر الواجهة الأمامية ديالو المكتوبة بـ Rust، والتخزين المؤقت radix، وـ CUDA graphs ديال prefill القابلة للتوقيف. كاين حتى process مستقل بـ Python كيتكلف بالـ API العمومي باستعمال FastAPI وuvloop وtokenizer ديال Hugging Face مدعوم بـ Rust، واتصالات غير متزامنة مجمّعة مع SGLang فـ localhost.

ما كيتصيفط حتى طلب لـ TypeSafe. الـ endpoint العمومي كيعرض API ديال التقييم، بينما مسارات التوليد والإدارة ديال SGLang كيبقاو خاصّين فـ localhost.

المزايا الرئيسية

  • ثلاثة أنواع ديال التقييم: Noul لاحتمال نعم/لا، وChoice للاختيار من فئة، وScore للمستويات المرتبة.
  • استدلال بتوكن واحد: كل سؤال كيتقيّم انطلاقاً من log probabilities ديال لاصقات الأجوبة، بلا chain of thought مولّدة.
  • تخزين مؤقت للبادئة المشتركة: كيتسخّن جزء مشترك من الـ prompt قبل ما تتشغّل فروع الأسئلة بالتوازي.
  • حتى لـ 64 سؤال: أسئلة Choice وScore كيدعمو بين 2 و64 جواب افتراضياً.
  • حالة منظّمة: الحالة والتعليمات يقدرو يكونو سلاسل نصية، كائنات JSON، ولا arrays.
  • مسارات تشغيلية: كاينين health وliveness وكتالوج النماذج والحدود ومخطط OpenAPI وSwagger UI ومرجع تفاعلي Scalar.
  • نشر Modal: التطبيق المرفق كيدعم التوسّع التلقائي، والكاشات الدائمة للنموذج، والاسترجاع عند الانطلاق، والسلوك ديال scale-to-zero.
  • حماية قابلة للضبط: كاينة حدود الطلبات، وضوابط التوازي، والمهل الزمنية، والمصادقة الاختيارية بـ Bearer.

المتطلبات المسبقة

ثبّت uv وخذ حساب Modal إلا كنت ناوي تستعمل النشر السحابي المرفق. أول build كيحمّل صورة SGLang كبيرة، وأول تشغيل بـ GPU كيهبّط أوزان النموذج وكيcompile ولا كيلتقط kernels.

تبعية CUDA كتبقى فكونتينر SGLang. تشغيل uv sync فالحاسوب ديالك كيثبّت غير الـ API وأدوات النشر والاختبارات.

ثبّت المشروع

دير clone للمستودع، دخل للدليل ديالو، وسينكرونايز بيئة Python:

uv sync

إلا ما كانش Modal متوثّق فالجهاز الحالي، كمّل الإعداد ديالو:

uv run modal setup

شغّل نشر مؤقت فـ Modal

باش تدير اختبار من البداية للنهاية، شغّل سيرفر مؤقت، دوز اختبارات الاستدلال المرفقة، ومن بعد طفي السيرفر:

uv run modal run modal_app.py

هاد الأمر كيحفظ تقرير اختبار الدخان فـ smoke-result.json. التقرير فيه مدة الانتظار عند الانطلاق، ومدة الاستدلال، والمعلومات المتوفرة على استعمال الكاش.

نشر endpoint مستقر

نشر التطبيق كخدمة Modal دائمة:

uv run modal deploy modal_app.py

النشر كيطبّع URL بحال https://YOUR-SERVER.us-west.modal.direct. خزّنو فمتغير بيئة باش تسهّل الولوج ليه:

export OPENJEV_URL="https://YOUR-SERVER.us-west.modal.direct"

الـ endpoint الافتراضي ديال Modal ما فيهش المصادقة عن قصد. كيستعمل منطقة التوجيه US West، ويقدر يبرمج الحوسبة فمناطق US المكوّنة. ما كاين حتى حد صريح للكونتينرات، والـ instances كتنقص للصفر من بعد خمس دقايق ديال الخمول.

السيرفر اللي نقص للصفر كيرجّع HTTP 503 وهو كيبدا. أمر smoke المرفق كيعيد محاولات هاد الردود ديال الانطلاق أوتوماتيكياً.

شغّل اختبار smoke ضد الـ URL المنشور:

uv run openjev smoke "$OPENJEV_URL"

اختبار smoke كيجرب أنواع الأجوبة الثلاثة، وكيتحقق من سؤال فيه 64 جواب، وكيدير فحوصات دلالية أساسية، وكيتأكد باللي 65 جواب مرفوضين.

صيفط أول تقييم ديالك

المسار الرئيسي هو POST /v1/systemone. الطلب التالي كيصنّف رسالة ديال زبون باستعمال أسئلة Noul وChoice وScore:

curl "$OPENJEV_URL/v1/systemone" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "jev-latest",
    "state": [
      {"role": "system", "content": "You are a support assistant."},
      {"role": "user", "content": "I was charged twice. Please refund the duplicate."}
    ],
    "questions": {
      "refund": {
        "type": "noul",
        "instructions": "Does the user request a refund?"
      },
      "department": {
        "type": "choice",
        "instructions": "Which department should handle this?",
        "criteria": {
          "billing": "Payments and refunds",
          "technical": "Software bugs"
        }
      },
      "urgency": {
        "type": "score",
        "instructions": "How urgent is the request?",
        "criteria": ["Routine", "Urgent", "Emergency"]
      }
    }
  }'

تقدر حتى تخلي JSON فملف وتصيفطو بلا quoting ديال shell:

curl "$OPENJEV_URL/v1/systemone" \
  -H 'Content-Type: application/json' \
  --data-binary @examples/request.json

فهم أنواع الأسئلة

  • Noul: كيرجّع الاحتمال المطبّع ديال yes.
  • Choice: كيرجّع الاختيار اللي عندو أعلى احتمال والتوزيع الكامل ديال الاحتمالات. سميات الاختيارات الأصلية كتبقى محفوظة فالرد.
  • Score: كيرجّع المستوى المتوقع ابتداءً من الصفر، محسوب من كل index ديال مستوى والاحتمال ديالو، ومعاه legend.

كيتم تقديم اختيارات الجواب للنموذج على شكل تسميات بالحروف متبوعة بالوصف ديالها. مفاتيح الأجوبة كتكون مخفية عادةً على النموذج. إلا كان وصف شي اختيار هو null، فالمفتاح ديالو هو اللي كيعطي المعنى بدالو.

تزويد الحالة والتعليمات

كل من state وinstructions كيقبلو نصوص، كائنات JSON، ولا لوائح. لائحة ديال رسائل المحادثة، ولا كائن فيه بالضبط {"messages": [...]}، كتترندر باستعمال قالب المحادثة الأصلي ديال النموذج.

الأدوار والكائنات الأصلية ديال الرسائل كيتحافظ عليهم، وكل سؤال تصنيف كيتزاد كدور جديد ديال المستخدم. القيم المهيكلة الأخرى كتتحول كما هي لرسالة ديال المستخدم. حتى الكائن اللي فيه messages وزيادات أخرى كيبقى محفوظ باش الميتاداتا ما تضيعش بلا تنبيه.

حالة المحادثة كتدعم غير المحتوى النصي. محتوى الصور والصوت والفيديو ما مدعومش.

استكشاف نقاط نهاية الخدمة

  • POST /v1/systemone كيدير تقييم Noul وChoice وScore.
  • GET /v1/models كيرجع كتالوغ ديال النماذج فيه حقول بنمط TypeSafe وOpenAI.
  • GET /v1/limits كيعرض حدود قبول الطلبات.
  • GET /health كيعرض الجاهزية، صحة SGLang، ومدة الإقلاع.
  • GET /health/live كيتحقق واش عملية API ما زالت خدامة.
  • GET / كيفتح مرجع Scalar للـ API فيه مثال قابل للتعديل ديال الطلب.
  • GET /docs كيفتح واجهة Swagger UI المدمجة.
  • GET /openapi.json كيرجع مخطط OpenAPI المولّد.

اسم النموذج ديال الطلب jev-latest هو اسم مستعار للتوافق. المعرّف العمومي الافتراضي للنموذج هو Qwen/Qwen3.6-35B-A3B، بينما مستودع NVIDIA كيتستعمل داخلياً كمصدر للأوزان.

كيفاش كيخدم الاستدلال

  1. الـ API كيتحقق من المخطط، وعدد الأجوبة، وحجم الجسم، وطول السياق، والميزانية الإجمالية للتوكنات.
  2. كيترندر قالب المحادثة الأصلي مرة وحدة مع تعطيل التفكير، ومن بعد كيفصل البادئة المشتركة على لواحق الأسئلة اللي تترمّز كل وحدة بوحدها.
  3. كيصيفط البادئة المشتركة لـ SGLang باستعمال max_new_tokens=1. التوكن اللي كيتولّد كيتحيد، وكتبقى البادئة متاحة لإعادة الاستعمال الانتهازية ديال radix-cache.
  4. كيصيفط بالتوازي فرع واحد لكل سؤال. كل فرع فيه البادئة، ولاحقة السؤال، ورأس المساعد، والعلامة Answer:.
  5. كيطلب احتمالات اللوغ غير لتسميات الأجوبة الصحيحة، وكيعاود يطبّعها باستعمال softmax مستقر.

بالنسبة لـ N أسئلة، الخادم كيدير N + 1 استدعاء كل واحد فيه توكن واحد: استدعاء واحد لتسخين الكاش واستدعاء واحد لكل سؤال. التوكن المولّد كيتجاهل، وبالتالي ما كاين لا استمرار ذاتي الانحدار لا سلسلة أفكار مولّدة. الاستدلال التخميني ما مفعّلاش.

التسميات كتبدا من A حتى Z، ومن بعد كتستعمل تركيبات مؤكدة من توكن واحد بحال AA وAB. جميع التسميات الـ64 كيتفحصو باستعمال الـ tokenizer النشيط وقت الإقلاع. هاد الشي كيتفادى استعمال تسميات رقمية متعددة التوكنات بحال 10 ولا 64.

فهم الاستعمال ومقاييس الكاش

رأس الاستجابة x-openjev-prefix-tokens كيعطي حجم البادئة المشتركة المطلوبة. ملي SGLang كيوفر أعداد الكاش، x-openjev-cached-tokens كيتضمن مجموع إصابات كاش الفروع.

الواجهة الأمامية Rust ديال SGLang 0.5.19 ما كتعرّضش هاد الأعداد ديال الكاش. فهاد الإعداد، الرأس ما كيبانش وتقرير الاختبار السريع كيسجل null، ماشي صفر. سجلات المجدول تقدر مع ذلك تبيّن إصابات الكاش الفعلية. رأس Server-Timing كيفصل بين تحضير الطلب، والتهيئة المسبقة المشتركة، والاستدلال ديال الفروع.

usage.input_tokens هو مجموع أعداد توكنات الطلب الكامل المبلّغ عليها عبر استدعاءات التسخين والفروع، بما فيها التوكنات المخزنة فالكاش. usage.output_tokens هو N + 1. هاد الأرقام كتوصف النشاط ديال الواجهة الخلفية، ماشي التوكنات الفريدة اللي تحسبات ولا تقديرات الفوترة ديال TypeSafe.

إعداد الحدود والمصادقة

حدود القبول الافتراضية كتشمل 64 سؤال، ومن 2 حتى 64 جواب لكل سؤال ديال Choice ولا Score، جسم JSON بحجم 2 MiB، و32,768 توكن لكل فرع بما فيها المخرجات، و262,144 توكن إجمالي مُرسل فالإدخال، و16 تقييم متزامن، و64 استدعاء متزامن للواجهة الخلفية.

الطلبات غير الصحيحة كترجع HTTP 422 قبل الاستدلال. الأجسام اللي كتفوت حد الحجم كترجع 413، والضغط الزائد كيرجع 529 مع Retry-After، والمهلات ديال الواجهة الخلفية كترجع 504. التقييمات اللي فشلات ولا تلغات كتلغي الفروع الشقيقة وكتحاول توقفها فـ SGLang.

الإعدادات متاحة عبر متغيرات البيئة OPENJEV_*. من بين الإعدادات الشائعة:

  • OPENJEV_MODEL: القيمة الافتراضية هي nvidia/Qwen3.6-35B-A3B-NVFP4.
  • OPENJEV_SERVED_MODEL_NAME: كيبدل المعرّف العمومي للنموذج وكيتمرير لـ SGLang.
  • OPENJEV_REVISION: كيختار نسخة نقطة التحقق المثبتة.
  • OPENJEV_FRONTEND: القيمة الافتراضية هي rust؛ وpython هو البديل الاحتياطي الصريح.
  • OPENJEV_MAX_INPUT_TOKENS: القيمة الافتراضية هي 32768.
  • OPENJEV_MAX_TOTAL_INPUT_TOKENS: القيمة الافتراضية هي 262144.
  • OPENJEV_MAX_CONCURRENT_REQUESTS: القيمة الافتراضية هي 16.
  • OPENJEV_MAX_CONCURRENT_BRANCHES: القيمة الافتراضية هي 64.
  • OPENJEV_REQUEST_TIMEOUT: القيمة الافتراضية هي 120 ثانية.
  • OPENJEV_TEMPERATURE: القيمة الافتراضية هي 1.0 وكتأثر على تطبيع التسميات.
  • OPENJEV_API_KEY: كيفعّل اختيارياً مصادقة Bearer للـ API العمومي.
  • OPENJEV_BACKEND_API_KEY: كيضبط اختيارياً مفتاح Bearer مستقل لـ SGLang.

مشغّل Modal كيدوز أوتوماتيكياً OPENJEV_PROFILE وOPENJEV_FRONTEND وOPENJEV_SERVED_MODEL_NAME من البيئة المحلية. زيد الإعدادات البعيدة الأخرى فـimage.env(...)، ولا استعمل Modal Secret بيانات الدخول.

التشغيل محلياً باستعمال SGLang backend موجود

باش تستعمل backend خدام من قبل، وجّه الـAPI للرابط المحلي ديالو:

uv run openjev serve --connect http://127.0.0.1:30000

خاص الـbackend يستعمل revision متطابق ديال الموديل والـtokenizer. وخصّو حتى يدعم احتمالات log ديال التوكنات المختارة، وradix caching، وطول سياق كافي.

فـhost ولا container ديال B200 اللي فيه SGLang 0.5.19 منصّب فبيئة Python مستقلة، حدّد الـinterpreter ديالو بشكل صريح:

uv run openjev serve --sglang-python /path/to/sglang/bin/python

التطوير والتحقق

استعمل الأوامر المرفقة باش تشغّل الاختبارات بلا اتصال، وفحوصات تكامل الـtokenizer، وlinting، وتوليد الـschema:

uv run pytest
uv run pytest -m integration
uv run ruff check .
uv run openjev schema

الاختبارات العادية كاتغطي سلوك الوحدات والـAPI بلا اتصال. اختبارات التكامل كتستعمل tokenizer حقيقي وتنزيل صغير من Hugging Face، ولكن ما كتحتاجش GPU. توليد الـschema حتى هو ما كيحتاج لا GPU لا تنزيل موديل.

نصائح متقدمة للنشر

خلي container ديال GPU سخون

Modal كينقص الخدمة للصفر من بعد خمس دقايق ديال الخمول. عيّن min_containers=1 فـmodal_app.py ملي تكون أولوية خفض وقت الانطلاق بشكل مستمر أهم من تفادي استعمال GPU ففترة الخمول.

توقّع التهيئة فالبداية الأولى

أول تشغيل ديال GPU كينزّل الأوزان وكيcompile ولا كيدير capture للـkernels. أوزان الموديل، وبيانات ضبط SGLang، وبيانات compilation ديال Triton كيبقاو فـModal Volume المسمّى openjev-huggingface. التشغيلات اللاحقة كتعيد استعمال هاد الملفات، مع أن capture ديال CUDA graph كيبقى كيتدار عند الانطلاق.

اعتبر إعادة استعمال الكاش فرصة ماشي ضمان

إعادة الاستعمال ديال Radix ماشي KV session مثبتة لكل request. الحالة المتكررة فموديل Qwen الهجين، وحدود صفحات الكاش، والضغط على الكاش، والطلبات المتزامنة يقدرو ينقصو من نسبة الإصابة. الـbackend كيستعمل --mamba-radix-cache-strategy extra_buffer.

فسّر الثقة بحذر

OpenJev كيعرّف الثقة بهاد الصيغة: 1 - H(probabilities) / log(number_of_options)، وكيحصرها بين صفر وواحد. الاحتمالات المتساوية كتعطي ثقة صفر، بينما point mass كتعطي واحد.

هاد الاحتمالات مشروطة بالخيارات المعطاة، وقد تعتمد على صياغة الـprompt وترتيب labels. ماشي تقديرات معايرة للصحة.

خطّط لفشل الـbackend

إلى خرج SGLang بشكل مفاجئ، الـAPI حتى هو كيخرج. من بعد، مشغّل Modal كينهي الـcontainer باش Modal يقدر يعوّضو، عوض ما يخلي process HTTP عمومي مربوط بـinference backend ميت. الإيقاف العادي كيعطّل بجوج الـwatchers بنظافة.

الخلاصة

openjev-sglang كيوفّر طريقة مركّزة لتشغيل classification متوافق مع Jev على Qwen3.6، مع قراءة فعّالة لاحتمال توكن واحد. إعداد Modal ديالو كيوفّر نشر قابل للتوسّع على B200، بينما الأوامر المحلية كتدعم الاختبار والاتصال بخدمة SGLang موجودة. بدي باختبار smoke، وتحقّق من الحدود وإعدادات المصادقة ديالك، وراقب التوقيت وheaders ديال الكاش ملي كيكبر الترافيك.