T3 · Advanced · 13 دقيقةبيتحدّث · آخر مراجعة: 2026-08-18مسودة أولى — بنراجعها

الـ Retrievers المتقدمة — لما البحث البسيط ميكفيش

في سطر واحد · **الـ Top-k البسيط بيفشل بطرق معروفة بالاسم — وكل طريقة فشل ليها Pattern بيصلّحها: Multi-Query لاختلاف الألفاظ، Self-Query لأسئلة الشروط والتواريخ، و Parent-Document للـ Chunks اللي أصغر من الإجابة.** <!-- Field 3: TL;DR -->

القاموس:HNSWHybrid SearchMulti-Query RetrievalParent Document RetrievalRerankingSelf-Query Retrieval
الخلاصة
  • الاسترجاع البسيط — اعمل Embedding للسؤال وهات أقرب k نتايج — كافي لأغلب الأنظمة في أولها. متبدأش من هنا وأنت قلقان.
  • لكنه بيفشل بأنماط محددة ومتكررة: سؤال بألفاظ مختلفة عن ألفاظ المستندات، سؤال فيه شرط زي «تقارير 2024»، Chunk صح بس أصغر من إن الإجابة تكمل منه، وسؤال واحد محتاج أكتر من زاوية.
  • التلات Patterns في الصفحة دي بيصلّحوا الأنماط دي واحد واحد — وكل واحد ليه تمن: نداءات LLM إضافية، Latency أعلى، وفاتورة أكبر.
  • القاعدة الذهبية: شخّص الفشل الأول، بعدين ركّب الـ Pattern اللي بيصلّحه بالظبط. مش العكس.
  • وإزاي تعرف إنه اشتغل؟ قياس قبل/بعد على Golden Set — مش «حاسس إنه أحسن».

<!-- Field 4: Why does this matter? -->

ليه ده مهم؟

السيناريو ده بيحصل لكل حد بنى RAG تقريبًا: خلصت الـ Pipeline، جربت على أسئلتك أنت، النتايج ممتازة. نشرت النظام. أول أسبوع مع مستخدمين حقيقيين — الشكاوى بدأت: «سألته سؤال والإجابة ملهاش علاقة».

فتحت الـ Logs، بصيت على الـ Chunks المسترجعة، ولقيت المفاجأة: الموديل مش هو المشكلة. الاسترجاع هو اللي بيسلّمه معلومات غلط أو ناقصة. ودي أشهر خلاصة في مفهوم Retrieval quality: لو المسترجع زبالة، أشطر موديل هيصيغ الزبالة صياغة مقنعة.

طيب والحل؟ هنا فيه فخ. أول ما بتدوّر «how to improve RAG retrieval» بتقابلك قايمة طويلة من الـ Patterns بأسماء براقة، والإغراء إنك تركّبهم كلهم. الصفحة دي هتديك حاجة أحسن: تشخيص. أنهي فشل عندك فعلًا، وأنهي Pattern بيصلّحه، وبكام.

ولمستوى الانترفيو: «الـ retrieval ضعيف — هتعمل إيه؟» بقى من الأسئلة الثابتة لوظايف الـ AI Engineering. الإجابة اللي بتفرّق مش سرد الـ Patterns — الربط بين العرض والعلاج.

<!-- Field 5: Explain it simply (Layer 1) -->

الاسترجاع البسيط بيعمل حاجة واحدة: بياخد سؤالك زي ما هو، بيحوّله لـ Embedding، وبيجيب أقرب Chunks في المعنى.

المشكلة؟ «زي ما هو» دي. السؤال الحقيقي ساعات بييجي بكلمات مختلفة عن كلمات المستندات، أو فيه شرط البحث الدلالي مش بيفهمه، أو الإجابة أكبر من الـ Chunk اللي اتلقى.

الـ Retrievers المتقدمة كلها فكرة واحدة: حط شوية ذكاء قبل البحث أو بعده. قبل البحث: عدّل السؤال أو ترجمه لشروط. بعد البحث: كبّر النتيجة أو رتّبها أحسن. البحث نفسه — الـ Vector Store — هو هو مبيتغيرش.

<!-- Field 6: Real-world analogy (Layer 2) -->

خلينا نفهمها بمثال

تخيّل أمينين مكتبة:

