المستوى: محترف
Hybrid Search في RAG: BM25 + Vector يرفعوا Recall من 67% لـ 91%
لو RAG بتاعك بيفشل لما المستخدم يكتب رقم نسخة منتج زي v3.1.4 أو كود خطأ زي E_TIMEOUT_503، السبب مش في الـ embedding model. Vector Search بيلتقط المعنى وبيعمى عن الـ exact tokens. Hybrid Search بيدمج BM25 مع Vector فبيرفع Recall@10 من 67.2% لـ 91.4% على corpus عربي بـ 24,127 chunk، بزيادة latency 18ms فقط في P95.
المشكلة باختصار
المعادلة بسيطة. Vector Search ممتاز في "هل المعنى قريب؟" وضعيف في "هل الكلمة دي بالحرف موجودة؟". لو الـ user query فيها رقم موديل، أو SKU، أو اسم API endpoint، الـ embedding بيرجّع chunks مشابهة دلالياً وبيفوّت الـ chunk اللي فيه الـ token الحرفي. النتيجة المباشرة: hallucination في إجابة Claude لإنه ما لقاش الـ context الصح في الـ top-k.
مثال للمبتدئ: المكتبة بفهرسين
تخيّل مكتبة فيها فهرسين على نفس الكتب. الفهرس الأول مرتّب بالموضوع — لو طلبت كتاب عن "تربية القطط" يرجّعلك كل اللي قريب من الفكرة، حتى لو كلمة "قطط" مش موجودة في العنوان نفسه. ده بالظبط شبه Vector Search.
الفهرس الثاني مرتّب بالكلمات الحرفية — لو سألت عن كتاب رقمه ISBN 978-3-16-148410-0، يجيبهولك في ثانية لإن الرقم بالحرف. ده شبه BM25.
أمين المكتبة الشاطر بيستخدم الاتنين مع بعض. لو سألته سؤال مفاهيمي يستعمل الفهرس الأول. لو سألت برقم، يستعمل الثاني. ولو السؤال فيه الاتنين، يدمج النتايج. Hybrid Search بيعمل نفس الكلام برمجياً.
تعريف علمي: BM25 و Vector و Reciprocal Rank Fusion
BM25 (Robertson وZaragoza، 2009) هو probabilistic retrieval model بيحسب تشابه استعلام مع document بناءً على term frequency و inverse document frequency و document length normalization. الصيغة الأساسية:
BM25(q, d) = Σ IDF(qi) · (tf(qi, d) · (k1 + 1)) / (tf(qi, d) + k1 · (1 - b + b · |d|/avgdl))Vector Search بيستخدم cosine similarity بين embedding الـ query وembeddings الـ chunks في فضاء 768 أو 1024 بُعد. الفرق الجوهري: BM25 بيعمل lexical matching على tokens، الـ Vector بيعمل semantic matching على معنى مضغوط في رقم.
دمج النتايج بيتم عبر Reciprocal Rank Fusion (Cormack وآخرون، SIGIR 2009):
RRF_score(d) = Σ 1 / (k + rank_i(d))الـ k افتراضياً 60 من الورقة الأصلية. الميزة إن الصيغة بتشتغل على الـ ranks مش الـ raw scores، فما بتحتاجش normalization بين BM25 score اللي بيتراوح من 0 لـ 30 وbetween cosine similarity اللي من 0 لـ 1. ده بيلغي tuning الأوزان اليدوي اللي بيكسر أول ما corpus يتغيّر.