در سیستمهای RAG واقعی، استفادهی صرف از جستجوی معنایی یا جستجوی کلیدواژهای معمولاً به بنبست میرسد. اگر کاربر نام دقیق یک تابع یا متغیر مانند `AbortMultipartOnFail` را جستجو کند، مدلهای امبدینگ متراکم معمولاً به دلیل همپوشانی برداری با مستندات نامرتبط به خطا میروند و نتیجهی اشتباهی را برمیگردانند. از طرف دیگر، اگر کاربر مفهوم یک سناریو را بازنویسی کند و کلمات کلیدی اصلی متن را به کار نبرد، موتورهای واژگانی مانند BM25 دست خالی میمانند.
راهحل استاندارد صنعتی برای این چالش، «بازیابی ترکیبی» (Hybrid Retrieval) است؛ یعنی اجرای همزمان بازیابی واژگانی و بازیابی متراکم و سپس تلفیق نتایج با روش «تلفیق رتبهی متقابل» (RRF). در این درس یاد میگیرید که چگونه الگوریتم BM25 را همراه با وزندهی به فیلدها و نرمالسازی طول سند از صفر بسازید و آن را بدون نیاز به وابستگی به کتابخانههای سنگین با جستجوی برداری ادغام کنید.
تمامی بخشهای این درس با یک پیادهسازی قطعی و بدون نیاز به فراخوانی API خارجی طراحی شدهاند، بنابراین میتوانید بدون نگرانی از هزینههای ارزی، سهمیهبندی سرویسهای ابری یا نیاز به سختافزارهای گرانقیمت، ساختار ریاضی و رفتاری تلفیق رتبهها را روی پردازندهی سیستم شخصی خود آزمایش و ارزیابی کنید.
بازیابی واژگانی و معنایی در توزیعهای متفاوتی از پرسوجوها با شکست روبهرو میشوند. بازیابی ترکیبی (hybrid retrieval) با تلفیق رتبهی متقابل (reciprocal rank fusion یا RRF) درونیابی نمیکند، بلکه رأیگیری میکند — و این رأی در همهی انواع پرسوجو برنده میشود.
اهداف یادگیری
- پیادهسازی BM25 از صفر بر اساس فرمول رابرتسون و اسپارک جونز، همراه با وزندهی به فیلدها، نرمالسازی طول سند، و پارامترهای قابلتنظیم k1 و b.
- ساخت یک بازیاب متراکم (dense retriever) روی یک امبدینگ ساختگی (mock embedding) قطعی تا حلقه بدون نیاز به اینترنت اجرا شود.
- پیادهسازی RRF دقیقاً مطابق مقالهی سال 2009 کورمک، کلارک و بوچر، و توضیح اینکه چرا نسبت به درونیابی با وزندهی امتیازها برتری مطلق دارد.
- تنظیم ثابت k در RRF و وزنهای اختصاصی هر روش (modality)، و بررسی بدهبستانهای آن روی یک پیکرهی متنی آزمایشی کوچک.
صورت مسئله
جستجوی واژگانی (lexical search) زمانی برنده است که پرسوجو شامل شناسهای دقیق باشد که عیناً در پیکره آمده است. پرسوجویی برای AbortMultipartOnFail، تابع درست در زبان Go را با BM25 در کسری از میکروثانیه پیدا میکند. اگر همین پرسوجو را امبد کنید، بردار آن روی مرز سه خوشهی مشابه مینشیند و بازیاب متراکم، فایل اشتباهی را در رتبهی اول قرار میدهد.
در سوی دیگر، جستجوی متراکم (dense search) وقتی دست بالا را دارد که پرسوجو بازنویسی شده باشد و واژههایش با توکنهای دقیق درون پیکره فرق کند. کاربری که میپرسد «چگونه آپلودهای لغوشده را مدیریت کنیم»، هرگز کلمات abort یا multipart را ننوشته است. در این حالت BM25 قطعهی مربوط به «آپلود فایلهای حجیم» از مستندات را برمیگرداند، چون در آن صفحه کلمهی uploads آمده است. اما بازیابی متراکم تابعی را پیدا میکند که کارش لغو فرایند است و در خلاصهاش به لغو شدن اشاره شده است.
انتخاب بین این دو یک تصمیم ایستا نیست؛ متغیر اصلی، توزیع پرسوجوهاست. یک سیستم RAG در محیط عملیاتی (پروداکشن) باید هر دو نوع پرسوجو را از طریق یک اندپوینت (endpoint) پاسخ دهد؛ بنابراین پایپلاین بازیابی باید بتواند همزمان از پس هر دو برآید. این همان بازیابی ترکیبی است. مرحلهی merge دقیقاً همان بخشی است که پیادهسازی درستش حیاتی است.
مبانی نظری
خلاصهی BM25 در یک پاراگراف
الگوریتم BM25 امتیاز یک جفت پرسوجو-سند را با جمع زدن روی واژههای پرسوجو حساب میکند: حاصلضرب ضریب فرکانس معکوس سند (IDF) در یک فاکتور فرکانس واژه (TF) که اشباعپذیر است و تصحیح نرمالسازی طول سند را هم در خود دارد. دو متغیر تنظیمی داریم: k1 نرخ اشباع (saturation) فرکانس واژه را کنترل میکند؛ مقدار پیشفرض 1.5 پیشنهاد ارائهشده در مقالههاست و نباید بدون بنچمارک تغییرش دهید. b تعیین میکند طول سند چقدر اثرگذار باشد؛ مقدار پیشفرض 0.75 یعنی اسناد طولانیتر جریمه میشوند، اما نه بهصورت خطی.
برای فرمول IDF از تعریف هموارسازیشدهی رابرتسون و اسپارک جونز استفاده میشود، یعنی log((N - df + 0.5) / (df + 0.5) + 1). عبارت بعلاوهی یکِ داخل لگاریتم باعث میشود وقتی واژهای در بیش از نیمی از پیکره آمده باشد، IDF مثبت بماند. این موضوع برای کلمات توقف (stopwords) که در بیشتر اسناد تکرار میشوند و همچنین در پیکرههای کوچک که یک واژهی رایج میتواند از مرز نصف پیکره بگذرد، اهمیت زیادی دارد.
وزندهی به فیلدها به شما امکان میدهد به BM25 بفهمانید تطابق در نام شناسه، ارزش بیشتری نسبت به تطابق در متن بدنه دارد. در پیادهسازی، این کار با اعمال یک ضریب روی شمارش واژهها هنگام نمایهسازی انجام میشود، نه در زمان امتیازدهی. با این کار، فرمولهای ریاضی تغییر نمیکنند و نیازی به محاسبهی امتیاز جداگانه برای هر فیلد نخواهد بود.
خلاصهی بازیابی متراکم در یک پاراگراف
با یک مدل امبدینگ، هر قطعه (chunk) را به یک بردار متراکم (dense vector) با بُعد ثابت تبدیل میکنید. هنگام پرسوجو، متن ورودی را امبد میکنید، تمام قطعهها را بر اساس شباهت کسینوسی رتبهبندی میکنید و k نتیجهی برتر را تحویل میدهید. کیفیت خروجی مستقیماً به مدلی بستگی دارد که انتخاب میکنید. خود الگوریتم بازیابی تنها در دو خط خلاصه میشود: ضرب داخلی (dot product) و مرتبسازی.
در این درس از یک امبدینگ قطعی بر پایهی هش استفاده میکنیم تا بتوانید محاسبات ریاضی تلفیق را بدون نیاز به فراخوانی شبکه بررسی کنید. این تابع هش، آفستهای متناظر با توکنها را در یک بردار 96 بعدی جمع کرده و نرمال میکند. رتبههای کسینوسی در همهی دفعات اجرا کاملاً یکسان هستند، که این ویژگی برای اجرای دقیق تستها ضروری است.
تلفیق رتبهی متقابل: فرمول اصلی مقاله
دو فهرست رتبهبندیشده را در نظر بگیرید. برای هر گزینهای که در هر یک از این دو فهرست آمده است، سهم رتبهی متقابل آن را جمع بزنید. مقالهی سال 2009 از فرمول 1 / (k + rank) با مقدار پیشفرض k برابر با 60 استفاده کرد. در نهایت فهرست را بر اساس امتیاز کل مرتب کنید؛ کل الگوریتم همین است.
مقدار ثابت k = 60 در مقالهی اصلی تصادفی انتخاب نشده است. با k = 60، سهم رتبهی اول 1 / 61 و سهم رتبهی دهم 1 / 70 خواهد بود. این یعنی سهم رتبهها با شیب ملایمی کم میشود تا گزینههای موجود در رتبههای پایینتر هم شانس رأیدادن داشته باشند. مقدار k کوچکتر باعث تسلط کامل نتایج صدر جدول میشود؛ در حالی که k بزرگتر، منحنی کاهش سهم رتبهها را هموارتر میکند.
در پیادهسازی ما دو متغیر تنظیمی وجود دارد: ثابت k، و یک جفت وزن برای هر روش، تا در صورت وجود شواهد (evidence) پیشین مبنی بر عملکرد بهتر یکی از روشها روی پیکرهی شما، بتوانید وزن BM25 یا بازیابی متراکم را بالاتر ببرید. ضرب کردن سهم رتبه در این وزن، سادهترین و اصولیترین روش پیادهسازی است؛ چون الگوی افت رتبه را حفظ میکند و بدون مقیاس باقی میماند.
چرا تلفیق از درونیابی با وزندهی امتیازها بهتر عمل میکند؟
امتیازهای BM25 کراندار نیستند و به پیکره وابستهاند. در مقابل، شباهتهای کسینوسی همواره در بازهی 1- تا 1 قرار دارند. ترکیب خطی این دو بهصورت alpha * bm25 + (1 - alpha) * cosine نیازمند تنظیم مجزای مقدار alpha برای هر پیکره است و با هر بار نمایهسازی مجدد به هم میریزد. تلفیق مبتنی بر رتبه چنین مشکلی ندارد؛ دو رتبه همیشه در میان روشهای مختلف قابل مقایسهاند. خط مبنای (baseline) استاندارد RRF از سال 2010 در تمامی رقابتهای عمومی TREC توانسته روشهای درونیابی امتیاز را شکست دهد.
همین استدلال را در مستندات موتورهای جستجوی Vespa و Weaviate دربارهی مقایسهی RankFusion با RRF میبینید. آنها هم به همین نتیجه رسیدهاند: همیشه از روشهای مبتنی بر رتبه استفاده کنید، مگر اینکه شواهد بسیار محکمی برای درونیابی امتیازها داشته باشید.
پیادهسازی
فایل code/main.py این بخشها را پیادهسازی میکند:
tokenize(text)- یک توکنایزر سریع مبتنی بر regex.BM25Index- نمایهساز همراه با وزندهی به فیلدها، متدهایaddوsearchو مقادیر قابلتنظیم k1 و b.mock_embedوDenseIndex- همان امبدینگ قطعی درس 64، تا قطعهها با هم قابل مقایسه باشند.rrf(rankings, k, weights)- پیادهسازی تلفیق مطابق مقاله، همراه با وزندهی به هر روش.HybridRetriever- ترکیبکنندهی BM25 و بازیاب متراکم.- تابع دموی
main()که یک پیکرهی متنی آزمایشی کوچک را بارگذاری میکند، سه پرسوجو را برای سنجش نقاط قوت و ضعف هر بازیاب اجرا میکند، و در نهایت رتبهبندیهای هر روش را در کنار فهرست تلفیقشده نمایش میدهد.
کد را اجرا کنید:
python3 code/main.py
خروجیهای دمو را کنار هم مقایسه کنید. در پرسوجوی حاوی شناسهی دقیق، رتبهی BM25 برابر با 1، رتبهی متراکم برابر با 4 و رتبهی نهایی RRF برابر با 1 میشود. در پرسوجوی بازنویسیشده، رتبهی BM25 برابر با 6، رتبهی متراکم برابر با 1 و رتبهی RRF برابر با 1 است. در پرسوجوی مبهم، رتبهی هر دو روش 3 است اما رتبهی RRF به 1 میرسد. تلفیق رتبهها صرفاً برای رفع برابریها نیست؛ بلکه سیستمی است که در همهی انواع پرسوجو بهترین نتیجه را میگیرد.
تنظیم متغیرها
| متغیر تنظیمی | مقدار پیشفرض | چه زمانی مقدار را بالا ببریم؟ | چه زمانی مقدار را پایین بیاوریم؟ |
|---|---|---|---|
| BM25 k1 | 1.5 | کلمات در اسناد تکرار میشوند و میخواهید تکرار واژه وزن بیشتری بگیرد | اسناد کوتاهاند و تکرار واژهها نویز به حساب میآید |
| BM25 b | 0.75 | اسناد طولانی واقعاً به ازای هر کلمه بار معنایی کمتری دارند | طول سند ارتباطی با موضوع آن ندارد |
| RRF k | 60 | میخواهید گزینههای رتبههای پایینتر هم شانس رأیدادن داشته باشند | میخواهید رتبهی اول بر سایر نتایج مسلط باشد |
| وزن BM25 | 1.0 | پیکرهی شما شامل شناسههای دقیق است و پرسوجوها عیناً با آنها مطابقت دارند | پرسوجوها توسط کاربران بازنویسی میشوند |
| وزن متراکم | 1.0 | پرسوجوها بازنویسی شدهاند | پرسوجوها واژگانی و حاوی شناسههای دقیقاند |
تنظیمات را بر اساس شهود دستکاری نکنید؛ بستر آزمایشی (harness) ارزیابی درس 68 را روی مجموعهی پرسوجوهای جداگانهی خود اجرا کنید و تصمیم بگیرید.
حالتهای شکستی که دمو پنهان میکند
توکنهای خارج از دایرهی واژگان. مقدار IDF در BM25 بر اساس کل پیکره محاسبه میشود؛ بنابراین واژههایی که فقط در پرسوجو آمدهاند، اثری در امتیاز ندارند. در مقابل، امبدینگهای متراکم برای همین واژهها یک بردار توهم میکنند. بازیابی متراکم برای شناسههایی که در پیکره نیستند، همسایههایی بهظاهر معقول اما کاملاً اشتباه برمیگرداند. روش تلفیق اثر این خطا را خنثی میکند، چون BM25 خروجیای نمیدهد و سهم رتبهی آن حذف میشود؛ البته به شرطی که حذف دادههای تکراری را بر اساس سند انجام دهید، نه بر اساس قطعه.
غلبهی توکنهای توقف. جستجوی واژهای مانند «the» در BM25 رتبهبندی یکنواختی روی کل پیکره تولید میکند. باید توکنهای توقف را در نمایهساز فیلتر کنید یا بپذیرید که واژههای با IDF بالا خودبهخود وزن غالب را میگیرند.
یکسان بودن محتوا در هر دو روش. اگر پیکرهی شما آنقدر کوچک باشد که رتبهی اول BM25 و بازیابی متراکم یکی شود، RRF هم دقیقاً همان رتبهی اول را با همان همسایهها تحویل میدهد. این رفتار کاملاً درست است و نشانهی شکست نیست، اما باعث میشود نقش تلفیق دیده نشود. برای اطمینان از عملکرد درست تلفیق، حتماً جفت پرسوجوهای چالشی به ارزیابی خود اضافه کنید.
استفاده در عمل
الگوهای بهکارگیری در محیط عملیاتی (پروداکشن):
- نمایهسازی BM25 را درون فرایند برنامه (in-process) انجام دهید؛ گلوگاه اصلی دیکشنری فرکانس واژههاست، نه بردارها.
- بردارهای متراکم را در یک ذخیرهساز جداگانه نگه دارید (در این درس از یک لیست ساده استفاده میکنیم، اما در محیط عملیاتی باید به سراغ HNSW بروید).
- هر دو پرسوجو را بهصورت موازی اجرا کنید؛ مرحلهی تلفیق یک merge با زمان ثابت روی اجتماع نتایج است.
- روش بازیابیِ هر نتیجه را در خروجی ثبت کنید تا مدل بازرتبهبندیِ (reranker) بعدی بتواند ببیند کدام روش به آن نتیجه رأی داده است.
ورود به محیط عملیاتی
در درس 66 نتایج برتر تلفیقشده در این درس را با یک کراسانکودر (cross-encoder) بازرتبهبندی میکنیم. درس 68 کل پایپلاین را با معیارهای دقت (precision)، بازخوانی (recall)، MRR و nDCG ارزیابی میکند. بازیاب ترکیبی این درس، گام نخست در سیستم سرتاسری (end-to-end) درس 69 خواهد بود.
تمرینها
- تابع
mock_embedرا با یک مدل واقعی از ارائهدهندهی خود جایگزین کنید. دمو را دوباره اجرا کرده و تغییرات رتبهبندیِ روش متراکم را روی پرسوجوی بازنویسیشده گزارش دهید. - یک روش سوم اضافه کنید: خلاصهی قطعهها را جداگانه نمایهسازی کنید و خروجی آن را بهصورت فهرست رتبهبندی سوم با نتایج قبلی تلفیق کنید. میزان بهبود را بسنجید.
- مقدار k در RRF را بین مقادیر 10، 30، 60، 100 و 200 تغییر دهید. نمودار بازخوانی در K (Recall@K) را بر اساس درس 68 رسم کنید و مقداری از k را که در آن نمودار روی پیکرهی شما به اوج میرسد، گزارش کنید.
- الگوریتم BM25F را بهطور استاندارد پیادهسازی کنید (نرمالسازی طول به ازای هر فیلد، بهجای ترفند ضریب تکرار) و عملکرد آن را روی پیکرهای بسنجید که تطابق نام شناسهها در آن بیشترین اهمیت را دارد.
اصطلاحات کلیدی
| اصطلاح | برداشتی که رایج است | معنای دقیق فنی |
|---|---|---|
| BM25 | «جستجوی واژگانی» | رتبهبندی احتمالات با IDF × اشباع TF × نرمالسازی طول سند |
| RRF | «تلفیق رتبه» | مجموع 1 / (k + rank) در فهرستهای رتبهبندیشده؛ مقدار پیشفرض k = 60 |
| k1 | «اشباع TF» | سرعت متوقف شدن اثرگذاری تکرار یک واژه در افزایش امتیاز را کنترل میکند |
| b | «جریمهی طول سند» | مقدار 0 یعنی طول سند بیاثر است، و 1 یعنی نرمالسازی کامل اعمال شود |
| Field weighting | «تقویت ارزش شناسه» | تکرار توکنها حین نمایهسازی برای افزایش وزن تطابق در آن فیلد خاص |
| Rank-based vs score-based fusion | «برتری RRF بر ترکیب خطی» | رتبهها در روشهای مختلف قابل مقایسهاند، اما امتیازها اینطور نیستند |
برای مطالعهی بیشتر
- مقالهی Cormack, Clarke, Buettcher با عنوان "Reciprocal Rank Fusion outperforms Condorcet and individual rank learning methods", SIGIR 2009
- مقالهی Robertson, Walker, Beaulieu, Gatford, Payne با عنوان "Okapi at TREC-3" (مقالهی اصلی BM25)
- Vespa: Hybrid Retrieval with BM25 and Embeddings
- Weaviate: Hybrid Search
- بخش 11، درس 06 - مبانی RAG
- بخش 19، درس 64 - قطعهبندهایی که خروجیشان در اینجا نمایهسازی میشود
- بخش 19، درس 66 - بازرتبهبندی با کراسانکودر روی k نتیجهی برتر تلفیقشده