الأول مبتدئ. بتقوله «عايز حاجة عن فلوس الأجازات» فبيدوّر حرفيًا على كلمة «فلوس الأجازات». الكتاب المطلوب اسمه «احتساب بدل الإجازات السنوية»؟ معلش، مش هيلاقيه. طلبت «مقالات 2024»؟ هيجيبلك أي حاجة «قريبة في المعنى» من غير ما يبص على سنة النشر. ولما يلاقي الصفحة الصح، بيقصها لك قصاصة صغيرة من نصها — من غير باقي الفصل اللي بيكمّل المعنى.

التاني خبير. بياخد طلبك ويعيد صياغته كذا مرة بمترادفات مختلفة قبل ما يدوّر (ده Multi-Query). بيسمع «مقالات 2024» فبيفهم إن «2024» دي فلتر مش كلمة بحث — بيروح لرف السنة دي وبيدوّر جواه (ده Self-Query). ولما يلاقي القصاصة المناسبة، بيجيبلك الفصل كله اللي هي منه (ده Parent-Document).

نفس المكتبة. نفس الكتب. الفرق كله في الذكاء اللي حوالين البحث.

<!-- Field 7: Simple example -->

مثال حقيقي — أربع طرق البحث البسيط بيقع بيها

Knowledge Base بتاع HR فيه سياسات الشركة. شوف الأربع أسئلة دول:

#السؤالاللي بيحصل مع Top-k البسيطنوع الفشل
1«الأجازات بتتحسب إزاي؟»المستند اسمه «احتساب رصيد الإجازات السنوية» بالفصحى الرسمية — التشابه الدلالي بين صيغة السؤال العامية وصيغة المستند أضعف من اللازم، والنتايج بتيجي مش دقيقةاختلاف الألفاظ (Vocabulary Mismatch)
2«هات قرارات الـ HR اللي صدرت في 2024 عن الشغل الـ Remote»البحث الدلالي «حاسس» بموضوع Remote — بس «2024» بالنسبة له مجرد كلمة. بيرجّع قرارات من 2021 بثقةسؤال Metadata
3«إيه إجراءات إنهاء التعاقد كاملة؟»بيلاقي Chunk فيه «الخطوة 3: تسليم العهدة» — صح ١٠٠٪، بس فين باقي الخطوات؟ الـ Chunk أصغر من الإجابةChunk أصغر من الإجابة
4«إيه فرق مزايا الدوام الكامل عن الجزئي؟»سؤال واحد محتاج مستندين مختلفين — والـ Embedding الواحد بتاع السؤال بيقرّب لواحد فيهم بسسؤال محتاج كذا زاوية

خد بالك: في الحالات الأربعة الموديل هيجاوب — بثقة. المشكلة مش في التوليد. المشكلة قبل ما الموديل يشوف أي حاجة أصلًا.

<!-- Field 8: How it works (Layer 3) -->

طيب بتحصل إزاي؟

التلات Patterns بيتدخلوا في نقطتين من الـ Pipeline اللي أنت عارفها:

1. قبل البحث (Query side): بدل ما السؤال يدخل زي ما هو — Multi-Query بيولّد منه كذا صيغة، و Self-Query بيترجمه لـ فلتر منظّم + نص بحث. 2. بعد البحث (Result side): بدل ما النتيجة تتسلم زي ما هي — Parent-Document بيستبدل الـ Chunk الصغير بالسياق الأكبر اللي هو جزء منه.

الـ Vector Store والـ Embeddings والتوليد؟ كلهم زي ما هم. عشان كده الـ Patterns دي بتتركب على أي نظام RAG شغال من غير ما تكسر حاجة.

<!-- Field 9: Step-by-step explanation — the three patterns in detail -->

الـ Patterns التلاتة — واحد واحد

