مقدمة
إذا كنت كتطوّر شات بوت أو محرك بحث داخلي وكتحتاج يجاوب بدقة على وثائقك الخاصة وبالعربية، فحل RAG (Retrieval-Augmented Generation) هو الأنسب. الفكرة بسيطة: كنسترجعو مقاطع من المعرفة ديالنا (PDFs، مقالات، قواعد معرفة…) وكنمدّوها للنموذج اللغوي باش يجاوب بالاعتماد عليها، وبهذا كنقللو الهلاوس ونحصلو على إجابات موثوقة.
في هاد المقال التطبيقي، غنشوفو شنو هو RAG، كيفاش نخزنو المعرفة باستخدام FAISS، ونبنو بايبلاين بسيط بLangChain يدعم العربية، مع نصائح عملية للتكلفة، التقييم، وتحسين الجودة.
شنو هو RAG؟
RAG = استرجاع المعرفة + توليد الإجابة.
- الاسترجاع: كتقسّم المعرفة إلى مقاطع (chunks) وتولد لها تمثيلات عددية (embeddings)، ومن بعد كتبحث على أقرب المقاطع للسؤال.
- التوليد: كتزوّد LLM بالسؤال + المقاطع المسترجعة، وهو كينتج جوابًا مدعومًا بالمصادر.
الفائدة:
- تقليل الهلاوس بشكل كبير
- التحكم في نطاق المعرفة (خصوصية وأمان)
- قابلية التحديث بمجرد إضافة وثائق جديدة
المعمارية في لمحة
- تقسيم الوثائق إلى مقاطع صغيرة (300–800 حرف/توكن)
- إنشاء Embeddings (مراعاة دعم العربية)
- تخزين向 فهرسة شعاعية (FAISS/Chroma)
- استرجاع Top-K مقاطع ذات صلة
- تمرير السياق + السؤال للـ LLM
- توليد جواب مبرر بمصادره
اختيار الأدوات العربية
- Embeddings تدعم العربية: ممكن تستخدم “text-embedding-3-large” من OpenAI أو “bge-m3”/“bge-base-ar” مفتوحة المصدر.
- نماذج توليد تدعم العربية: GPT-4o/4.1، Claude 3.5، أو نماذج مفتوحة مثل Qwen2.5، Jais.
- مخزن向 المتجهات: FAISS سريع وخفيف، أو Chroma لو بغيت ميزات إضافية.
مشروع عملي صغير ببايثون
باش نجربو بسرعة، غنستخدمو LangChain + FAISS + OpenAI Embeddings. تقدر تبدل OpenAI ببدائل مفتوحة.
المتطلبات
pip install langchain faiss-cpu openai tiktoken pypdf
ضبط المتغيرات:
export OPENAI_API_KEY=sk-...
إعداد بيانات بسيطة
# text: مثال توثيق داخلي
DOCS = [
"""
سياسة الشركة: ساعات العمل من 9 صباحاً حتى 5 مساءً بتوقيت الدار البيضاء.
يمكن للموظفين العمل عن بُعد يومي الإثنين والخميس.
""",
"""
دليل التقنية: يُنصح باستخدام PostgreSQL 15 للتطبيقات الإنتاجية.
عند استخدام Redis، فعّل خاصية persistence عبر AOF.
""",
]
بناء الفهرس باستخدام FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
# 1) تقسيم المقاطع (مهم للدقة، خصوصاً بالعربية)
splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=80)
chunks = []
for doc in DOCS:
chunks.extend(splitter.split_text(doc))
# 2) Embeddings تدعم العربية
emb = OpenAIEmbeddings(model="text-embedding-3-large")
# 3) بناء فهرس متجهي
vs = FAISS.from_texts(chunks, embedding=emb)
بايبلاين الاسترجاع + التوليد
from langchain.chat_models import ChatOpenAI
from langchain.schema.runnable import RunnablePassthrough
from langchain.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)
retriever = vs.as_retriever(search_kwargs={"k": 4})
PROMPT = ChatPromptTemplate.from_template(
"""
أنت مساعد عربي خبير. أجب عن السؤال بدقة وبالاعتماد على السياق المعطى.
إذا كانت المعلومات غير كافية، قل ذلك بصراحة.
السياق:
{context}
السؤال: {question}
"""
)
def format_docs(docs):
return "\n\n".join(d.page_content if hasattr(d, 'page_content') else d for d in docs)
rag_chain = {
"context": retriever | format_docs,
"question": RunnablePassthrough(),
} | PROMPT | llm
answer = rag_chain.invoke("شحال هي ساعات العمل الرسمية؟ واش كاين ريموت؟")
print(answer.content)
إظهار المصادر
from langchain.schema import StrOutputParser
rag_with_sources = (
{
"docs": retriever,
"question": RunnablePassthrough(),
}
| (lambda x: {"context": format_docs(x["docs"]), "question": x["question"], "sources": x["docs"]})
| PROMPT
| llm
)
res = rag_with_sources.invoke("شنو ننصح نستخدم لقاعدة البيانات فالإنتاج؟")
print(res.content)
# لاحقاً: اطبع روابط/معرفات المقاطع لو وثّقت كل chunk بmetadata
أفضل الممارسات لجودة أعلى
- تقسيم ذكي: جرب chunk_size 400–800 وoverlap 50–120 حسب نوع النص.
- التطبيع للعربية: وحّد التشكيل، الأرقام (هندية/عربية)، المسافات، وإزالة الرموز غير المهمة.
- التقييم: استخدم أسئلة واقعية من المستخدمين وقارن الإجابات بمراجع داخلية.
- منع الهلاوس: ألزم الموديل يجاوب فقط من السياق عبر تعليمات واضحة وtemperature منخفض.
- الخصوصية: خزن المتجهات محلياً وابتعد عن إرسال البيانات الحساسة لمزودات خارجية.
- التكلفة: خفّض k، واستخدم موديلات أصغر وقت التطوير، وفعّل caching للـ embeddings.
توسيع الفكرة
- دعم PDF/HTML: استعمل pypdf وBeautifulSoup لاستخراج النصوص.
- إعادة الترتيب (Reranking): استعمل bge-reranker-v2 لتحسين نتائج الاسترجاع.
- Multi-Query: توليد صيغ متعددة للسؤال لتحسين التغطية.
- Graph RAG: مثالي للمعرفة العلائقية المعقدة.
- فهرسة دورية: Job ليحدّث الفهرس مع كل وثائق جديدة.
خاتمة
بناء RAG عربي اليوم أسهل من أي وقت مضى. جرّب البنية أعلاه، وابدأ بوثائق صغيرة، وقيّم النتائج، ومن بعد وسّع تدريجياً. إذا أعجبك الموضوع وبغيتي مقالات أكثر حول Agentic RAG أو توصيله مع تطبيقات الويب (FastAPI/Next.js) قولي لينا فالتعليقات وشكون المجالات اللي مهتم بها.