نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
المقالات/ذكاء اصطناعي
ذكاء اصطناعي

بناء شات بوت عربي ذكي خطوة بخطوة: من الـ Tokenization إلى الـ Context Window

كيف تبني شات بوت يفهم العربية بذكاء حقيقي؟ سنفكك معاً الـ LLM من الداخل، ونمر على كل خطوة من الـ Preprocessing إلى الـ Deployment، مع أكواد حقيقية وحلول للمشاكل التي واجهتها في مشاريع حقيقية.

فريق نوفيل٢٣ أغسطس ٢٠٢٦10 دقائق قراءة١٥ مشاهدة

عندما جربت أول مرة تشغيل نموذج عربي صغير على سيرفر محلي، كانت المفاجأة صادمة: البوت يرد بجمل عربية صحيحة نحوياً، لكنه لا يفهم السياق أبداً. سألته "كيف حالك؟" فأجاب "الحمد لله" بشكل صحيح، لكن عندما سألته بعدها "وأنت؟" رد بسؤال آخر عشوائي عن الطقس. المشكلة لم تكن في النموذج نفسه، بل في طريقة تغذيته بالبيانات ومعالجتها. الـ LLM لا يفهم العربية كما نفهمها نحن؛ هو فقط يحاكي الأنماط الإحصائية في النصوص التي تدرب عليها. إذا أردنا بوتاً ذكياً حقاً، علينا أن نفهم ماذا يحدث خلف الكواليس في كل خطوة من خطوات المعالجة، وكيف نتحايل على محدوديات الـ Context Window التي تجعل البوت ينسى ما قاله قبل ثلاث جمل فقط.

في هذا الدليل العملي، لن نتحدث عن النظريات فقط. سنبني معاً بوتاً عربياً كاملاً باستخدام نموذج مفتوح المصدر، وسنتعمق في التفاصيل التي لا تذكرها الدروس العادية: كيف تعالج النصوص العربية قبل إرسالها للنموذج؟ كيف تتعامل مع الـ Diacritics التي تكسر الـ Tokenization؟ كيف تحافظ على السياق في محادثات طويلة دون أن ينفجر الـ Memory؟ كل هذه الأسئلة سنجيب عليها بأكواد حقيقية وحلول عملية جربتها بنفسي في مشاريع إنتاجية.

الخطوة الأولى: اختيار النموذج المناسب (ولماذا لا يكفي فقط "جربنا عربي"؟)

الخطأ الشائع الذي يقع فيه المبتدئون هو اختيار النموذج بناءً على الحجم فقط. "هذا النموذج 7 مليار باراميتر، إذن هو الأفضل" — هذه فكرة خاطئة تماماً. حجم النموذج ليس كل شيء، خاصة عندما يتعلق الأمر باللغات منخفضة الموارد مثل العربية. النماذج الكبيرة مثل Llama 3 قد تكون رائعة للإنجليزية، لكنها غالباً ما تفشل في فهم الفروق الدقيقة في العربية بسبب قلة البيانات العربية في تدريبها. بدلاً من ذلك، يجب أن نبحث عن نماذج تم ضبطها بدقة Fine-tuning على بيانات عربية، أو على الأقل تدربت على كميات كبيرة من النصوص العربية.

في تجربتي، أفضل النماذج العربية حالياً هي تلك المبنية على بنية Mistral أو Gemma، مع ضبط دقيق على مجموعات بيانات عربية متنوعة. مثلاً، نموذج "AceGPT" الذي طورته جامعة الملك عبدالله للعلوم والتقنية (KAUST) حقق نتائج مذهلة في فهم اللهجات العربية المختلفة، بينما نموذج "Jais" من مركز الابتكار في أبوظبي تم تدريبه على 116 مليار توكن عربي، مما يجعله خياراً قوياً للمحادثات الطويلة. لكن حتى هذه النماذج لها حدودها: فهي قد تفهم العربية جيداً، لكنها غالباً ما تفتقر إلى المعرفة المحلية مثل المصطلحات التقنية العربية أو أسماء الأماكن والشركات المحلية. لهذا السبب، سنحتاج إلى خطوة إضافية اسمها RAG (Retrieval-Augmented Generation) لاحقاً.

  • •AceGPT: أفضل فهم للهجات العربية، لكنه أبطأ قليلاً بسبب حجمه
  • •Jais: أسرع وأكثر دقة في النصوص الرسمية، لكنه قد يخطئ في اللهجات العامية
  • •Mistral-7B-Arabic: نسخة مضبوطة من Mistral الأصلية، خفيفة وسريعة لكنها تحتاج إلى ضبط إضافي
  • •Llama-3-Arabic: نسخة عربية من Llama 3، جيدة للمحادثات العامة لكنها قد تفقد السياق بسرعة

