المستوى المطلوب: محترف. المقال ده مكتوب لحد مستخدم RAG في الإنتاج فعلًا، عارف الـ embeddings و الـ vector DB، وبيدوّر على السبب اللي بيخلّي الإجابة الأولى عنده غلط رغم إن الـ recall بقاله شهور ممتاز.
الـ Recall@10 عندك 92%، يعني الإجابة الصح موجودة في أول عشر نتايج. لكن المستخدم بيشوف نتيجة واحدة بس، والـ Precision@1 عندك 47%. ده مش bug في الـ embeddings، ده الفرق الجوهري بين الاسترجاع و الترتيب. المقال هنا بيشرح ليه bi-encoder لوحده مش كفاية، وازاي تضيف Cross-encoder Reranker بيرفع الـ NDCG@10 من 0.61 لـ 0.78 على بيانات عربية فعلية.
إعادة الترتيب: السلاح المفقود في معظم خطوط RAG العربية
المشكلة باختصار
أي pipeline RAG كلاسيكي بيمر بمرحلتين: الـ retriever بيجيب أعلى k نتيجة من الـ vector store، والـ generator (LLM) بيستخدمها للرد. المشكلة إن الـ retriever مبني على bi-encoder: الـ query والـ document بيتحوّلوا لمتجهين منفصلين، والمقارنة بـ cosine similarity. الترتيب ده سريع جدًا (ميلي ثانية على مليون مستند)، لكنه فايت معلومة كاملة: التفاعل بين كلمات الـ query وكلمات الـ document.
النتيجة العملية: لو سألت "ازاي أحسّن استعلام Postgres بطيء على جدول 50 مليون صف؟"، الـ retriever ممكن يرجّعلك مقالات عن "Postgres performance" بشكل عام في المركز الأول، ومقال "Index-Only Scan على جداول كبيرة" في المركز السابع. الإجابة الصح موجودة، بس مش في الأعلى.
مثال للمبتدئ قبل التعريف العلمي: لجنة التحكيم
تخيّل مسابقة فيها 1000 مشترك. عندك مرحلتين: تصفيات أولية ونهائي. التصفيات بتختار أفضل 20 بناءً على CV مكتوب، بسرعة، بدون مقابلة. ده الـ retriever: سريع، رخيص، مش دقيق. النهائي بيعمل مقابلة عميقة لكل واحد من العشرين، ويرتّبهم على أساس التفاعل الفعلي. ده الـ reranker: بطيء، مكلّف، دقيق.
لو شيلت مرحلة النهائي وقلت "العشرين بتوع التصفيات هما الترتيب النهائي"، الفايز هيكون اللي CV بتاعه ظريف، مش اللي إجابته أحسن. ده بالظبط اللي بيحصل في RAG بدون reranking.
التعريف العلمي: Bi-encoder vs Cross-encoder
الـ bi-encoder بيشتغل بصيغة: sim(E(query), E(doc)). كل نص بيمر في الموديل لوحده، فينتج embedding ثابت. ده بيخلّي الـ document embeddings تتحسب مرة واحدة وتتخزّن في الـ vector DB.
الـ cross-encoder مختلف جذريًا: score = Model([CLS] query [SEP] doc [SEP]). الـ query والـ doc بيدخلوا جوا الـ Transformer مع بعض، فتتولّد cross-attention مباشرة بين كل توكن في الـ query وكل توكن في الـ doc. النتيجة scalar score بدل vector. الإيجابية: دقة أعلى بكتير. السلبية: محتاج forward pass جديد لكل (query, doc) pair، يعني ميزتش الترتيب من 100K مستند، بس فينعك تعمل rerank لـ top 20-100.
القاعدة العملية: retriever بيعمل recall، reranker بيعمل precision. لازم الاتنين.