هنگام ساخت برنامههای تولید تقویتشده با بازیابی (RAG)، توسعهدهندگان اغلب با گلوگاه رایج «یافتن سوزن در انبار کاه» مواجه میشوند. اگرچه پایگاههای داده برداری در بازیابی اسناد مشابه از نظر معنایی در مقیاس بزرگ عالی هستند، اما به تعبیههای متراکم تکیه دارند که شباهت را تقریب میزنند. این تقریب میتواند منجر به نویز شود، جایی که قطعات بازیابیشده از نظر موضوعی مرتبط هستند اما از نظر زمینهای برای پاسخ به پرسشهای پیچیده ناکافیاند. در اینجا بازمرتبسازی وارد میشود—مرحله بهینهسازی حیاتی که یک سیستم RAG خوب را به یک سیستم عالی تبدیل میکند.
درک شکاف بازیابی
در یک پایپلاین RAG استاندارد، مرحله بازیابی معمولاً از معماری دوبردار (bi-encoder) استفاده میکند. در اینجا، پرسش و سند به طور مستقل به تعبیههای برداری کدگذاری میشوند و شباهت از طریق شباهت کسینوسی محاسبه میشود. اگرچه این روش از نظر محاسباتی کارآمد است و تا میلیونها سند مقیاسپذیر است، اما فاقد توانایی درک تعاملات ظریف بین کلمات خاص پرسش و محتوای سند است.
برای مثال، اگر کاربر بپرسد: «آیا قرارداد اجازه قطع پیشدستانه بدون جریمه را میدهد؟»، یک دوبردار ممکن است بند مربوط به قطع پیشدستانه را از بخش دیگری بازیابی کند که حاوی جریمه است، صرفاً به این دلیل که کلمات از نظر معنایی همپوشانی دارند. اینجاست که مرحله بازمرتبسازی برای اصلاح این خطاها مداخله میکند.
بازمرتبسازی با Cross-Encoders
استاندارد طلایی برای بازمرتبسازی، استفاده از Cross-Encoders است. برخلاف دوبردارها، Cross-Encoders پرسش و سند را به طور همزمان پردازش میکنند. آنها میتوانند به هر کلمه در پرسش و هر کلمه در سند توجه کنند و تعاملات پیچیده معنایی، نفیها و محدودیتهای خاص را به دام بیندازند.
معمولاً، یک پایپلاین از جستجوی برداری متراکم برای بازیابی اولیه درشت (مثلاً دریافت ۵۰ تا ۱۰۰ سند برتر) استفاده میکند و سپس یک Cross-Encoder را برای امتیازدهی مجدد به این کاندیداها اعمال میکند و تنها ۵ تا ۱۰ قطعه مرتبطتر را به LLM برمیگرداند. این رویکرد هیبریدی سرعت و دقت را متعادل میکند.
پیادهسازی عملی با Sentence Transformers
پیادهسازی یک بازمرتبساز با استفاده از کتابخانههای مدرن پایتون ساده است. کتابخانه sentence-transformers مدلهای Cross-Encoder از پیش آموزشدیدهای را ارائه میدهد که میتوان آنها را در هر پایپلاین RAG جای داد. در زیر یک مثال عملی از نحوه امتیازدهی اسناد بازیابیشده در برابر یک پرسش آورده شده است.
from sentence_transformers import CrossEncoder
# بارگذاری یک مدل Cross-Encoder از پیش آموزشدیده
model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
# پرسش کاربر
query = "What are the benefits of using Cross-Encoders for re-ranking?"
# کاندیداهای اولیه بازیابیشده از یک پایگاه داده برداری (مرحله دوبردار)
candidates = [
"Cross-encoders are slow but accurate.",
"Vector databases use cosine similarity for search.",
"Re-ranking improves precision by processing query-document pairs jointly.",
"LLMs can hallucinate if context is irrelevant."
]
# محاسبه امتیازهای مرتبط بودن
scores = model.predict([(query, text) for text in candidates])
# جفت کردن امتیازها با متنها و مرتبسازی بر اساس امتیاز به صورت نزولی
results = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
for text, score in results:
print(f"Score: {score:.4f} | Text: {text}")
در این قطعه کد، مدل یک امتیاز مرتبط بودن برای هر کاندیدا برمیگرداند. با مرتبسازی این نتایج، ما تضمین میکنیم که LLM اطلاعاتی را دریافت میکند که بیشترین ارتباط زمینهای را دارد و نرخ توهم (hallucination) را به طور قابل توجهی کاهش میدهد.
نتیجهگیری
بازمرتبسازی فقط یک ویژگی اضافی اختیاری نیست؛ بلکه یک جزء ضروری برای سیستمهای RAG در سطح تولید است. با بهرهگیری از Cross-Encoders برای اصلاح نتایج بازیابی اولیه، توسعهدهندگان میتوانند دقت بازیابی دانش خود را به شدت بهبود بخشند. اگرچه این کار تأخیر را افزایش میدهد، اما این مبادله تقریباً همیشه به نفع کسب کیفیت پاسخ بیشتر است. هنگامی که برنامههای هوش مصنوعی خود را مقیاسبندی میکنید، ادغام یک استراتژی بازمرتبسازی قوی، عامل تمایز بین یک نمونه اولیه و یک محصول قابل اعتماد خواهد بود.