### 1) Multi-Query Retrieval — «اسأل السؤال بكذا طريقة»

  • بيصلّح إيه: اختلاف الألفاظ (فشل #1) والسؤال المتعدد الزوايا (فشل #4).
  • بيشتغل إزاي: قبل البحث، نداء LLM واحد بيولّد 3–4 صيغ بديلة للسؤال بمفردات مختلفة. بتعمل بحث بكل صيغة، وبتدمج النتايج مع إزالة التكرار.
  • مثال مصغّر: «الأجازات بتتحسب إزاي؟» بيتولد منه: «طريقة احتساب رصيد الإجازة السنوية» + «vacation balance calculation policy» + «كام يوم إجازة بيستحقها الموظف؟». الصيغة التانية هي اللي هتضرب على مستند الـ HR الرسمي — والتالتة بتغطي لو المستندات أصلًا بالإنجليزي.
  • 💸 التمن: نداء LLM إضافي (وبالتالي +Latency قبل ما البحث يبدأ أصلًا) + 3–4 عمليات بحث بدل واحدة + Chunks أكتر داخلة الـ Prompt لو مش بتشذّب. الحساب الكامل تحت في قسم التكلفة.

### 2) Self-Query Retrieval — «الموديل يترجم السؤال لفلتر + بحث»

  • بيصلّح إيه: أسئلة الـ Metadata (فشل #2) — «هات مقالات 2024 عن X»، «قرارات قسم كذا»، «تذاكر الـ priority العالي».
  • بيشتغل إزاي: نداء LLM بياخد السؤال + وصف حقول الـ Metadata عندك، وبيطلع حاجتين: فلتر منظّم (year = 2024) + نص بحث دلالي («الشغل الـ Remote»). الفلتر بيتنفذ كـ Metadata Filtering عادي، والبحث الدلالي بيشتغل جوه النتايج المفلترة بس.
  • مثال مصغّر: «هات قرارات الـ HR بتاعة 2024 عن الـ Remote» ← filter: {type: "hr-decision", year: 2024} + query: "سياسة العمل عن بعد". دلوقتي مستحيل ترجع قرارات 2021 — الفلتر قصّهم قبل البحث أصلًا.
  • ⚠️ الشرط المسبق اللي محدش بيقوله: الـ Pattern ده جودته = جودة الـ Metadata بتاعتك. لو المستندات متخزنة من غير year و type نضاف ومتسقين، الموديل هيولّد فلاتر على حقول مش موجودة — والنتيجة صفر نتايج أو زبالة. صمم الـ Metadata وقت الـ Ingestion الأول.
  • 💸 التمن: نداء LLM إضافي لكل سؤال + شغل صيانة على Schema الـ Metadata.

### 3) Parent-Document Retrieval — «دوّر بالصغير، رجّع الكبير»

  • بيصلّح إيه: الـ Chunk الأصغر من الإجابة (فشل #3).
  • بيشتغل إزاي: وقت الـ Ingestion بتقطّع مرتين: Chunks صغيرة (150–300 Token) بتتعملها Embeddings — لأن الصغير أدق في البحث. وكل Chunk صغير بيشاور على Parent أكبر (القسم أو الصفحة، 1,000–1,500 Token) متخزن في Store عادي جنبه. وقت السؤال: البحث بيحصل في الصغير، واللي بيتحط في الـ Prompt هو الـ Parent.
  • مثال مصغّر: البحث بيلقط «الخطوة 3: تسليم العهدة» (دقة عالية لأن الـ Chunk مركّز) — والموديل بياخد قسم «إجراءات إنهاء التعاقد» كامل بخطواته الخمسة. البحث كسب دقة الصغير، والإجابة كسبت اكتمال الكبير.
  • 💸 التمن: مفيش نداءات إضافية — التمن هنا مختلف: تخزين مضاعف (Store تاني للـ Parents) و Context أكبر بكتير داخل للموديل في كل سؤال — يعني Input Tokens أكتر، يعني فلوس. ولو عملت الـ Parents ضخمة أوي، رجعت بنفسك لمشكلة «المعلومة بتتوه في النص».

### طيب و Reranking و Query Rewriting؟

دول قرايبهم اللي أنت قابلتهم قبل كده — ومش هنعيد شرحهم:

  • Reranking بيشتغل على ترتيب النتايج بعد ما رجعت: النتايج موجودة بس الأحسن مش الأول. (مفهوم Reranking & advanced retrieval.)
  • Query Rewriting بيصلّح سؤال ناقص سياق المحادثة: «طيب والمخفضة؟» محتاج يتحول لسؤال كامل قبل البحث. (مفهوم Multi-turn RAG.)

الأربعة بيتكاملوا: Rewriting بيصلّح صياغة السؤال، Multi-Query بيوسّع تغطيته، Self-Query بيترجم شروطه، Parent-Document و Reranking بيحسّنوا اللي راجع.

<!-- Field 10: Visual explanation -->

بالرسم

فين كل Pattern بيتدخل في الـ Pipeline:

                    ┌─────────────────────────────────────────────────┐
User question ────► │  QUERY SIDE — before the search                 │
                    │                                                 │
                    │  Multi-Query : 1 question ──► N phrasings       │
                    │  Self-Query  : question ──► filter + query text │
                    └───────────────────────┬─────────────────────────┘
                                            ▼
                              Vector store search (unchanged)
                                            ▼
                    ┌─────────────────────────────────────────────────┐
                    │  RESULT SIDE — after the search                 │
                    │                                                 │
                    │  Parent-Document : small chunk ──► big parent   │
                    │  Reranking       : re-order results             │
                    │                    (separate concept)           │
                    └───────────────────────┬─────────────────────────┘
                                            ▼
                              Augment + Generate (unchanged)

لاحظ إن الصندوق اللي في النص — البحث نفسه — مكتوب جنبه unchanged. ده جوهر الموضوع: أنت مش بتغيّر البحث، أنت بتحسّن اللي داخل له واللي خارج منه. وعشان كده تقدر تركّب أي Pattern منهم لوحده، النهارده، على النظام اللي عندك.

<!-- Field 11: Technical explanation (Layer 4) -->

لو أنت Developer

أول حاجة تثبتها: الأسماء دي أسماء Patterns مش Features في مكتبة. اتشهرت من التوثيق بتاع الـ Frameworks (LangChain و LlamaIndex بيقدموها جاهزة بنفس الأسماء تقريبًا)، بس كل واحدة فيها فكرة تتكتب في 15–30 سطر كود عادي. لو فاهم الفكرة، تقدر تنفذها بإيدك أو تستخدم الجاهز — وأنت فاهم اللي بيحصل جواه (وده قرار مفهوم «تبني الـ RAG بإيه؟» كامل).

تاني حاجة: التلاتة بيتجمعوا في معادلة واحدة. الاسترجاع البسيط هو:

answer(question) = generate(question, search(embed(question)))

الـ Patterns بيحقنوا دوال في النص:

Multi-Query      : search(embed(q))  ──►  merge(search(embed(v)) for v in variants(q))
Self-Query       : search(embed(q))  ──►  search(embed(text(q)), filter=parse(q))
Parent-Document  : search(...)       ──►  parents(search(...))

تالت حاجة — الترتيب اللي تجرب بيه مش عشوائي. ابدأ بالأرخص تشغيليًا: Parent-Document (مفيش نداءات إضافية وقت السؤال) → Multi-Query (نداء واحد إضافي) → Self-Query (نداء إضافي + استثمار في الـ Metadata). ده لو التشخيص بيسمح — التشخيص أولًا دايمًا.

<!-- Field 13: Code example (D-4 provider-agnostic, CR-4 Arabic surround) -->

على مستوى التشغيل — وإزاي تعرف إنه اشتغل أصلًا

الـ Pattern اتركّب. دلوقتي السؤال الوحيد المهم: حسّن ولا لأ؟ والإجابة عمرها ما تكون «حاسس إنه أحسن» — الإحساس ده هو اللي بيخلي أنظمة تدفع ضعف الفلوس على تحسين وهمي.

الطريقة المنهجية (وهي نفسها فلسفة Evaluating RAG systems):

1. Golden Set صغير: 20–30 سؤال حقيقي — من الـ Logs بتاعتك مش من خيالك — وجنب كل سؤال: الـ Chunks اللي المفروض تترجع (أو على الأقل المستند الصح). 2. قيس الاسترجاع لوحده، قبل التوليد: لكل سؤال — هل الـ Chunk الصح ظهر في النتايج؟ (Hit Rate)، وفي أنهي ترتيب؟ نسبة الملائم وسط اللي رجع (Precision) ونسبة اللي جبته من الملائم الموجود (Recall). 3. خد Baseline بالبحث البسيط. رقم واحد: «Hit Rate = 62%». 4. ركّب Pattern واحد بس. قيس تاني. طلع 81%؟ الـ Pattern كسب مكانه. طلع 64% والتكلفة زادت 60%؟ شيله — بدون ندم. 5. سجّل التكلفة والـ Latency مع كل قياس. التحسين اللي بيدفّعك 3× عشان +2% مش تحسين — قرار خاسر بمقياس واضح.

💡 نصيحة: الخطوة 4 بالذات — واحد واحد. لو ركّبت تلات Patterns مرة واحدة والجودة اتحسنت، مش عارف مين اللي حسّن. ولو باظت، مش عارف مين اللي خرّب. عزل المتغيرات ده مش ترف علمي — ده اللي هيوفرلك أسابيع Debugging.

<!-- Field 16: When to use it (Layer 7a) — the symptom → pattern decision table -->

الكود

ده Multi-Query كامل من غير أي Framework — الفكرة عريانة، بأي Provider وأي Vector Store:

# ---------- MULTI-QUERY RETRIEVAL: the whole pattern, no framework ----------
question = "How are vacation days calculated?"

# 1) One extra LLM call: rephrase the question from different angles
variants_prompt = f"""Rewrite this question in 3 different ways.
Use different vocabulary in each rewrite. One question per line.

Question: {question}"""

variants = llm.generate(variants_prompt).strip().splitlines()
all_queries = [question] + variants              # 4 queries total

# 2) Search with every phrasing (parallelize these in production)
seen_ids, merged = set(), []
for q in all_queries:
    for chunk in vector_store.search(embed(q), top_k=3):
        if chunk.id not in seen_ids:             # 3) de-duplicate
            seen_ids.add(chunk.id)
            merged.append(chunk)

# 4) Cap the final set, then continue like any normal RAG pipeline
top_chunks = merged[:6]
answer = generate_grounded_answer(question, top_chunks)

تلات حاجات خد بالك منهم:

  • السطر `merged[:6]` هو خط الدفاع عن فلوسك. من غيره، 4 استعلامات × 3 نتايج ممكن يدخّلوا 12 Chunk في الـ Prompt — والفاتورة والتشتيت معاهم. الدمج لازم يتبعه تشذيب.
  • إزالة التكرار مش رفاهية. الصيغ المختلفة لنفس السؤال غالبًا هترجّع نفس أقوى الـ Chunks — وده في حد ذاته إشارة جودة: اللي بيظهر في كل الصيغ هو الأملأ للعين.
  • نداء الـ Variants ممكن يكون بموديل أرخص. إعادة صياغة سؤال مش محتاجة أقوى موديل عندك — دي أول فرصة توفير هتقابلك.

<!-- Field 12: Developer perspective (API-level reality) — includes "how to know it worked" per brief, ties to eval philosophy -->

خلينا نبنيها

تمرين (45–60 دقيقة، على مشروعك الحالي):

1. افتح الـ RAG Knowledge Assistant بتاعك واجمع 20 سؤال حقيقي — لو عندك Logs استخدمها، لو لسه، اكتب أسئلة بصياغات مستخدم حقيقي مش بصياغات مستنداتك. 2. لكل سؤال سجّل: المستند اللي المفروض يترجع. مبروك — ده أول Golden Set ليك. 3. قيس الـ Hit Rate بالبحث البسيط. اكتب الرقم. ده الـ Baseline. 4. بص على الأسئلة اللي فشلت وصنّفها بجدول «العرض→العلاج» فوق: كام واحدة Vocabulary Mismatch؟ كام واحدة Metadata؟ كام واحدة Chunk صغير؟ 5. نفّذ Pattern واحد — اللي بيصلّح أكبر فئة فشل عندك — بإيدك زي كود Multi-Query فوق. قيس تاني، وقارن بالرقم المكتوب.

اللي هتتعلمه من الخطوة 4 بالذات — إن أنماط الفشل عندك مش موزعة بالتساوي — هو الدرس الحقيقي في الصفحة دي.

<!-- Field 27: Interview questions -->

أشهر الأخطاء
#❌ الغلط✅ الصح
1تركيب Pattern من غير تشخيص: «قريت عن Multi-Query فركبته»افتح الـ Logs، شوف أنماط الفشل الفعلية، وركّب اللي بيصلّح فشلك أنت — جدول العرض→العلاج فوق
2تركيب كل حاجة مرة واحدة: التلات Patterns في Sprint واحدواحد واحد، وقياس على Golden Set بعد كل واحد — وإلا مش هتعرف مين حسّن ومين خرّب
3Self-Query على Metadata مهملة: الموديل بيولّد year=2024 والحقل أصلًا مش متخزنالـ Metadata Schema بتتصمم وقت الـ Ingestion — قبل ما تفكر في Self-Query أصلًا
4Parents بحجم المستند كله: «خد المستند الـ 40 صفحة كامل يا موديل»الـ Parent = القسم أو الصفحة (1,000–1,500 Token) — كبّرت أكتر رجعت لمشكلة «المعلومة بتتوه» اللي بتحاول تحلها
5دمج نتايج Multi-Query من غير تشذيب: 4 استعلامات × 5 نتايج = 20 Chunk في الـ PromptDedup ثم Cap (6–8 مثلًا) — أو Reranking يختار الأحسن من المجموع
6تلميع فوق أساس بايظ: Patterns فوق Chunking عشوائيلو الاسترجاع بيفشل حتى في الأسئلة المباشرة، المشكلة تحت — صلّح الـ Chunking الأول

<!-- Field 15: Common misconceptions -->

مفاهيم غلط منتشرة

1) «Retriever أعقد = نتايج أحسن» — ❌ أكتر فكرة غلط في الموضوع ده كله. كل Pattern بيصلّح نمط فشل معين — لو النمط ده مش موجود عندك، الـ Pattern بيضيف تكلفة و Latency وساعات Noise (نتايج زيادة بتشتت الموديل) من غير أي مكسب. التعقيد مش ميزة — التعقيد فاتورة. الميزة الوحيدة هي رقم أحسن على الـ Golden Set.

2) «الـ Patterns دي بتاعة LangChain» — ❌ الأسماء اتشهرت من توثيق الـ Frameworks، بس دي Architecture Patterns — زي الـ RAG نفسه بالظبط. كل واحدة بتتكتب في أقل من 30 سطر بأي لغة وأي Provider (شوفت Multi-Query كامل فوق في 20 سطر). استخدم الجاهز لو عايز — بس افهم الفكرة الأول، عشان لما يفشل تعرف تفتحه وتصلحه.

3) «Self-Query بيغنيني عن تصميم الـ Metadata» — ❌ بالعكس تمامًا — Self-Query هو أكتر Pattern بيعتمد على Metadata متصممة كويس. الموديل بيترجم السؤال لفلاتر على الحقول اللي أنت عرفتها وقت الـ Ingestion. مفيش حقول نضيفة؟ مفيش Self-Query. الذكاء في الـ Schema قبل ما يكون في الموديل.

