الدرس 9 من 23
تصميم نظام RAG

نظرة عامة على هندسة RAG

4 دقيقة للقراءة

التوليد المعزز بالاسترجاع (RAG) هو النمط الأكثر شيوعاً في أنظمة الذكاء الاصطناعي الإنتاجية. يرسّخ استجابات LLM في بياناتك، مما يقلل الهلوسات ويمكّن الإجابات الخاصة بالمجال.

لماذا RAG؟

المشكلةكيف يحلها RAG
هلوسات LLMترسيخ الاستجابات في حقائق مسترجعة
المعرفة القديمةاستخدام بيانات حالية من مصادرك
الاستجابات العامةتوفير سياق خاص بالمجال
حدود الرموزاسترجاع المعلومات ذات الصلة فقط

هندسة خط أنابيب RAG

┌─────────────────────────────────────────────────────────────────┐
│                       خط أنابيب RAG                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────── مرحلة الفهرسة ──────────────────────┐   │
│  │                                                          │   │
│  │   المستندات ──▶ التقسيم ──▶ التضمين ──▶ قاعدة المتجهات  │   │
│  │                                                          │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                  │
│  ┌──────────────────── مرحلة الاستعلام ─────────────────────┐   │
│  │                                                          │   │
│  │   الاستعلام ──▶ التضمين ──▶ الاسترجاع ──▶ إعادة الترتيب  │   │
│  │                              │                           │   │
│  │                              ▼                           │   │
│  │                    أفضل K مستند                          │   │
│  │                              │                           │   │
│  │                              ▼                           │   │
│  │   ┌─────────────────────────────────────────────────┐   │   │
│  │   │     السياق + الاستعلام ──▶ LLM ──▶ الاستجابة    │   │   │
│  │   └─────────────────────────────────────────────────┘   │   │
│  │                                                          │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

المرحلة 1: فهرسة المستندات

استراتيجيات التقسيم

class ChunkingStrategy:
    """نهج مختلفة لتقسيم المستندات."""

    @staticmethod
    def fixed_size(text: str, chunk_size: int = 500, overlap: int = 50) -> list:
        """قطع بحجم ثابت بسيطة مع تداخل."""
        chunks = []
        start = 0
        while start < len(text):
            end = start + chunk_size
            chunks.append(text[start:end])
            start = end - overlap
        return chunks

    @staticmethod
    def semantic(text: str, max_tokens: int = 500) -> list:
        """التقسيم على حدود دلالية (فقرات، أقسام)."""
        # التقسيم على أسطر جديدة مزدوجة (فقرات)
        paragraphs = text.split("\n\n")

        chunks = []
        current_chunk = []
        current_tokens = 0

        for para in paragraphs:
            para_tokens = len(para) // 4  # تقدير تقريبي
            if current_tokens + para_tokens > max_tokens:
                chunks.append("\n\n".join(current_chunk))
                current_chunk = [para]
                current_tokens = para_tokens
            else:
                current_chunk.append(para)
                current_tokens += para_tokens

        if current_chunk:
            chunks.append("\n\n".join(current_chunk))

        return chunks

مقايضات حجم القطعة

حجم القطعةالإيجابياتالسلبيات
صغير (100-200 رمز)استرجاع دقيققد يفقد السياق
متوسط (300-500 رمز)متوازنخيار افتراضي جيد
كبير (500-1000 رمز)سياق كاملقد يتضمن معلومات غير ذات صلة

توليد التضمينات

from openai import OpenAI

class EmbeddingPipeline:
    def __init__(self, model: str = "text-embedding-3-small"):
        self.client = OpenAI()
        self.model = model

    async def embed_chunks(self, chunks: list) -> list:
        """تضمين قطع متعددة بكفاءة."""
        # تضمين دفعات للكفاءة
        response = self.client.embeddings.create(
            model=self.model,
            input=chunks
        )
        return [item.embedding for item in response.data]

    async def embed_query(self, query: str) -> list:
        """تضمين استعلام واحد."""
        response = self.client.embeddings.create(
            model=self.model,
            input=query
        )
        return response.data[0].embedding

المرحلة 2: معالجة الاستعلام

تدفق الاسترجاع

class RAGPipeline:
    def __init__(self, vector_store, llm, embedding_model):
        self.vector_store = vector_store
        self.llm = llm
        self.embedder = embedding_model

    async def query(self, user_query: str, top_k: int = 5) -> dict:
        # الخطوة 1: تضمين الاستعلام
        query_embedding = await self.embedder.embed_query(user_query)

        # الخطوة 2: استرجاع المستندات المتشابهة
        results = await self.vector_store.search(
            embedding=query_embedding,
            top_k=top_k
        )

        # الخطوة 3: بناء السياق
        context = "\n\n---\n\n".join([
            f"المصدر: {r.metadata.get('source', 'غير معروف')}\n{r.content}"
            for r in results
        ])

        # الخطوة 4: توليد الاستجابة
        prompt = f"""أجب بناءً على السياق المقدم فقط.
إذا لم تكن الإجابة في السياق، قل "ليس لدي معلومات عن ذلك."

السياق:
{context}

السؤال: {user_query}

الإجابة:"""

        response = await self.llm.complete(prompt)

        return {
            "answer": response,
            "sources": [r.metadata for r in results],
            "context_used": context
        }

المقاييس الرئيسية لأنظمة RAG

المقياسما يقيسهالهدف
دقة الاسترجاع% المستندات المسترجعة ذات الصلة> 80%
استدعاء الاسترجاع% المستندات ذات الصلة التي تم استرجاعها> 70%
دقة الإجابةصحة الاستجابة النهائية> 90%
زمن الاستجابةالوقت من الاستعلام إلى الاستجابة< 3 ثوانٍ
الإخلاصالإجابة مرتكزة على المستندات المسترجعة> 95%

بعد ذلك، سنتعمق في اختيار قاعدة البيانات المتجهة والمقايضات. :::

مراجعة سريعة: كيف تجد هذا الدرس؟

اختبار

الوحدة 3: تصميم نظام RAG

خذ الاختبار