المستوى: متوسط
Reranking في RAG: ليه الـ vector search لوحده مش كفاية
لو الـ chatbot عندك بيرجّع إجابات قريبة من السؤال لكن مش الإجابة الصح في نص الحالات، المشكلة مش في النموذج ولا في حجم الـ corpus. المشكلة إنك بتعتمد على bi-encoder واحد لاتخاذ قرار محتاج cross-encoder. سطر واحد من Cohere Rerank بيرفع Precision@1 من 47% لـ 89% على نفس الـ embeddings بالظبط.
المشكلة باختصار
الـ vector search بيشتغل بـ embedding واحد لكل وثيقة و embedding واحد للسؤال، وبيقيس cosine similarity بينهم. ده سريع جداً (10 مللي ثانية على مليون وثيقة) لكنه تقريبي. الـ bi-encoder بيضغط معنى الوثيقة كاملاً في 1024 رقم قبل ما يشوف السؤال أصلاً، فبيخسر تفاصيل دقيقة الـ user بيهتم بيها.
النتيجة في الإنتاج: top-5 بيكون فيه الإجابة الصح في 71% من الحالات (Recall@5 = 71%)، لكن top-1 — اللي هو اللي بتعرضه للمستخدم — بيكون غلط في 53% من الحالات. ده الفرق بين RAG بيشتغل و RAG بيخرّب الـ trust بتاع المنتج.
مثال بسيط: أمين المكتبة والمساعد
تخيّل مكتبة فيها 10 آلاف كتاب وعميل سأل عن "كتب الفيزياء النووية للمبتدئين". المساعد بيدوّر بسرعة في الفهرس ويرجّع 50 كتاب فيهم الكلمة. كويس، لكن مش كل الـ 50 مفيدين. أمين المكتبة الخبير بيقلّب فيهم، يقرا المقدمات، ويختار: ده فعلاً للمبتدئين، ده ماجستير، ده عن الاندماج مش الانشطار.
الـ bi-encoder هو المساعد السريع. الـ cross-encoder هو أمين المكتبة الدقيق. الـ RAG اللي بيشتغل في الإنتاج لازم يكون فيه الاتنين. واحد بياخد قرار "هل الوثيقة دي محتمل تكون مفيدة؟" بسرعة، والتاني بياخد قرار "هل هي فعلاً الأفضل من ضمن الـ 50 ديه؟" بدقة.
الفرق العلمي بين Bi-encoder و Cross-encoder
الـ bi-encoder (زي text-embedding-3-small) بيمر السؤال في transformer لوحده، والوثيقة في transformer لوحدها، وبيطلع vector لكل واحد. المقارنة بتحصل بعد كده بـ dot product بسيط. التكلفة: embedding الوثائق بيتحسب مرة واحدة وقت الـ indexing، والـ query embedding بيتحسب مرة في الـ runtime. البحث في 10 مليون وثيقة بياخد 20ms.
الـ cross-encoder بيدخل السؤال والوثيقة سوا في input واحد، وبيمر على كل layers الـ transformer مع cross-attention بين كل كلمة في السؤال وكل كلمة في الوثيقة. الدقة بتقفز لأن النموذج بيشوف العلاقة المباشرة. المشكلة: لازم يتعمل forward pass جديد لكل (query, document) pair. على مليون وثيقة، ده ساعتين لكل query.
الحل الهندسي: استخدم bi-encoder علشان تنزّل المليون وثيقة لـ top-100 في 20ms، وبعدين استخدم cross-encoder علشان ترتّب الـ 100 وتاخد top-5 في 120ms. المجموع 140ms، والدقة بتقفز 42 نقطة.
الكود الكامل بـ Cohere Rerank 3.5
الكود تحت بيشتغل على Python 3.11+ و cohere SDK 5.13+. الافتراض إن عندك vector store قائم (Pinecone أو Qdrant أو حتى pgvector) وبيرجّع candidates مع نصوصهم.