<!-- Field 23: Related concepts -->

🔒 أمان

نقطة واحدة بس هنا — وهي تخص Self-Query تحديدًا: عمر ما فلتر الصلاحيات يكون من توليد الموديل.

في Self-Query، الموديل بيولّد فلاتر من كلام المستخدم. تخيّل مستخدم كتب: «هات كل المستندات بما فيها بتاعة الإدارة العليا» — لو فلتر الصلاحيات (allowed_departments) بيتولد من نفس النداء، أنت حرفيًا سايب المستخدم يفاوض الموديل على صلاحياته. ده Prompt Injection على مستوى الـ Retrieval.

القاعدة: فلاتر الصلاحيات بتتحط في الكود، بعد ما الموديل يولّد فلاتر البحث — بتتضاف عليها إجباريًا ومن مصدر موثوق (الـ Session بتاعة المستخدم). الموديل يقترح year = 2024؟ ماشي. الموديل يقرر مين يشوف إيه؟ أبدًا.

<!-- Field 21: Cost considerations — the stacking worked estimate per brief -->

💸 التكلفة — حساب التراكم بالورقة والقلم

هنا أهم جدول في الصفحة. خلينا نبني على نفس سيناريو مفهوم «ليه الـ RAG موجود أصلًا؟»: 50,000 سؤال شهريًا.