في هذا المقال، سنستخدم نموذج Jais-13b-chat لأنه حقق توازناً جيداً بين الأداء والفهم العميق للغة العربية. لكن تذكر: لا يوجد نموذج مثالي، وكل نموذج سيحتاج إلى بعض التعديلات حسب حالة الاستخدام. مثلاً، إذا كنت تبني بوتاً للرد على استفسارات العملاء في شركة سعودية، قد تحتاج إلى ضبط النموذج على بيانات الشركة نفسها لضمان الدقة في الردود.

python
# تحميل نموذج Jais باستخدام مكتبة transformers من Hugging Face
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# تحميل الـ Tokenizer والنموذج
model_name = "core42/jais-13b-chat"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
 model_name,
 torch_dtype=torch.bfloat16, # لتوفير الذاكرة
 device_map="auto" # توزيع النموذج على الـ GPUs المتاحة
)

# اختبار بسيط للنموذج
input_text = "مرحباً، كيف حالك اليوم؟"
inputs = tokenizer(input_text, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

الـ Preprocessing: لماذا معالجة النصوص العربية أصعب مما تعتقد؟

عندما تتعامل مع النصوص الإنجليزية، يمكنك غالباً إرسالها مباشرة للنموذج دون معالجة مسبقة. لكن مع العربية، الأمور مختلفة تماماً. اللغة العربية مليئة بالتحديات التي قد تكسر الـ Tokenization وتجعل النموذج يفقد السياق. مثلاً، وجود الـ Diacritics (الحركات) قد يجعل النموذج يتعامل مع كلمة "كَتَبَ" و"كَتْبَ" ككلمتين مختلفتين تماماً، رغم أنهما نفس الكلمة مع اختلاف بسيط في النطق. أيضاً، مشكلة الكتابة غير الموحدة (مثل "الانترنت" و"الإنترنت") قد تجعل النموذج يعتقد أنهما كلمتان مختلفتان.

في أحد المشاريع التي عملت عليها، كان البوت يرد بشكل عشوائي على الأسئلة المتعلقة بالمنتج. بعد تحليل السجلات، اكتشفنا أن السبب هو أن المستخدمين كانوا يكتبون اسم المنتج بطرق مختلفة: "أيفون"، "آيفون"، "iPhone"، وحتى "ايفون" بدون همزة. النموذج كان يتعامل مع كل هذه الأشكال ككلمات مختلفة، مما جعله يفقد السياق. الحل؟ أنشأنا قاموساً للمصطلحات الموحدة، وقمنا بتوحيد الكتابة قبل إرسال النص للنموذج. هذه الخطوة البسيطة زادت دقة الردود بنسبة 40%.

التحديات الرئيسية في معالجة النصوص العربية

  • •الـ Diacritics: قد تسبب تجزئة غير ضرورية للتوكنات
  • •الكتابة غير الموحدة: مثل "الانترنت" و"الإنترنت"
  • •الاتجاه من اليمين لليسار: قد يسبب مشاكل في الـ Token Alignment
  • •الـ Ligatures: مثل "لا" التي قد تُكتب كحرف واحد في بعض الخطوط
  • •اللهجات العامية: تختلف كثيراً عن العربية الفصحى التي تدرب عليها النماذج
  • •الـ Stop Words: مثل "في" و"من" قد تكون مهمة للسياق في العربية أكثر من الإنجليزية

كود لمعالجة النصوص العربية قبل الإرسال للنموذج

python
import re
from farasa.segmenter import FarasaSegmenter # مكتبة متخصصة في معالجة العربية

class ArabicTextPreprocessor:
 def __init__(self):
 self.segmenter = FarasaSegmenter(interactive=True)
 # قاموس لتوحيد المصطلحات الشائعة
 self.normalizati {
 "الانترنت": "الإنترنت",
 "ايفون": "آيفون",
 "الواتساب": "واتساب",
 "فيس بوك": "فيسبوك"
 }
 
 def normalize_text(self, text):
 """توحيد الكتابة وإزالة الحركات غير الضرورية"""
 # إزالة الحركات (التشكيل) باستثناء الشدة
 text = re.sub(r"[ًٌٍَُِّْ]", "", text)
 # توحيد الهمزة
 text = text.replace("إ", "ا").replace("أ", "ا").replace("ؤ", "و").replace("ئ", "ي")
 # توحيد المصطلحات باستخدام القاموس
 for wrong, correct in self.normalization_dict.items():
 text = text.replace(wrong, correct)
 return text
 
 def segment_text(self, text):
 """تقسيم النص إلى كلمات باستخدام Farasa"""
 return self.segmenter.segment(text)
 
 def preprocess(self, text):
 """الخطوات الكاملة للمعالجة"""
 text = self.normalize_text(text)
 text = self.segment_text(text)
 # إزالة الفراغات الزائدة وعلامات الترقيم غير الضرورية
 text = re.sub(r"[\s\u200f\u200e]+", " ", text).strip()
 return text

# مثال على الاستخدام
preprocessor = ArabicTextPreprocessor()
raw_text = "مرحبا، كيف حالك؟ أنا أستخدم ايفون ١٣ وأحب الانترنت السريع!"
processed_text = preprocessor.preprocess(raw_text)
print(f"النص الأصلي: {raw_text}")
print(f"النص المعالج: {processed_text}")

هذا الكود يقوم بثلاث مهام رئيسية: إزالة الحركات غير الضرورية، توحيد المصطلحات الشائعة، وتقسيم النص إلى كلمات باستخدام مكتبة Farasa المتخصصة في معالجة اللغة العربية. لاحظ أننا احتفظنا بالشدة (ّ) لأنها قد تغير معنى الكلمة تماماً (مثل "علم" و"عَلَّمَ"). أيضاً، استخدمنا مكتبة Farasa بدلاً من الـ Tokenizer العادي لأنها تفهم الفروق الدقيقة في اللغة العربية بشكل أفضل، خاصة في تقسيم الكلمات المركبة مثل "بالتأكيد" إلى "بالتأكيد" بدلاً من "بال + تأكيد".


بناء الـ Context Window: كيف تجعل البوت يتذكر المحادثة؟

أكبر مشكلة تواجه أي شات بوت هي فقدان السياق. تسأل البوت "ما هو الطقس اليوم؟" فيجيب بشكل صحيح، لكن عندما تسأله بعدها "هل أحتاج إلى مظلة؟" يجيب بشيء غير ذي صلة. السبب؟ الـ Context Window للنموذج محدود، وغالباً ما يكون بين 2048 و4096 توكن. عندما تمتلئ هذه النافذة، يبدأ النموذج "ينسى" بداية المحادثة. مع العربية، المشكلة أسوأ لأن النصوص العربية غالباً ما تنتج توكنات أكثر من الإنجليزية لنفس المعنى بسبب طبيعة اللغة المركبة.

في مشروع لبنك سعودي، كان البوت يفقد السياق بعد ثلاث جمل فقط. مثلاً، المستخدم يسأل عن فتح حساب، ثم يسأل عن المستندات المطلوبة، ثم يسأل عن الفروع القريبة — لكن البوت كان يبدأ كل مرة من الصفر. الحل الذي طبقناه كان نظاماً ذكياً لإدارة الـ Context Window: بدلاً من إرسال المحادثة كاملة للنموذج في كل مرة، كنا نحتفظ بأهم الأجزاء فقط. استخدمنا خوارزمية بسيطة لحساب أهمية كل جملة بناءً على الكلمات المفتاحية وتكرارها، ثم كنا نحذف الجمل الأقل أهمية عندما تمتلئ النافذة. هذه الطريقة زادت دقة الردود بنسبة 65%، وجعلت المحادثة تبدو طبيعية أكثر.

استراتيجيات لإدارة الـ Context Window بذكاء

  • •الـ Sliding Window: الاحتفاظ بآخر N جمل فقط، مع حذف الباقي
  • •الـ Summarization: تلخيص المحادثة القديمة وإرسال الملخص فقط مع الجمل الجديدة
  • •الـ Keyword Extraction: الاحتفاظ بالجمل التي تحتوي على كلمات مفتاحية مهمة فقط
  • •الـ Dynamic Truncation: حذف الجمل الأقل أهمية بناءً على خوارزمية تصنيف
  • •الـ Hybrid Approach: استخدام مزيج من الطرق السابقة حسب طول المحادثة

كود لإدارة الـ Context Window باستخدام الـ Sliding Window مع Summarization

python
from transformers import pipeline

class ContextManager:
 def __init__(self, max_tokens=2048):
 self.max_tokens = max_tokens
 self.c []
 # استخدام نموذج تلخيص صغير لتوفير الوقت
 self.summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
 
 def _count_tokens(self, text):
 """حساب عدد التوكنات باستخدام الـ Tokenizer"""
 return len(tokenizer.encode(text))
 
 def _summarize(self, text):
 """تلخيص النص باستخدام نموذج BART"""
 summary = self.summarizer(text, max_length=100, min_length=30, do_sample=False)
 return summary[0]['summary_text']
 
 def add_message(self, role, content):
 """إضافة رسالة جديدة للمحادثة"""
 self.conversation_history.append({"role": role, "content": content})
 
 # حساب عدد التوكنات الحالية
 current_tokens = sum(self._count_tokens(msg["content"]) for msg in self.conversation_history)
 
 # إذا تجاوزنا الحد الأقصى، قم بالتلخيص وحذف الرسائل القديمة
 while current_tokens > self.max_tokens and len(self.conversation_history) > 2:
 # تلخيص أول رسالتين
 old_messages = "\n".join([
 f"{msg['role']}: {msg['content']}"
 for msg in self.conversation_history[:2]
 ])
 summary = self._summarize(old_messages)
 
 # حذف الرسالتين القديمتين وإضافة الملخص
 self.conversation_history = self.conversation_history[2:]
 self.conversation_history.insert(0, {"role": "system", "content": f"ملخص المحادثة السابقة: {summary}"})
 
 # إعادة حساب عدد التوكنات
 current_tokens = sum(self._count_tokens(msg["content"]) for msg in self.conversation_history)
 
 def get_context(self):
 """إرجاع السياق الحالي للنموذج"""
 return self.conversation_history

# مثال على الاستخدام
context_manager = ContextManager(max_tokens=1500)
context_manager.add_message("user", "مرحباً، أريد فتح حساب جديد في البنك")
context_manager.add_message("assistant", "مرحباً! يسعدنا انضمامك إلينا. ما نوع الحساب الذي ترغب في فتحه؟")
context_manager.add_message("user", "حساب توفير، ما هي المستندات المطلوبة؟")
context_manager.add_message("assistant", "تحتاج إلى بطاقة الهوية الوطنية وصورة شخصية حديثة.")
context_manager.add_message("user", "وما هي الفروع القريبة مني في الرياض؟")

# عرض السياق الحالي
for msg in context_manager.get_context():
 print(f"{msg['role']}: {msg['content']}")

هذا الكود يستخدم استراتيجية هجينة لإدارة السياق: عندما تمتلئ النافذة، يقوم بتلخيص أقدم رسالتين ويحذفهما، ثم يضيف الملخص كرسالة نظام جديدة في بداية المحادثة. لاحظ أننا استخدمنا نموذج تلخيص صغير (BART) بدلاً من النموذج الرئيسي لتوفير الوقت والموارد. أيضاً، اخترنا الاحتفاظ برسالتين على الأقل في كل مرة لضمان عدم فقدان السياق تماماً. في التطبيقات الحقيقية، قد تحتاج إلى ضبط حجم النافذة وعدد الرسائل التي تحتفظ بها بناءً على أداء النموذج ونوع المحادثات.


الـ RAG: كيف تجعل البوت يعرف أكثر مما درب عليه؟

حتى أفضل النماذج العربية لديها مشكلة واحدة: فهي لا تعرف شيئاً عن العالم بعد تاريخ تدريبها، ولا تعرف شيئاً عن بياناتك الخاصة. مثلاً، إذا سألت بوتاً مبنياً على نموذج Jais عن أحدث منتجات شركة معينة، سيجيب بشيء عام أو سيختلق إجابة. الحل؟ استخدام تقنية RAG (Retrieval-Augmented Generation) التي تجمع بين قوة النماذج اللغوية وقواعد البيانات الخارجية. الفكرة بسيطة: عندما يسأل المستخدم سؤالاً، نبحث أولاً في قاعدة بياناتنا عن المعلومات ذات الصلة، ثم نمرر هذه المعلومات للنموذج مع السؤال ليجيب بناءً عليها.

في مشروع لشركة اتصالات، استخدمنا RAG لجعل البوت يجيب على أسئلة العملاء عن الباقات والعروض. بدون RAG، كان البوت يعطي معلومات عامة أو قديمة. بعد إضافة RAG، أصبح البوت يجيب بدقة عن العروض الحالية والأسعار، بل ويستطيع مقارنة الباقات بناءً على استهلاك العميل. المفتاح هنا كان في بناء قاعدة بيانات متكاملة تحتوي على جميع المعلومات التي قد يحتاجها العميل، ثم استخدام خوارزمية بحث ذكية لاسترجاع المعلومات الأكثر صلة بالسؤال.

خطوات بناء نظام RAG فعال

  • •جمع البيانات: إنشاء قاعدة بيانات تحتوي على المعلومات التي تريد للبوت معرفتها
  • •الـ Indexing: تحويل البيانات إلى شكل يمكن البحث فيه بسرعة (مثل استخدام مكتبات مثل FAISS أو Elasticsearch)
  • •الـ Embedding: تحويل النصوص إلى متجهات رقمية باستخدام نماذج مثل sentence-transformers
  • •الـ Retrieval: البحث عن المعلومات الأكثر صلة بالسؤال باستخدام خوارزميات مثل cosine similarity
  • •الـ Generation: تمرير المعلومات المسترجعة مع السؤال للنموذج ليجيب بناءً عليها

كود كامل لبناء نظام RAG بسيط باستخدام FAISS وsentence-transformers

python
from sentence_transformers import SentenceTransformer
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.docstore.document import Document
import numpy as np

# الخطوة 1: تحميل نموذج Embedding
embedding_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

# الخطوة 2: تحضير البيانات (مثال على بيانات وهمية)
documents = [
 "باقة الإنترنت المنزلية توفر سرعة 100 ميجابت بسعر 150 ريال شهرياً",
 "باقة الإنترنت المحمول توفر 50 جيجا بايت بسعر 80 ريال شهرياً",
 "خدمة العملاء متاحة على الرقم 920000000 طوال الأسبوع",
 "يمكنك دفع الفواتير عبر تطبيق الشركة أو موقعنا الإلكتروني",
 "العروض الحالية تشمل خصم 20% على الباقات السنوية"
]

# الخطوة 3: تقسيم النصوص إلى أجزاء أصغر
text_splitter = RecursiveCharacterTextSplitter(
 chunk_size=200,
 chunk_overlap=50
)
docs = text_splitter.create_documents(documents)

# الخطوة 4: إنشاء متجهات Embedding للفقرات
embeddings = embedding_model.encode([doc.page_content for doc in docs])

# الخطوة 5: بناء قاعدة بيانات FAISS
vector_db = FAISS.from_documents(docs, embedding_model)

# دالة للبحث عن المعلومات ذات الصلة
def retrieve_relevant_info(query, k=2):
 query_embedding = embedding_model.encode([query])
 results = vector_db.similarity_search_by_vector(query_embedding[0], k=k)
 return "\n".join([doc.page_content for doc in results])

# مثال على الاستخدام
user_query = "ما هي باقات الإنترنت المتاحة حالياً؟"
relevant_info = retrieve_relevant_info(user_query)
print(f"المعلومات ذات الصلة:\n{relevant_info}")

# دمج المعلومات مع السؤال وإرسالها للنموذج
prompt = f"استناداً إلى المعلومات التالية:\n{relevant_info}\n\nأجب عن السؤال: {user_query}"
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=100)
print("\nإجابة البوت:")
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

