المعمارية
طبقة تقديم النماذج اللغوية المحلية: vLLM وSGLang وllama.cpp وOllama
بعد اختيار النموذج، يكون أول قرار معماري هو أي طبقة تقديم ستشغّله. تفصل هذه الملاحظة بين أربع طبقات، لا بقوائم الميزات بل بمقاربتها المعمارية للجدولة والذاكرة وإعادة الاستخدام والتغليف.
حين تختار مؤسسة النموذج الذي تنوي تشغيله، يكون ما بين يديها ملفاً: أوزان، ومفردات، وصيغة التوجيه التي يتوقعها النموذج. وتحويل ذلك الملف إلى خدمة قطعة برمجية منفصلة. فهي تصفّ الطلبات الواردة، وتوزّع ذاكرة وحدة المعالجة الرسومية، وتقرر كم مستخدماً يستطيع إجراء محادثة في وقت واحد، وتعرض واجهة برمجية.
وتفصل هذه الملاحظة بين أربعة أسماء — vLLM وSGLang وllama.cpp وOllama — لا بجدول ميزات، بل بمقاربتها المعمارية على أربعة محاور: الجدولة، والذاكرة، وإعادة الاستخدام، والتغليف. وهي لا ترتّبها بحسب السرعة، وكل رقم أدناه مقتبس مع تاريخه ومرجع المقارنة الخاص بمصدره. أما الحسابات على جانب ملف النموذج — مستويات التكميم، وحساب ذاكرة VRAM، والقيم الافتراضية لنافذة السياق — فتعود إلى اختيار النموذج ولا تُكرَّر هنا.
ما الذي تفعله طبقة التقديم، وما الذي يفعله ملف النموذج
تنفصل مسؤوليتان. فملف النموذج يحمل الأوزان والمفردات وصيغة التوجيه. وطبقة التقديم تتولى الجدولة، وإدارة الذاكرة، والتزامن، والواجهة البرمجية. وللفصل نتيجة ملموسة: ملف النموذج نفسه يمكن أن يعمل على الطبقات الأربع جميعاً، لكن عدد المستخدمين الذين يتلقون جواباً في وقت واحد على العتاد نفسه تقرره طبقة التقديم، لا الملف.
وعملياً تأخذ الطبقة عادةً هيئة خادم HTTP: فوثائق خادم llama.cpp تصف أداتها بأنها خادم HTTP خفيف بلغة C/C++ خالصة مبني على httplib وnlohmann::json، ويقدّم واجهات REST وواجهة ويب. والأسس تتداخل أيضاً — ففي 15 مايو 2025 أعلنت Ollama محركها الخاص فوق مكتبة الموتّرات GGML للنماذج متعددة الوسائط، قائلة في المنشور نفسه إنها اعتمدت حتى ذلك الحين على مشروع llama.cpp لدعم النماذج.
مقاربات التجميع: ثابت، وديناميكي، ومستمر
أول قرار تتخذه طبقة التقديم هو كيفية تجميع الطلبات الواصلة في الوقت نفسه.
- دفعة ثابتة: تُجمَع الطلبات في مجموعة، وتُنفَّذ ككل، ولا تبدأ الدفعة التالية حتى ينتهي كل طلب فيها. وهذه التسمية وصفية فقط؛ وليست مصطلحاً من أي مصدر.
- التجميع الديناميكي: يشكّل الخادم الدفعة وقت التشغيل. فتنتظر الطلبات قليلاً وتُرسَل ما إن يُبلَغ الحجم المفضّل أو تنفد ميزانية التأخير.
- التجميع المستمر: تُقرَّر محتويات الدفعة من جديد عند كل تكرار. فالطلب المنتهي يغادر، والمنتظر ينضم فور اكتمال التكرار الجاري.
والصورة الموثّقة للمقاربة الوسطى تقع في NVIDIA Triton (انظروا Triton Inference Server — Dynamic Batcher). فالتجميع الديناميكي يدمج الطلبات الفردية في دفعة واحدة عند لحظة يختارها الخادم. والانتظار محدود بـ max_queue_delay_microseconds، والإعداد المثال يستخدم 100 ميكروثانية.
والمصدر الأساسي للمقاربة الثالثة هو Orca (USENIX OSDI ’22, pp. 521-538). وتذكر الورقة النتيجة أولاً: كانت الأنظمة حتى ذلك الحين تجدول التنفيذ بحبيبة الطلب، فتُبقي مجموعة ثابتة من الطلبات حتى ينتهي كل طلب في الدفعة، فلا يستطيع الطلب المنتهي مبكراً العودة إلى العميل، وينتظر الوافد المتأخر حتى تُستنزَف الدفعة الحالية تماماً. وجواب Orca هو إنزال الجدولة إلى حبيبة التكرار: فالمجدول يختار الطلبات التي ستعمل، ويستدعي المحرك لتكرار واحد، ويجمع النتائج. وهذا هو أصل ما يُسمى اليوم التجميع المستمر.
وتعرّف الورقة تقنية ثانية كذلك: التجميع الانتقائي. فالتكرار التالي لطلبين لا يمكن دمجه دائماً — إن كان كلاهما في طور البدء بأعداد مختلفة من رموز الإدخال، أو كان كل منهما في طور مختلف، لم تتوافق أشكال موتّرات الانتباه. ولذلك يُطبَّق التجميع لا على كل العمليات بل على مختارات منها. وتذكر Orca إنتاجية أعلى بـ 36.9 ضعفاً من NVIDIA FasterTransformer على GPT-3 175B عند مستوى زمن الاستجابة نفسه: قياس من 2022، أمام مرجع ذلك اليوم.
والمصطلحات لا تُرسم بالطريقة نفسها في كل وثيقة. فوثائق خادم llama.cpp تعرّف راية --cont-batching بأنها «التجميع المستمر (المعروف أيضاً بالتجميع الديناميكي)» وتفعّلها افتراضياً. والفصل المفاهيمي أعلاه يعود إلى مصطلحات vLLM وSGLang.
PagedAttention: تقسيم ذاكرة KV إلى صفحات
ما إن تهبط الجدولة إلى حبيبة التكرار، تصير إدارة الذاكرة العامل الحاسم. والسبب سلوك ذاكرة KV: فهي كبيرة لكل طلب وتكبر وتصغر مع مضيّ التوليد. وتقول ورقة PagedAttention ذلك مباشرة — إن ذلك السلوك يحدد حجم الدفعة (انظروا Efficient Memory Management for Large Language Model Serving with PagedAttention, arXiv:2309.06180, SOSP ’23).
وما تقيسه الورقة هو الحصة: فمن 20.4% إلى 38.2% فقط من كتلة ذاكرة متصلة مخصصة سلفاً تحمل حالات رموز فعلية، مقابل 96.3% لـ vLLM في القياس نفسه. والباقي يذهب إلى خانات محجوزة لرموز مستقبلية وإلى مساحة ناتجة عن التخصيص وفق أقصى طول للتسلسل.
والجواب يأتي من أنظمة التشغيل. فـ PagedAttention يقسّم ذاكرة KV لكل طلب إلى كتل، تحمل كل واحدة متجهات المفتاح والقيمة لعدد ثابت من الرموز، ولا يشترط أن تكون تلك الكتل متجاورة في الذاكرة الفيزيائية. وتشبيه الورقة يحمل القسم كله: "one can think of blocks as pages, tokens as bytes, and requests as processes".
والمحاسبة تتبع ذلك. فكل مدخل في جدول الكتل يحمل رقم كتلة فيزيائية وعدد الخانات المملوءة في تلك الكتلة؛ وذاكرة الطلب سلسلة من كتل منطقية تُملأ من اليسار إلى اليمين، ولا تُخصَّص كتلة فيزيائية جديدة إلا بعد امتلاء السابقة. وكل كتلة فيزيائية تحمل عدّاد مراجع ويُطبَّق النسخ عند الكتابة بحبيبة الكتلة: فمخرجان يتشاركان توجيهاً يبقيان نسخة واحدة من حالة التوجيه، والكتابة تخصّص كتلة جديدة.
وعائد المشاركة مقيس: ففي البحث الشعاعي، تعطي مشاركة الكتل توفيراً في الذاكرة يصل إلى 55%. وتذكر الورقة إنتاجية أعلى بـ 2-4 أضعاف أمام FasterTransformer وOrca عند مستوى زمن الاستجابة نفسه — قياس من 2023 أمام مراجع ذلك اليوم.
RadixAttention وذاكرة البادئة: إعادة استخدام السياق المشترك
والتغيّر الثالث في الحبيبة على جانب إعادة الاستخدام. فـ PagedAttention جعل المشاركة داخل الطلب الواحد رخيصة؛ وSGLang يستهدف المشاركة بين الطلبات (انظروا SGLang: Efficient Execution of Structured Language Model Programs, arXiv:2312.07104).
وما يميّز RadixAttention بسيط: فهو يحفظ الذاكرة في شجرة جذرية بعد انتهاء التوليد بدل أن يهملها. والشجرة الجذرية صورة موفّرة للمساحة من شجرة البادئة، ويمكن وسم حوافها بتسلسلات متغيرة الطول لا بعناصر مفردة. وتربط الشجرة تسلسلات الرموز بموتّرات ذاكرة KV الخاصة بها، وتُخزَّن التوجيهات والتوليدات معاً.
وهذه طبقة، لا بديل. فتذكر الورقة بوضوح أن RadixAttention متوافق مع التجميع المستمر والانتباه المصفَّح وتوازي الموتّرات، وأنه حين لا تقع إصابة في الذاكرة، تكون كلفة الذاكرة والوقت التي يضيفها مهملة.
والاستعادة تتبع سياسة LRU وتبدأ من الأوراق: فالورقة الأقل استخداماً حديثاً تذهب أولاً، وتبقى الأسلاف المشتركة قابلة لإعادة الاستخدام حتى تصير أوراقاً هي نفسها. ولا يُخصَّص سلفاً أي مجمّع ذاكرة ثابت الحجم؛ فالرموز المخزّنة والطلبات العاملة تتشارك مجمّع الذاكرة نفسه.
والجدولة واعية بالذاكرة كذلك: فالطلبات تُرتَّب بطول البادئة المطابقة. وتنص النظرية 3.1 على أنه حين لا يكون حجم الذاكرة أصغر من أقصى طول طلب، يكافئ ترتيبُ الأطول بادئةً مشتركةً أولاً اجتيازاً عميقاً أولاً للشجرة الجذرية ويعطي معدل الإصابة الأمثل.
وموضع العائد ملموس: التوجيهات قليلة الأمثلة، وسجل المحادثات متعدد الأدوار، والسياق المشترك في مسار RAG. وعبر تلك المقاييس يتراوح معدل الإصابة بين 50% و99%، وتقترب الجدولة الواعية بالذاكرة من 96% من معدل الإصابة الأمثل في المتوسط. وفي نشر استمر شهراً على Chatbot Arena، لوحظ معدل إصابة 52.4% لـ LLaVA-Next-34B و74.1% لـ Vicuna-33B، مع انخفاض متوسط زمن أول رمز لـ Vicuna-33B بمقدار 1.7 ضعف — ملاحظة من 2024، خاصة بذلك الحمل.
ويقدّم vLLM الوظيفة نفسها اليوم؛ والفارق بنيوي. ففي vLLM تكون هوية الكتلة قائمة على التجزئة: إذ تتشكل تجزئة الكتلة من تجزئة الكتلة الأم ومن الرموز التي فيها، ولا تُخزَّن إلا الكتل الممتلئة، ويدخل ملح تخزين في التجزئة لفصل الذواكر في البيئات متعددة المستأجرين. وخوارزمية التجزئة الافتراضية هي sha256 منذ الإصدار v0.11، وتخزين البادئة مفعّل افتراضياً. وعلى جانب SGLang تُبنى الوظيفة نفسها من شجرة جذرية بإخلاء الأوراق وفق LRU — الوظيفة نفسها ببنية بيانات مختلفة.
GGUF والملف التنفيذي الواحد: التغليف ونموذج التشغيل
والمحور الرابع يغادر الجدولة والذاكرة: التغليف. فـ GGUF صيغة ملفات لتخزين النماذج للاستدلال مع GGML والمنفّذين القائمين عليه. وأهداف تصميمه مسرودة بالترتيب في المواصفة: النشر بملف واحد — إذ يمكن توزيع الملفات وتحميلها بسهولة ولا تحتاج ملفات خارجية؛ وقابلية التوسيع؛ والتوافق مع mmap؛ وسهولة الاستخدام؛ والمعلومات الكاملة — إذ يحتوي الملف كل ما يلزم لتحميل نموذج.
وذلك الهدف الأخير ليس مجرداً. فمفاتيح البيانات الوصفية العامة معرَّفة بأنها general.architecture وgeneral.quantization_version وgeneral.file_type وgeneral.alignment. والمُرمِّز يسافر في الملف كاملاً: المفردات، وقواعد الدمج، وأنواع الرموز، ومعرّفات الرموز الخاصة. وألفت المفاتيح هو tokenizer.chat_template — قالب Jinja يصف صيغة الإدخال التي يتوقعها النموذج، جالساً في الملف نفسه مع الأوزان.
وفي نشر داخل مقر الشركة، ينبغي التمييز بين «ملفين واحدين» مختلفين. الأول ملف GGUF الواحد للنموذج. والثاني هو المشغّل نفسه: فأول نقطة ميزة لدى llama.cpp تنفيذ بلغة C/C++ خالصة بلا اعتماديات، ووحدة التوزيع ملف تنفيذي قابل للتنزيل لا حزمة حاويات.
ووحدة التغليف لدى Ollama هي Modelfile، وتصفها الوثائق بأنها مخطط إنشاء النموذج ومشاركته. وتعليماتها FROM وPARAMETER وTEMPLATE وSYSTEM وADAPTER وLICENSE وMESSAGE؛ ويقبل FROM اسم نموذج قائم، أو دليل Safetensors، أو مساراً إلى ملف GGUF. ويرتبط التكميم بخطوة الإنشاء، بالصيغة الموثّقة ollama create --quantize q4_K_M، ثم يُشارَك النموذج بـ ollama push ويُشغَّل على الطرف الآخر بـ ollama run. أما ما يعنيه مستوى التكميم على جانب الجودة والذاكرة فيعود إلى اختيار النموذج؛ والموضوع هنا هو التغليف نفسه.
أين التقى النظام البيئي: انتقال مستودع TGI إلى الأرشيف
وأحدث إشارة إلى سبب ذكر هذه الأسماء الأربعة معاً تأتي من مشروع أُغلق. فقد أُرشِف مستودع Text Generation Inference لدى Hugging Face في 21 مارس 2026؛ والتاريخ مكتوب في الشريط على صفحة المستودع. ويحمل ملف README إشعار وضع الصيانة.
والمهم هو الجملة الثانية من ذلك الإشعار نفسه. فهي تقول إن TGI بدأ حركة اعتماد محركات الاستدلال المحسّنة على معماريات نماذج transformers، وتوجّه القارئ بالاسم إلى vLLM، وSGLang، والمحركات العاملة محلياً ذات التوافق البيني مثل llama.cpp أو MLX. فثلاث من الطبقات الأربع في هذه الملاحظة مذكورة بالاسم في نص المشروع المغلق نفسه.
والخط الزمني قصير: آخر إصدار موسوم كان v3.3.7 في 19 ديسمبر 2025. وتُظهر قائمة ميزات المستودع كذلك ما كان يُعدّ قياسياً في ذلك التاريخ — توازي الموتّرات على وحدات معالجة رسومية متعددة، والتجميع المستمر للطلبات الواردة، وواجهة Messages متوافقة مع OpenAI Chat Completion API، وكود استدلال يستخدم Flash Attention وPaged Attention.
أي طبقة تناسب أي سيناريو في تركيب داخل المقر
وأكثر زوج أرقام ملموسية يفصل هذه الطبقات بحسب وضع التشغيل يقع في وثائق Ollama. فـ OLLAMA_NUM_PARALLEL هو عدد الطلبات المتزامنة لكل نموذج وقيمته الافتراضية 1؛ وOLLAMA_MAX_LOADED_MODELS هو عدد النماذج التي يمكن تحميلها في وقت واحد وقيمته الافتراضية 3 لكل وحدة معالجة رسومية. وتلك القيم الافتراضية تصف وضعاً: تزامن منخفض، ونماذج كثيرة.
والقيم الافتراضية في vLLM وSGLang تصف العكس: نموذج واحد، وتزامن عالٍ. فـ vLLM يجدول بالأسبقية في الوصول؛ ولأن كتل التسلسل يُوصل إليها معاً، يُطبَّق الإخلاء بمبدأ الكل أو لا شيء. ويُدعَم توازي الموتّرات على نمط Megatron-LM، ولأن كل شظية من النموذج تعالج مجموعة رموز الإدخال نفسها، يُحتفَظ بمدير واحد لذاكرة KV وبتعيين واحد من الكتل المنطقية إلى الفيزيائية داخل المجدول المركزي.
ويصف SGLang نفسه بأنه إطار تقديم يتوسّع من وحدة معالجة رسومية واحدة إلى عناقيد موزّعة كبيرة. والقيم الافتراضية في وسائط خادمه تؤكد الوضع: ذاكرة جذرية مفعّلة، وlru سياسةً للإخلاء، وحجم صفحة 1، وحجم توازي موتّرات 1.
ووضع llama.cpp هو أدنى إعداد ممكن: قائمة خلفيات تمتد من BLAS إلى CUDA وMetal وVulkan، واستدلال هجين بين المعالج ووحدة الرسوميات يسرّع جزئياً النماذج الأكبر من إجمالي سعة VRAM. وعلى جانب Ollama، تعيش أدلة النماذج في مواضع موثّقة وتنتقل بمتغيّر البيئة OLLAMA_MODELS؛ وحيث تكون محلية البيانات شرطاً مكتوباً، ينتمي ذلك المسار إلى وثيقة النشر أيضاً.
والواجهة البرمجية توحّد الوصول إلى النموذج؛ أما الطبقة التي توحّد وصول النموذج إلى أنظمة المؤسسة فطبقة أخرى، وتتناولها ملاحظة «ما هو خادم MCP، وما ليس هو».
والمقابل المعماري لسؤال من يجوز له رؤية أي سياق في تركيب مشترك تعالجه ملاحظة «التحكم في الوصول داخل RAG: من يرى ماذا».
وإيقاع الإصدارات سريع. فحتى 8 أغسطس 2026 يكون الإصدار الموسوم لـ vLLM هو v0.26.0 (27 يوليو 2026) ولـ SGLang هو v0.5.17 (8 أغسطس 2026). وأسماء الرايات والقيم الافتراضية في هذه الملاحظة تعود إلى ذلك التاريخ نفسه؛ فقارنوها بوثائق إصداركم قبل النشر.
المصادر
- Orca: A Distributed Serving System for Transformer-Based Generative Models — USENIX OSDI ’22, pp. 521-538 (iteration-level scheduling, selective batching, the 36.9x measurement)
- Efficient Memory Management for Large Language Model Serving with PagedAttention — arXiv:2309.06180, SOSP ’23 (block table, copy-on-write, token-state share)
- SGLang: Efficient Execution of Structured Language Model Programs — arXiv:2312.07104 (RadixAttention, cache-aware scheduling, Theorem 3.1)
- NVIDIA Triton Inference Server Documentation — Dynamic Batcher (max_queue_delay_microseconds)
- vLLM — GitHub repository, README.md and vllm/config/cache.py (feature list, prefix caching default)
- vLLM Documentation — Automatic Prefix Caching, Structured Outputs, OpenAI-Compatible Server, Parallelism and Scaling
- SGLang — GitHub repository and Documentation, Server Arguments (radix cache default, lru, page size 1)
- Text Generation Inference — GitHub repository (archived on 21 March 2026; last release v3.3.7)
- GGUF Specification — ggml-org/ggml, docs/gguf.md (design goals, tokenizer.chat_template)
- llama.cpp — GitHub repository and tools/server/README.md (dependency-free implementation, backend table)
- Ollama Documentation — Modelfile Reference, Import a model, OpenAI compatibility and FAQ (concurrency defaults, model directories)
- Ollama’s new engine for multimodal models — Ollama Blog, 15 May 2025
- GitHub Releases — vllm-project/vllm v0.26.0 and sgl-project/sglang v0.5.17