> 💸 أرقام قابلة للتغير *(Volatile fragment — أسعار نموذجية للتوضيح؛ راجع أسعار مزوّدك الحالية)*: موديل توليد متوسط بـ $3/مليون Input و $15/مليون Output؛ نداء مساعد (Variants/Parsing) بموديل صغير ~$0.001 للنداء؛ Embeddings مهملة التكلفة زي ما حسبنا قبل كده.

الإعدادنداءات LLM/سؤالInput Tokens تقريبًاتكلفة/سؤالشهريًا (50k)Latency تقريبية
Top-k بسيط (Baseline)1~2,300~$0.011~$570~2–4 ث
+ Multi-Query2~3,000 (بعد التشذيب لـ 6 Chunks)~$0.015~$760+1–1.5 ث
+ Parent-Document (فوق اللي فات)2~5,500 (Parents أكبر)~$0.023~$1,150+0.1 ث
+ Self-Query (التلاتة مع بعض)3~5,500~$0.024~$1,220+1–1.5 ث

اقرا الجدول ده من تحت لفوق: التراكم الكامل = ضعف الفاتورة وضعف الـ Latency تقريبًا (من ~2–4 ثواني لـ ~5–7). ممكن جدًا يستاهل — لو الـ Golden Set بيقول إن الجودة قفزت. ومستحيل يستاهل لو ركّبته «احتياطيًا».