هذا الكود يبني نظام RAG بسيط ولكنه فعال. لاحظ أننا استخدمنا نموذج Embedding متعدد اللغات (paraphrase-multilingual-MiniLM-L12-v2) لأنه يدعم العربية بشكل جيد. أيضاً، استخدمنا مكتبة FAISS من فيسبوك لبناء قاعدة البيانات المتجهية لأنها سريعة وفعالة في البحث عن المتشابهات. في التطبيقات الحقيقية، قد تحتاج إلى استخدام قاعدة بيانات أكبر مثل Elasticsearch إذا كانت بياناتك ضخمة، أو استخدام تقنيات أكثر تقدماً مثل Hierarchical Indexing لتحسين أداء البحث.


الـ Deployment: من الكود المحلي إلى الإنتاج

بعد بناء البوت واختباره محلياً، تأتي الخطوة الأصعب: نشره في بيئة إنتاجية. هنا تبدأ المشاكل الحقيقية: كيف تجعل البوت يستجيب بسرعة؟ كيف تضمن أنه لن ينهار تحت ضغط آلاف المستخدمين؟ كيف تحمي البيانات الحساسة؟ في تجربتي، معظم المشاريع تفشل في هذه المرحلة ليس بسبب ضعف النموذج، بل بسبب مشاكل في البنية التحتية. مثلاً، في مشروع لشركة تأمين، كان البوت يعمل بشكل مثالي على جهاز التطوير، لكنه كان يستغرق 15 ثانية للرد في الإنتاج بسبب عدم تحسين الـ GPU وازدحام السيرفر.

