أحدث صعود نماذج اللغة الكبيرة (LLMs) تحولاً جذرياً في متطلبات البنية التحتية. على عكس الخدمات المصغرة التقليدية، فإن أحمال عمل استنتاج LLM كثيفة الموارد وحساسة للغاية لقدرات العتاد. ومع انتقال المؤسسات من التطوير إلى الإنتاج، تواجه مشهداً متجزئاً من العتاد: عناقيد GPU للتدريب والاستنتاج عالي الإنتاجية، وحواسيب CPU فقط للنشر على الحافة أو المحسّن للتكلفة، ومعماريات CPU متباينة (amd64 مقابل arm64) عبر مزودي السحابة. ضمان تشغيل حاويات استنتاج LLM الخاصة بك بشكل موثوق عبر هذا الطيف يتطلب استراتيجيات بناء متطورة.
تحدي العتاد غير المتجانس
صورة Docker قياسية مبنية على حاسوب محمول للتطوير مزود بـ NVIDIA GPU ستفشل على عقدة إنتاج تعتمد على CPU فقط، والعكس صحيح. علاوة على ذلك، خلط مكتبات CUDA في الصورة الأساسية يسبب تضخماً وتعارضات في الاعتماديات إذا كان الجهاز المستهدف يفتقر إلى برامج تشغيل NVIDIA. في LLMOps، يجب علينا فصل الاهتمامات: منطق التطبيق، أوزان النموذج، والاعتماديات وقت التشغيل (CUDA/CPU) يجب أن تكون وحدات مستقلة.
الاستراتيجية 1: فصل الصور الأساسية حسب المعمارية
بدلاً من صورة "شاملة" واحدة ضخمة، حافظ على صور أساسية مميزة لأهداف العتاد المختلفة.
- صورة GPU: مبنية على
nvidia/cuda:11.8-runtime-ubuntu22.04. تتضمن أدوات CUDA ومكتبات خاصة بـ GPU مثلflash-attn. - صورة CPU: مبنية على
python:3.10-slim. تتضمن MKL أو OpenBLAS لحسابات CPU المحسّنة، لكنها تستبعد جميع اعتماديات CUDA.
الاستراتيجية 2: إدارة الاعتماديات المعيارية
استخدم آلية الاعتماديات الشرطية في Python لتثبيت الحزم فقط عند اكتشاف العتاد ذي الصلة. هذا يمنع مشاكل ImportError على العقد غير المتوافقة.
# requirements-gpu.txt
torch==2.0.1+cu118
transformers==4.36.0
flash-attn==2.3.6 # GPU only
# requirements-cpu.txt
torch==2.0.1
transformers==4.36.0
في Dockerfile الخاص بك، استخدم حجة البناء (build arguments) لاختيار ملف المتطلبات الصحيح:
ARG BUILD_VARIANT=cpu
RUN if [ "$BUILD_VARIANT" = "gpu" ]; then \
pip install -r requirements-gpu.txt; \
else \
pip install -r requirements-cpu.txt; \
fi
الاستراتيجية 3: الاستفادة من BuildX للبناء متعدد المعماريات
للأهداف المعتمدة على CPU، يجب أن تدعم كل من amd64 و arm64 (شائعة في AWS Graviton و Apple Silicon). استخدم Docker Buildx لإنشاء قوائم متعددة المعماريات دون الحاجة إلى عتاد فعلي لكل معمارية.
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg BUILD_VARIANT=cpu \
-t my-llm-app:cpu-mixed .
الاستراتيجية 4: فصل أوزان النموذج
لا تدمج أبداً أوزان النماذج الكبيرة (7B-13B بارامتر) في صورة Docker الخاصة بك. تصبح الصور ضخمة الحجم (عدة جيجابايت)، مما يبطئ خطوط CI/CD وسحب السجلات. بدلاً من ذلك، استخدم تركيبات الأحجام (volume mounts) أو اسحب الأوزان من سجل (مثل Hugging Face Hub) عند بدء تشغيل الحاوية. هذا يضمن بقاء صورتك خفيفة الوزن وقابلة للتبويب، بينما يمكن تحديث النماذج بشكل مستقل.
أفضل الممارسات لتنفيذ CI/CD
1. التخزين المؤقت للطبقات بشكل عدواني: احتفظ بـ pip install للاعتماديات الأساسية في الطبقات المبكرة. انسخ كود التطبيق فقط في الطبقات اللاحقة.
2. فحوصات الصحة: نفّذ CMD HEALTHCHECK للتحقق من توفر GPU (باستخدام nvidia-smi) أو عدد أنوية CPU قبل إعلان الخدمة جاهزة.
3. اتفاقية التسمية: استخدم وسوم مثل my-llm:v1.0-gpu و my-llm:v1.0-cpu لمنع عدم التطابق العرضي في النشر.
الخاتمة
تحويل استنتاج LLM إلى حاويات لا يتعلق بإنشاء صورة واحدة تناسب الجميع. إنه يتعلق ببناء مجموعة من المخرجات المحسّنة والمخصصة للعتاد. من خلال فك ارتباط اعتماديات وقت التشغيل، والاستفادة من حجة البناء، وفصل أوزان النموذج عن كود التطبيق، يمكنك تحقيق نشرات LLM موثوقة وقابلة للتوسع وفعالة من حيث التكلفة عبر أي طوبولوجيا عتاد. ابدأ بملفات Docker المعيارية في مرحلة مبكرة من خط LLMOps الخاص بك لتجنب الديون التقنية مع توسع بنيتك التحتية.