وحيلتين توفير قبل ما تمشي:

  • نداء واحد بدل اتنين: لو بتستخدم Multi-Query و Self-Query مع بعض، اطلب من الموديل الصيغ والفلتر في نفس النداء — وفرت نداء و ~1 ثانية على كل سؤال.
  • الـ Patterns مش لازم تشتغل على كل سؤال: Router بسيط (أو حتى Regex بيكتشف سنة/قسم في السؤال) يقدر يفعّل Self-Query للأسئلة اللي محتاجاه بس. أغلب الأسئلة بسيطة — متدفعش تمن الدهاء فيها.

<!-- Field 14: Common mistakes -->

إمتى تستخدمها؟

شخّص من الجدول ده — العرض الأول، بعدين العلاج:

العرض اللي شايفه في الـ Logsالتشخيصالـ Pattern
المستخدمين بيسألوا بكلمات مختلفة عن كلمات المستندات (عامية vs رسمي، عربي vs إنجليزي، مترادفات)Vocabulary MismatchMulti-Query
أسئلة فيها شروط — سنة، قسم، نوع، حالة — والنتايج بتتجاهل الشرطسؤال MetadataSelf-Query
الـ Chunk الراجع صح بس الإجابة بتطلع ناقصة أو مقطوعةChunk أصغر من الإجابةParent-Document
سؤال مقارنة أو متعدد الجوانب بيرجّع جانب واحد بسسؤال محتاج كذا زاويةMulti-Query
النتايج الملائمة موجودة بس مدفونة في ترتيب متأخرمشكلة ترتيبReranking (مفهومه المخصوص)
المحادثة متعددة الأدوار — «طيب وده؟» بيرجّع زبالةسؤال ناقص سياقQuery Rewriting (Multi-turn RAG)
النتايج ملهاش علاقة خالص حتى بأسئلة مباشرةالمشكلة أعمق من الـ Retrieverارجع خطوة: Chunking والـ Embedding Model والبيانات نفسها