الحل؟ استخدام بنية تحتية مصممة خصيصاً لتطبيقات الـ LLM. بدلاً من تشغيل النموذج على سيرفر واحد، استخدمنا بنية موزعة مع تحميل موازن Load Balancer. أيضاً، استخدمنا تقنيات مثل Model Quantization لتقليل حجم النموذج وزيادة سرعة الاستجابة. بالنسبة للبيانات الحساسة، استخدمنا نظاماً لفصل البيانات الشخصية عن بقية المحادثة، بحيث لا تمرر أبداً معلومات مثل أرقام الهويات أو الحسابات للنموذج نفسه، بل تحل محلها بعلامات خاصة قبل المعالجة.

استراتيجيات لنشر البوت في الإنتاج

  • •الـ Model Quantization: تقليل حجم النموذج باستخدام تقنيات مثل 8-bit quantization
  • •الـ Caching: تخزين الردود الشائعة لتقليل الحمل على النموذج
  • •الـ Rate Limiting: منع إساءة الاستخدام بحصر عدد الطلبات لكل مستخدم
  • •الـ Asynchronous Processing: معالجة الطلبات في الخلفية لتجنب تجميد السيرفر
  • •الـ Fallback Mechanism: استخدام نموذج أصغر أو ردود جاهزة في حالة فشل النموذج الرئيسي
  • •الـ Monitoring: مراقبة أداء البوت في الوقت الحقيقي باستخدام أدوات مثل Prometheus وGrafana

