يا جماعة الخير، السلام عليكم ورحمة الله وبركاته، معكم أخوكم أبو عمر.
قبل فترة، كنت شغال على مشروع حساس شوي لأحد العملاء. الفكرة كانت ببساطة بناء مساعد ذكي (Chatbot) قادر يجاوب على أسئلة المستخدمين بخصوص قاعدة بيانات ضخمة من الوثائق القانونية الداخلية للشركة. طبعاً، أول ما خطر ببالي هو استخدام أحد النماذج اللغوية الكبيرة (LLM) المشهورة، وتدريبه أو تلقينه المعلومات اللازمة.
الأيام الأولى كانت وردية. النموذج كان فاهم عليّ، ويجاوب على الأسئلة العامة بشكل مبهر. لكن الكارثة بدأت لما دخلنا في التفاصيل الدقيقة. سألته عن مادة معينة في قانون العمل لسنة 2017، والنموذج بكل ثقة “أفتى” لي بمادة قانونية كاملة، برقمها وتفاصيلها… المشكلة؟ هالمادة ما إلها أي وجود في الواقع! كانت من نسج خيال النموذج. قعدت صافن في الشاشة وأنا بحكي لحالي: “شو هالحكي؟ من وين جاب هالكلام؟”.
هون بلش الكابوس. النموذج كان “يهلوس” (Hallucinating) بشكل مستمر. يخلط معلومات صحيحة بمعلومات مخترعة، ويقدمها بثقة عمياء تخلي الواحد يشك في حاله. قضيت ليالي وأنا أحاول أعمل Fine-tuning وأغير في الـ Prompts، لكن الهلوسة كانت زي العفريت، كل ما أسد باب تطلعلي من شباك. حسيت المشروع كله رح ينهار، وسمعتي كمطور صارت على المحك. لحد ما في ليلة من الليالي، وأنا ببحث بيأس، وقعت عيني على مصطلح غيّر كل شي: Retrieval-Augmented Generation (RAG).
ما هي “هلوسة” النماذج اللغوية؟ ولماذا تحدث؟
قبل ما نغوص في الحل، خلينا نفهم المشكلة بالزبط. الهلوسة في عالم الذكاء الاصطناعي هي لما النموذج اللغوي يولد معلومات تبدو منطقية ومقنعة، لكنها في الحقيقة خاطئة تماماً أو لا تستند إلى أي بيانات واقعية من بيانات التدريب الخاصة به.
تخيل النموذج كطالب ذكي جداً لكنه متوتر في امتحان. هو تدرب على مليارات النصوص من الإنترنت، وصار عنده قدرة رهيبة على التنبؤ بالكلمة التالية في أي جملة. لما تسأله سؤال ما بيعرف إجابته الدقيقة من ذاكرته (بيانات تدريبه)، بدل ما يحكي “لا أعرف”، بيحاول “يألف” إجابة تبدو الأكثر احتمالاً من الناحية اللغوية. هو لا يكذب عن قصد، بل هو مجرد آلة احتمالات بتحاول تكمل الفراغ بأفضل شكل ممكن بناءً على ما تعلمته. وهذه هي المصيبة في التطبيقات اللي بتحتاج دقة 100% زي التطبيقات القانونية أو الطبية.
طوق النجاة: التوليد المعزز بالاسترجاع (RAG)
الـ RAG هو مش نموذج جديد، بل هو “هندسة” أو “طريقة” ذكية جداً للجمع بين قوة النماذج اللغوية الكبيرة في الفهم والتوليد، وقوة محركات البحث التقليدية في استرجاع المعلومات الدقيقة.
شو قصة الـ RAG؟ كيف بيشتغل؟
الفكرة عبقرية في بساطتها. بدل ما نعتمد على “ذاكرة” النموذج المحدودة والمُدرّبة مسبقاً، بنعطيه “كتاب مفتوح” (Open Book) وقت الإجابة. هالكتاب هو قاعدة بياناتك الخاصة (وثائقك، ملفاتك، موقعك الإلكتروني، أي شي بدك ياه).
العملية بتمر بمراحل واضحة:
- الاسترجاع (Retrieval): لما المستخدم يسأل سؤال، النظام ما بروح للنموذج اللغوي مباشرة. أولاً، بياخذ السؤال وببحث في قاعدة بياناتك الخاصة (الكتاب المفتوح) عن أكثر أجزاء النص صلة بالسؤال. هذه العملية تشبه لما تبحث في جوجل عن معلومة.
- التعزيز (Augmentation): بعد ما يلاقي الأجزاء ذات الصلة (مثلاً، فقرتين من وثيقة PDF)، بيقوم “بتعزيز” السؤال الأصلي. يعني بيجهز prompt جديد للنموذج اللغوي، شكله كالتالي:
“يا نموذج يا محترم، بالاعتماد على السياق التالي فقط، أجب عن سؤال المستخدم.
السياق: [هنا نضع الفقرات اللي تم استرجاعها]
سؤال المستخدم: [هنا نضع السؤال الأصلي]”
- التوليد (Generation): الآن، النموذج اللغوي يستقبل هذا الـ prompt المعزز. مهمته صارت أسهل بكثير وأكثر أماناً. بدل ما يجاوب من ذاكرته الواسعة اللي ممكن تكون خاطئة، هو الآن مجبر يجاوب بالاعتماد على السياق الدقيق والمحدّث اللي أعطيناه إياه. هيك، بنكون قضينا على الهلوسة من جذورها لأنه صار مربوط بمصدر موثوق.
خلونا نوسّخ إيدينا: مثال عملي بسيط باستخدام Python
الحكي النظري حلو، بس خلينا نشوف كيف هالكلام بترجم لكود حقيقي. رح نستخدم مكتبة LangChain المشهورة في هذا المجال لأنها بتبسط العملية جداً.
الأدوات اللي رح نحتاجها
- مكتبة
langchainللربط بين المكونات. - مكتبة للتعامل مع نماذج اللغة مثل
langchain-openai. - مكتبة لإنشاء قاعدة بيانات فيكتور (Vector Store) مثل
faiss-cpu. - مكتبة لقراءة الملفات مثل
pypdf.
الكود خطوة بخطوة
لنفترض أن لدينا ملف PDF اسمه "my_document.pdf" ونريد أن نجعل النموذج يجيب على أسئلة منه.
# أولاً، نقوم بتثبيت المكتبات اللازمة
# pip install langchain langchain-openai faiss-cpu pypdf
import os
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
# ضع مفتاح OpenAI الخاص بك هنا
os.environ["OPENAI_API_KEY"] = "sk-..."
# --- الخطوة 1: تحميل وتقسيم الوثائق ---
# سنقوم بتحميل ملف الـ PDF
loader = PyPDFLoader("my_document.pdf")
documents = loader.load()
# النماذج اللغوية لها حد معين من الكلمات (context window)
# لذلك يجب تقسيم النص الطويل إلى أجزاء صغيرة (chunks)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
texts = text_splitter.split_documents(documents)
print(f"تم تقسيم الوثيقة إلى {len(texts)} جزء.")
# --- الخطوة 2: إنشاء Embeddings وتخزينها في Vector Store ---
# الـ Embeddings هي تحويل النصوص إلى أرقام (فيكتور) ليفهمها الكمبيوتر
# الـ Vector Store هي قاعدة بيانات متخصصة في البحث عن هذه الفيكتورات المتشابهة
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(texts, embeddings)
print("تم إنشاء قاعدة البيانات الفيكتورية بنجاح.")
# --- الخطوة 3: إعداد سلسلة RAG ---
# هنا نربط كل شيء معًا
# llm: النموذج اللغوي الذي سيقوم بتوليد الإجابة النهائية
# chain_type="stuff": الطريقة التي سنجمع بها النصوص مع السؤال (مناسبة للنصوص الصغيرة)
# retriever: هو المسؤول عن البحث في قاعدة البيانات الفيكتورية
qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0),
chain_type="stuff",
retriever=vectorstore.as_retriever()
)
# --- الخطوة 4: طرح الأسئلة ---
query = "ما هي أهم النقاط المذكورة في الفصل الثالث من الوثيقة؟"
result = qa_chain.invoke({"query": query})
print("n--- السؤال ---")
print(query)
print("n--- الإجابة ---")
print(result['result'])
بهذه البساطة، يا جماعة! الكود أعلاه يبني نظام RAG كامل. الآن، بدل ما النموذج “يهلوس”، هو مجبر يبحث في my_document.pdf ويستخرج الإجابة منه مباشرة. صار مساعد ذكي موثوق بدلاً من كونه “مُفتي” لا يعتمد عليه.
نصائح من أخوكم أبو عمر (من أرض المعركة)
بعد ما اشتغلت على أكثر من مشروع باستخدام RAG، جمعتلكم شوية نصائح عملية ممكن توفر عليكم وقت وجهد كبير:
- اهتم بتقسيم النصوص (Chunking): طريقة تقسيمك للوثائق لأجزاء صغيرة تؤثر بشكل مباشر على جودة البحث. لا تقسم الكلمات في منتصف الجملة. استخدم
RecursiveCharacterTextSplitterلأنه ذكي ويحاول الحفاظ على بنية الفقرات. - جودة الـ Retriever هي كل شيء: إذا كانت نتائج البحث الأولية (الاسترجاع) سيئة، فالإجابة النهائية ستكون سيئة حتماً. جرب تغيير عدد النتائج المسترجعة (parameter اسمه
k) وشوف كيف تتأثر الجودة. - الـ Prompt هو الملك: الـ prompt اللي بتعطيه للنموذج في مرحلة التوليد مهم جداً. كن واضحاً في تعليماتك. جملة مثل “أجب بالاعتماد على السياق فقط. إذا كانت الإجابة غير موجودة في السياق، قل بوضوح ‘لا أملك معلومات كافية للإجابة’.” يمكن أن تصنع فرقاً هائلاً.
- لا تهمل الـ Metadata: عند تقسيم الوثائق، يمكنك إضافة بيانات وصفية (metadata) لكل جزء، مثل رقم الصفحة أو اسم الملف. هذا يساعدك لاحقاً على ذكر المصدر في الإجابة، مما يزيد من ثقة المستخدم.
- فكر في Hybrid Search: أحياناً البحث عن طريق الكلمات المفتاحية (keyword search) التقليدي يكون أفضل من البحث الدلالي (vector search) للأسماء والمصطلحات الدقيقة. الجمع بين الاثنين (Hybrid Search) يعطي نتائج خارقة في كثير من الأحيان.
الخلاصة: من الهلوسة إلى الثقة 😌
في النهاية، تقنية RAG ليست عصا سحرية، بل هي نمط هندسي قوي وفعال يحل واحدة من أكبر مشاكل النماذج اللغوية الكبيرة: الثقة والدقة. هي الجسر الذي يربط بين القدرة الإبداعية الهائلة لهذه النماذج وبين أرض الواقع الصلبة المتمثلة في بياناتنا ووثائقنا الخاصة.
بالنسبة لي، كانت RAG هي المنقذ الذي حول مشروع على حافة الفشل إلى قصة نجاح، وحول علاقتي بالنماذج اللغوية من علاقة شك وحذر إلى علاقة ثقة وتعاون. إذا كنت تعمل مع نماذج لغوية وتحتاج إلى إجابات دقيقة وموثوقة من مصادر بياناتك الخاصة، فصدقني، الـ RAG هو صديقك الذي تبحث عنه.
لا تخافوا من التجربة، وسّخوا إيديكم بالكود، واكتشفوا القوة بأنفسكم. بالتوفيق يا أبطال! 👨💻