⚠️ خد بالك من السطر الأخير. لو الأساس بايظ — Chunking أعمى أو Embedding Model مش مناسب للغة بياناتك — أي Pattern هتركّبه فوقه بيلمّع الزبالة مش بيصلّحها. الـ Patterns دي تحسين على أساس سليم، مش بديل عنه.

<!-- Field 17: When NOT to use it (Layer 7b) -->

وإمتى لأ؟
  • النظام لسه بيتبني: أول نسخة من أي RAG تبقى بالبحث البسيط. دايمًا. محتاج Baseline تقيس عليه قبل أي دهاء.
  • مفيش قياس: لو معندكش Golden Set، مش وقت Patterns — وقت بناء Golden Set. التحسين من غير قياس اسمه تخمين بفلوس.
  • الفشل مش عندك: مستخدمينك بيسألوا أسئلة مباشرة بألفاظ المستندات نفسها؟ الـ Top-k البسيط كفاية، وأي إضافة تمن من غير مقابل.
  • الـ Latency عندك مقدسة: لو الـ SLA بتاعك ضيق، نداء LLM إضافي قبل البحث ممكن يكون رفاهية متتحملش — ساعتها فكّر في Hybrid Search أو تحسين الـ Chunking الأول (بيصلّحوا كتير من نفس الأعراض بصفر نداءات إضافية).
  • سؤال Metadata نادر: لو سؤال «هات بتاع 2024» بيظهر مرة في الشهر، متبنيش Self-Query عشانه — حط الفلاتر في الـ UI وخلي المستخدم يختارها بنفسه. أرخص وأضمن.

<!-- Field 18: Alternatives -->

البدايل — قبل ما تركّب Retriever متقدم

البديلبيصلّح إيهإمتى يكسب
تحسين الـ Chunkingمعنى مقطوع، Chunks بلا سياقأول حاجة تجربها دايمًا — بيصلّح نسبة كبيرة من مشاكل الاسترجاع بصفر تكلفة تشغيلية
Hybrid Searchالأسماء والأكواد والمصطلحات الدقيقة اللي البحث الدلالي بيطمسهابياناتك فيها أكواد منتجات، أسماء APIs، أرقام سياسات
Rerankingترتيب ضعيف لنتايج موجودةالنتيجة الصح بتظهر بس مش في الأول
Metadata Filtering يدوي (من الـ UI)نفس مشكلة Self-Queryالشروط معروفة ومحدودة — سيبها للمستخدم بدل موديل يخمنها
Long Context (حط أكتر)«يمكن الإجابة في اللي مرجعتوش»إغراء دايم — وغالبًا غلط: بتدفع أكتر وبتشتت الموديل. قيس قبله

<!-- Field 19: Trade-offs -->

الموازنات