كود لنشر البوت باستخدام FastAPI وDocker

python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
import logging
from contextlib import asynccontextmanager

# تهيئة التطبيق مع إدارة دورة الحياة
@asynccontextmanager
async def lifespan(app: FastAPI):
 # تحميل النموذج عند بدء التطبيق
 global model, tokenizer
 model_name = "core42/jais-13b-chat"
 tokenizer = AutoTokenizer.from_pretrained(model_name)
 model = AutoModelForCausalLM.from_pretrained(
 model_name,
 torch_dtype=torch.bfloat16,
 device_map="auto",
 load_in_8bit=True # Quantization لتقليل حجم النموذج
 )
 logging.info("تم تحميل النموذج بنجاح")
 yield
 # تنظيف الموارد عند إيقاف التطبيق
 del model
 del tokenizer
 torch.cuda.empty_cache()
 logging.info("تم تفريغ الذاكرة")

app = FastAPI(lifespan=lifespan)

class ChatRequest(BaseModel):
 message: str
 user_id: str

# نظام تخزين مؤقت للردود الشائعة
cache = {}

@app.post("/chat")
async def chat(request: ChatRequest):
 try:
 # التحقق من وجود الرد في التخزين المؤقت
 cache_key = request.message.lower()
 if cache_key in cache:
 return {"response": cache[cache_key]}
 
 # معالجة الرسالة
 inputs = tokenizer(request.message, return_tensors="pt").to("cuda")
 outputs = model.generate(**inputs, max_new_tokens=100)
 resp tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 # تخزين الرد في التخزين المؤقت
 cache[cache_key] = response
 
 return {"response": response}
 except Exception as e:
 logging.error(f"خطأ في معالجة الرسالة: {str(e)}")
 raise HTTPException(status_code=500, detail="حدث خطأ أثناء معالجة رسالتك")

