
بقلم: يوسف | محرر أدوات الذكاء الاصطناعي · صوت تحريري بإشراف بشري
الـ LLM المحلي الذي يُعيد نصاً حراً لا يكفي حين يكون جزءاً من منظومة أكبر. المكوّن التالي في سلسلة العمل يحتاج بيانات يمكن تحليلها برمجياً، لا فقرات نثرية. هنا يأتي دور Structured Output: بدلاً من أن تطلب من النموذج إجابة حرة، تُعرّف مسبقاً الشكل المتوقع للمخرجات وتُلزم النموذج بالالتزام به. النتيجة كائن Python جاهز للاستخدام المباشر، بدلاً من نص يحتاج إلى parsing يدوي مُرهق. هذا الدليل يشرح كيف تُحقق ذلك عملياً باستخدام Ollama كـ runtime محلي، وNemma 4 كنموذج، وPydantic لتعريف الـ schema والتحقق منه.
دراسة الحالة التي يعتمدها هذا الشرح هي تطبيق منزل ذكي: المستخدم يسأل “هل أُشغّل غسالة الأطباق الآن أم لاحقاً؟”، والتطبيق بحاجة إلى استخراج معلومات الأجهزة وأوقات التشغيل والتعريفات الكهربائية من ملاحظات المنزل. بما أن هذه الملاحظات تحتوي على بيانات خاصة، يقوم LLM محلي بتحويلها إلى كائن منظم يحتفظ فقط بالحقائق اللازمة للجدولة، ثم يُمرَّر هذا الكائن المعقّم إلى نموذج سحابي أقوى لاتخاذ القرار. التركيز هنا على خطوة التحويل المحلية.
- تعريف المخرجات المتوقعة بـ Pydantic — ابدأ بتحديد شكل الكائن الذي تريده. في هذا المثال، يتضمن النموذج
SchedulingContextالوقت الحالي، الجهاز محل الاهتمام، عدد الأجهزة العاملة في وقت واحد، سعر الكهرباء الحالي، أوقات التعريفة المنخفضة وسعرها، وقائمة منDeviceToSchedule. كل جهاز يحمل: الاسم، مدة الدورة بالدقائق، استهلاك الطاقة بالـ kWh، أبكر وقت للبدء، وأحدث وقت للانتهاء. هذه القيود تُفرَّغ مباشرةً من ملاحظات المنزل: الغسالة تحتاج 90 دقيقة وتستهلك 1.2 kWh وتبدأ على أبكر تقدير 18:30، وشاحن السيارة يحتاج 120 دقيقة و14 kWh، والغسالة الأوتوماتيك 60 دقيقة و0.9 kWh. تعريفة الكهرباء تتراوح بين 0.45 في الساعة الذروة (17:00–20:00) و0.12 في الوادي (00:00–06:00). - تثبيت Ollama وسحب نموذج Gemma 4 — على Windows نفّذ
winget install Ollama.Ollama، وعلى macOS/Linux استخدمcurl -fsSL https://ollama.com/install.sh | sh. بعد التثبيت، اسحب النموذج بالأمرollama pull gemma4:e4b— وهو المتغير المضغوط بحجم 4B مناسب للاستخدام المحلي. ثبّت المكتبتين المطلوبتين بـpip install ollama pydantic. - ربط Pydantic بـ Ollama عبر دالة مركزية — الفكرة الجوهرية هي تمرير الـ schema مباشرةً إلى Ollama عبر المعامل
format. الدالةcall_local_llmتستخدمschema.model_json_schema()لتحويل نموذج Pydantic إلى JSON Schema يفهمه Ollama، ثم تمرره في استدعاءollama.chat()مع الرسائل وإعدادthink="medium". عند عودة الاستجابة، تستدعيschema.model_validate_json()لتحليل JSON وتحويله إلى كائن Python صالح للاستخدام المباشر. - صياغة التعليمات وبناء الـ prompt — التعليمات يجب أن تكون صريحة ومحدودة: “حوّل المادة المُدخلة إلى سياق جدولة منظم. لا تقترح جدولة ولا تتخذ قرارات.” الـ prompt يدمج سؤال المستخدم مع ملاحظات المنزل في نص واحد. البساطة مقصودة: كلما زادت الحرية التفسيرية، زادت احتمالية الخطأ.
- تشغيل الاستدعاء أحادي الخطوة وفهم حدوده — عند تمرير
SchedulingContextكاملاً في استدعاء واحد، يعيد Gemma 4 JSON صالح يُحلَّل بنجاح بـ Pydantic. لكن يظهر خطأ محتوى: المكنسة الروبوتية تُدرج ضمنdevices_to_scheduleرغم أن الملاحظات تُفيد بأنها أنجزت مهمتها الساعة 16:10 ولا حاجة لتشغيلها اليوم. هذا يكشف التمييز الجوهري: Structured Output يُلزم بالشكل، لكنه لا يضمن صحة المحتوى. في استدعاء واحد، يُكلَّف النموذج بأربعة أعمال متزامنة: تحديد الأجهزة المطلوبة، استخراج حقائقها، تعيين الحقول الصحيحة، وتجميع الكائن المتداخل — وهو حمل ثقيل على نموذج محلي مضغوط. - تفكيك المهمة إلى خطوتين منفصلتين — الحل هو الاستدعاء المرحلي. الخطوة الأولى تستخدم schema مبسطة
SchedulingScopeتحتوي فقط على اسم الجهاز محل الاهتمام وقائمة أسماء الأجهزة التي تحتاج جدولة. Gemma 4 يُعيد هذه المرة النتيجة الصحيحة: الغسالة وشاحن السيارة والغسالة الأوتوماتيك فقط، دون المكنسة. الخطوة الثانية تُمرر قائمة الأجهزة المستخرجة مع السؤال الأصلي والملاحظات إلىSchedulingContextالكامل — فيُنتج النموذج المخرجات الصحيحة بالكامل. - التحقق من النتيجة النهائية — الكائن المُعاد يحتوي على: الوقت الحالي 18:30، السعر الحالي 0.45 لكل kWh، بداية الـ off-peak 00:00 ونهايتها 06:00 بسعر 0.12، والأجهزة الثلاثة بحقائقها الدقيقة كما في الملاحظات الأصلية. لا مكنسة، لا بيانات شخصية، وكل قيمة رقمية مطابقة للمصدر. النهج المرحلي يُنتج بنية صحيحة ومحتوى صحيح معاً.
الدرس العملي من هذا المثال يتجاوز أدوات بعينها: حين يفشل LLM محلي في إنتاج محتوى صحيح رغم التزامه بالشكل، لا تتسرع في رفع حجم النموذج أو تعقيد الـ prompt. جرّب أولاً تقسيم المهمة إلى استدعاءات أصغر، لكل منها schema مبسطة وهدف واحد واضح. النماذج المحلية المضغوطة تؤدي بشكل أفضل بكثير حين تُعطى قرارات محدودة وواضحة، لا قرارات متعددة متشابكة في وقت واحد. وإن كنت تبني workflows مع نماذج متعددة الوكلاء، فهذا المبدأ هو نفس المنطق الذي تعتمده أنظمة الوكلاء الحديثة في تقسيم المسؤوليات.