المعيارTop-k بسيطMulti-QuerySelf-QueryParent-Document
نداءات LLM إضافية لكل سؤال0+1+10
عمليات بحث لكل سؤال13–51 (مفلترة)1
Latency إضافية—⚠️ ~0.5–1.5 ثانية (النداء قبل البحث)⚠️ ~0.5–1.5 ثانية✅ شبه صفر
حجم الـ Context الداخل للموديلBaseline⚠️ أكبر لو مشذبتش✅ زي الـ Baseline أو أقل❌ أكبر بوضوح (Parents)
شغل وقت الـ IngestionBaseline✅ ولا حاجة⚠️ تصميم Metadata Schema⚠️ تقطيع مزدوج + Store تاني
أكبر مكسب متوقع—تغطية أوسع للصياغاتدقة شبه كاملة في أسئلة الشروطإجابات كاملة بدل مقطوعة
أسوأ ما فيهبيفشل بصمتفلوس و Latency على كل سؤال حتى السهلMetadata ضعيفة = فلاتر غلط = صفر نتايجContext متضخم يرجّعك لمشكلة تانية

<!-- Field 20: Security considerations -->

خلينا نبنيهاالقراءة خلصت — دلوقتي ابنيها بإيدك.تحدّي: تشريح الـ Retrieval
أسئلة الانترفيو

س1: الـ Retrieval عندك ضعيف — امشيني في طريقة تفكيرك. الإجابة القوية بتبدأ بالتشخيص مش بالحلول: أطلّع عينة من الأسئلة الفاشلة من الـ Logs، أبص على الـ Chunks الراجعة بعيني، وأصنّف الفشل — ألفاظ مختلفة؟ شروط Metadata متجاهلة؟ سياق ناقص؟ ترتيب ضعيف؟ كل نمط ليه علاج معروف (Multi-Query / Self-Query / Parent-Document / Reranking). وأقيس قبل وبعد على Golden Set. اللي بيرد بقايمة Patterns من غير كلمة «تشخيص» بيقول إنه بيحفظ مش بيهندس.

س2: اشرح Multi-Query Retrieval — وإيه تمنه الحقيقي؟ توليد 3–4 صيغ بديلة للسؤال بنداء LLM، البحث بكلهم، ودمج النتايج مع إزالة التكرار — بيصلّح اختلاف الألفاظ بين السؤال والمستندات. التمن: نداء LLM إضافي قبل البحث (يعني +Latency في المسار الحرج)، بحث مضاعف، و Context أكبر لو مفيش تشذيب. تقريبًا +35–50% على تكلفة السؤال. ذكر التمن من غير ما تتسأل هو اللي بيميز الإجابة.

س3: إيه الفرق بين Self-Query Retrieval والـ Metadata Filtering العادي؟ الآلية واحدة — التنفيذ وقت الاسترجاع بفلاتر على الحقول. الفرق في مين بيكتب الفلتر: في العادي، الكود أو المستخدم (Dropdown في الـ UI). في Self-Query، موديل بيترجم السؤال الطبيعي لفلتر. ولازم تكمّل: فلاتر الصلاحيات بالذات عمرها ما تتولد من الموديل — دي بتتضاف من الـ Session في الكود، وإلا فتحت باب Injection.

س4: ركّبت Retriever متقدم — إزاي تثبت لمديرك إنه استاهل؟ بتلات أرقام قبل/بعد على Golden Set ثابت: مقياس جودة استرجاع (Hit Rate أو Precision/Recall)، التكلفة لكل سؤال، والـ Latency. «الجودة من 62% لـ 84%، مقابل +$0.004 للسؤال و +1 ثانية» — دي إجابة مهندس. «الإجابات بقت شكلها أحسن» — دي مش إجابة أصلًا.

<!-- Field 28: Knowledge check (scenario-based per F5) -->

مصادر أكتر
  • جوه BuildAI (بالترتيب): Reranking & advanced retrieval ← Query understanding: rewriting & expansion ← Evaluating RAG systems ← RAG cost & latency optimization.
  • قرار التنفيذ: «تبني الـ RAG بإيه؟ — LangChain ولا LlamaIndex ولا من غير Framework؟» — بتنفذ الـ Patterns دي بإيدك ولا بمكتبة جاهزة.
  • توثيق الـ Frameworks: LangChain و LlamaIndex عندهم صفحات لنفس الـ Patterns بنفس الأسماء تقريبًا — اقراها بعد الصفحة دي، وهتلاحظ إنك بقيت شايف الفكرة ورا الـ API.

<!-- Reading→building exit — single primary CTA per Phase 1 §6 -->