# Dockerfile للنشر
# FROM nvidia/cuda:12.1.1-base-ubuntu22.04
# 
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install -r requirements.txt
# COPY . .
# 
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

هذا الكود يستخدم FastAPI لبناء واجهة برمجة تطبيقات بسيطة للبوت، مع إدارة دورة حياة النموذج باستخدام lifespan لضمان تحميل النموذج مرة واحدة فقط عند بدء التطبيق. لاحظ أننا استخدمنا Quantization لتقليل حجم النموذج باستخدام load_in_8bit، مما يقلل استخدام الذاكرة ويزيد سرعة الاستجابة. أيضاً، أضفنا نظام تخزين مؤقت بسيط للردود الشائعة لتقليل الحمل على النموذج. في الإنتاج، قد تحتاج إلى استبدال هذا بنظام تخزين مؤقت أكثر قوة مثل Redis، وإضافة آليات مثل Rate Limiting لحماية السيرفر من الهجمات.


خلاصة المهندس: نصائح لن تبوح بها لك الدروس العادية

بعد بناء أكثر من عشرة بوتات عربية في بيئات إنتاجية، هذه هي النصائح الذهبية التي أتمنى لو عرفتها قبل أن أبدأ: أولاً، لا تثق أبداً في أن النموذج سيعمل كما تتوقع — اختبر كل سيناريو محتمل، خاصة الأسئلة الغامضة أو التي تحتوي على أخطاء إملائية. ثانياً، الـ Context Window هو عدوك الأكبر — استثمر وقتاً في بناء نظام إدارة سياق ذكي، لأنه سيوفر عليك ساعات من تصحيح الأخطاء لاحقاً. ثالثاً، معالجة النصوص العربية ليست ترفاً — هي ضرورة، وكل دقيقة تقضيها في تحسين الـ Preprocessing ستوفر عليك ساعات من تصحيح الردود الغريبة. رابعاً، لا تبني كل شيء من الصفر — استخدم مكتبات مثل LangChain وLlamaIndex لتسريع التطوير، لكن افهم كيف تعمل خلف الكواليس لتتمكن من تصحيح الأخطاء. وأخيراً، لا تنسَ مراقبة البوت بعد النشر — النماذج تتدهور بمرور الوقت بسبب تغير لغة المستخدمين، فكن مستعداً لتحديثها باستمرار.

الخطوة التالية؟ ابدأ ببناء بوتك الأول باستخدام هذا الدليل، لكن لا تتوقف عند الكود الذي كتبته هنا. جرب تعديل المعلمات، جرب نماذج مختلفة، جرب استراتيجيات جديدة لإدارة السياق. الذكاء الاصطناعي مجال سريع التغير، والطريقة الوحيدة للبقاء في المقدمة هي التجربة المستمرة والتعلم من الأخطاء. وإذا واجهتك مشكلة، تذكر: كل مشكلة واجهتها هي فرصة لتعلم شيء جديد. الآن، افتح محرر الكود وابدأ البناء!

شات بوت عربي LLM معالجة اللغة العربية RAG الذكاء الاصطناعي التوليدي

التعليقات

العودة للمقالات
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر