Retrieval-Augmented Generation (RAG)

تسلط بر جستجوی ترکیبی: معیار طلایی برای دقت RAG

تولید تقویت‌شده با بازیابی (RAG) نحوه تعامل مدل‌های زبانی بزرگ (LLM) با داده‌های خصوصی را متحول کرده است. با این حال، جستجوی صرفاً معنایی (بر پایه برداری) یک نقص حیاتی دارد: اغلب در شناسایی شناسه‌های خاص، اسامی خاص یا اصطلاحات فنی دقیق مشکل دارد. اگر از یک سیستم RAG بخواهید «کد خطای 40412» را پیدا کند، یک پایگاه داده برداری ممکن است صفحاتی درباره خطاهای عمومی 404 یا خطاهای «سطح 400» نامرتبط را بازیابی کند، اما به ندرت تعریف دقیق مورد نیاز شما را پیدا می‌کند.

راه‌حل چیست؟ جستجوی ترکیبی.

جستجوی ترکیبی، درک زمینه‌ای از جاسازی‌های برداری را با دقت تطبیق کلمات کلیدی سنتی (جستجوی پراکنده) ترکیب می‌کند. با ترکیب این دو روش‌شناسی، فراخوانی و دقت را به‌طور قابل‌توجهی بهبود می‌بخشید و اطمینان حاصل می‌کنید که LLM شما هر بار مرتبط‌ترین اسناد را بازیابی می‌کند.

چرا جستجوی برداری خالص ناکافی است

جاسازی‌های برداری معنای متن را به دست می‌آورند. آن‌ها در درک اینکه «بلیت‌های ارزان» و «هزینه پایین بلیت هواپیما» مشابه هستند عالی عمل می‌کنند. با این حال، آن‌ها در فضایی با ابعاد بالا عمل می‌کنند که در آن تطبیق دقیق رشته‌ها وجود ندارد.

  • فقدان خاصیت: بردارها نمی‌توانند بین «قطعه A» و «قطعه B» تمایز قائل شوند اگر در زمینه‌های مشابه ظاهر شوند.
  • مشکلات توکن‌سازی: شناسه‌های منحصربه‌فرد، کدهای محصول یا نام‌های خاص نادر ممکن است به دلیل فقدان فراوانی زمینه‌ای در داده‌های آموزشی، نمایش‌های جاسازی ضعیفی داشته باشند.
  • شکاف‌های فراخوانی: اگر یک پرسش حاوی کلمه کلیدی باشد که از نظر معنایی از سند هدف دور است اما از نظر واژگانی یکسان است، جستجوی برداری آن را از دست می‌دهد.

در مقابل، جستجوی کلمات کلیدی سنتی (مانند BM25) در یافتن تطبیقات دقیق عالی است اما درک نیت را از دست می‌دهد. نمی‌تواند تشخیص دهد که «چگونه لوله نشتی را تعمیر کنم» و «تعمیرات لوله‌کشی برای شیرآلات» مرتبط هستند مگر اینکه کلمات تداخل داشته باشند.

معماری جستجوی ترکیبی

یک خط لوله جستجوی ترکیبی معمول شامل سه مرحله اصلی است:

  1. بازیابی چگال: جاسازی پرسش و بازیابی نتایج برتر-K بر اساس شباهت کسینوس.
  2. بازیابی پراکنده: استفاده از یک موتور جستجوی سنتی (مانند Elasticsearch، جستجوی متن کامل PostgreSQL) برای بازیابی نتایج برتر-K بر اساس تداخل واژگانی (BM25).
  3. ادغام: ترکیب دو مجموعه نتیجه با استفاده از الگوریتم رتبه‌بندی مانند ادغام رتبه متقابل (RRF).

نمونه پیاده‌سازی

در زیر یک نمونه پایتون با استفاده از LangChain و Chroma (برای بردارها) همراه با یک پیاده‌سازی ساده BM25 آورده شده است. در محیط تولید، ممکن است از Elasticsearch یا OpenSearch برای بخش پراکنده استفاده کنید.

import numpy as np
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.retrievers import ParentDocumentRetriever
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. Setup Vector Store (Dense Search)
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_texts(texts, embeddings=embeddings)
vector_retriever = vectorstore.as_retriever(k=5)

# 2. Setup Sparse Search (BM25)
# Note: In a real app, you'd use Elasticsearch or a TF-IDF/BM25 index
def bm25_search(query, documents, top_k=5):
    # Pseudo-code for BM25 ranking
    # Returns list of (document_id, score)
    pass

def reciprocal_rank_fusion(rank_lists, k=60):
    """
    Fuses multiple ranked lists into a single ranked list.
    k is a constant (typically 60) to dampen the impact of lower-ranked items.
    """
    scores = {}
    for i, rank_list in enumerate(rank_lists):
        for rank, item in enumerate(rank_list, start=1):
            if item not in scores:
                scores[item] = 0
            scores[item] += 1.0 / (k + rank)
    
    # Sort by score descending
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

# 3. Hybrid Retrieval Function
def hybrid_search(query, documents):
    # Get results from vector search
    vector_results = vector_retriever.get_relevant_documents(query)
    vector_ids = [doc.metadata['id'] for doc in vector_results]
    
    # Get results from BM25
    bm25_results = bm25_search(query, documents, top_k=5)
    bm25_ids = [res[0] for res in bm25_results]
    
    # Fuse results
    fused_ids, fused_scores = reciprocal_rank_fusion([vector_ids, bm25_ids])
    
    # Return top 3 documents
    return fused_ids[:3]

نکات عملی برای تنظیم

  • وزن‌دهی: می‌توانید وزن‌هایی را به فرمول RRF اعمال کنید اگر یکی از روش‌های جستجو از نظر تاریخی برای حوزه شما قابل‌اتکا‌تر باشد. برای مثال، اگر اسناد فنی به شدت به شماره‌های قطعات وابسته هستند، وزن جستجوی پراکنده را بالاتر قرار دهید.
  • مدل‌های جاسازی: از مدل‌های جاسازی جدیدتر و با عملکرد بالا (مانند text-embedding-3-large) استفاده کنید تا کیفیت بخش جستجوی چگال را به حداکثر برسانید.
  • شاخص‌سازی: اطمینان حاصل کنید که شاخص پراکنده شما بهینه شده است. از n-grams یا لیست‌های مترادف در پیکربندی موتور جستجوی خود برای مدیریت مؤثر مخفف‌ها و جمع‌ها استفاده کنید.

نتیجه‌گیری

جستجوی ترکیبی دیگر یک بهبود اختیاری برای سیستم‌های RAG نیست؛ بلکه یک بهترین عمل برای برنامه‌های سطح تولید است. با پل زدن بر شکاف بین درک معنایی و دقت واژگانی، لایه‌ای از بازیابی ایجاد می‌کنید که هم مقاوم و هم دقیق است. با یک ادغام RRF ساده از جستجوهای برداری و کلمات کلیدی موجود خود شروع کنید، بهبود کیفیت پاسخ‌ها را اندازه‌گیری کنید و از آنجا تکرار کنید. نتیجه یک سیستم خواهد بود که واقعاً داده‌های شما را درک می‌کند—چه در حال پرسیدن معنای یک مفهوم باشد یا شناسه دقیق یک قطعه.

Share: