Agent Frameworks

پیاده‌سازی استراتژی‌های جستجوی ترکیبی و مرتب‌سازی مجدد در Haystack برای RAG با دقت بالا

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

محدودیت‌های بازیابی تک‌استراتژی

بیشتر پیاده‌سازی‌های اولیه RAG یا بر بازیابی پراکنده (مانند BM25) یا بازیابی چگال (با استفاده از جاسازی‌هایی مانند Sentence-BERT) متکی هستند. هر کدام از این‌ها نقاط کور متمایزی دارند.

  • بازیابی پراکنده (BM25): در تطبیق دقیق کلمات کلیدی و درک نام‌های خاص موجودیت‌ها، کدها یا اصطلاحات فنی برتری دارد. با این حال، در درک شباهت معنایی یا بازنویسی شکست می‌خورد.
  • بازیابی چگال (جاسازی‌ها): معنای معنایی و زمینه را به خوبی درک می‌کند و به آن اجازه می‌دهد سندهایی را پیدا کند که همان مفهوم را با کلمات متفاوت بحث می‌کنند. با این حال، اغلب در شناسایی شناسه‌های منحصربه‌فرد، SKUهای خاص محصولات یا اصطلاحات فنی نادر دچار مشکل می‌شود.

با استفاده از فقط یکی از این‌ها، یا دقت را برای اصطلاحات خاص یا فراخوانی را برای تغییرات معنایی فدا می‌کنید. جستجوی ترکیبی هر دو سیگنال را ترکیب می‌کند تا این ضعف‌ها را کاهش دهد.

ساخت یک بازیاب ترکیبی در Haystack

چارچوب Haystack یک انتزاع ظریف برای ترکیب بازیاب‌ها ارائه می‌دهد. شما می‌توانید یک BM25Retriever و یک EmbeddingRetriever را به صورت موازی هماهنگ کنید و سپس نتایج آن‌ها را ترکیب نمایید.


from haystack import Pipeline
from haystack.components.retrievers.in_memory import BM25Retriever, EmbeddingRetriever
from haystack.components.routers import SwitchRouter
from haystack.components.joiners import DocumentJoiner
from haystack.components.builders import DocumentJoiner

# Initialize Retriever Components
# Note: In a real pipeline, you would connect these to your InMemoryDocumentStore
bm25_retriever = BM25Retriever(document_store, top_k=20)
embedding_retriever = EmbeddingRetriever(document_store, top_k=20)

# Initialize the Joiner
# This component merges documents from both retrievers
# The score_type determines how scores are combined (e.g., 'distributional', 'arithmetic')
doc_joiner = DocumentJoiner(
    join_mode="concatenate",
    duplicate_documents="skip",
    score_normalization="min_max",
    score_threshold=0.3
)

# Construct the Hybrid Search Pipeline
pipeline = Pipeline()
pipeline.add_component("bm25", bm25_retriever)
pipeline.add_component("embedding", embedding_retriever)
pipeline.add_component("joiner", doc_joiner)

# Connect the components
# Both retrievers run in parallel, and their outputs are fed into the joiner
pipeline.connect("bm25", "joiner")
pipeline.connect("embedding", "joiner")

در این پیکربندی، خط لوله همزمان از هر دو شاخص پرس‌وجو می‌کند. سپس DocumentJoiner فهرست سندها را ادغام می‌کند. نکته حیاتی این است که باید امتیازات را نرمال کنید، زیرا امتیازات BM25 (که نامحدود و وابسته به پرس‌وجو هستند) و امتیازات شباهت کسینوسی (که بین -1 و 1 محدود شده‌اند) به طور مستقیم قابل مقایسه نیستند. استفاده از score_normalization="min_max" هر دو مجموعه امتیاز را به یک محدوده مشترک مقیاس می‌کند و امکان رقابت منصفانه در فرآیند ادغام را فراهم می‌آورد.

نقش حیاتی مرتب‌سازی مجدد

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

مرتب‌سازها از مدل‌های Cross-Encoder استفاده می‌کنند. برخلاف Bi-Encoders که در بازیابی برداری استفاده می‌شوند (که پرس‌وجو و سند را به صورت مستقل کدگذاری می‌کنند)، Cross-Encoders پرس‌وجو و سند را در یک سر توجه واحد پردازش می‌کنند. این به مدل اجازه می‌دهد تعامل عمیق در سطح توکن را انجام دهد و امتیاز مرتبط بودن دقیق‌تری ارائه دهد.

یکپارچه‌سازی یک مرتب‌ساز در خط لوله

ما یک SentenceTransformersReRanker یا یک مرتب‌ساز مبتنی بر API اختصاصی (مانند Cohere یا Jina) را به انتهای مرحله بازیابی اضافه می‌کنیم. مرتب‌ساز N سند بالای ترکیبی از جستجوی ترکیبی را دریافت می‌کند و آن‌ها را مجدداً مرتب می‌کند و فقط K مورد مرتبط‌ترین را برای تولیدکننده انتخاب می‌کند.


from haystack.components.rerankers import TransformersSimilarityRanker

# Initialize Re-Ranker
# Use a strong cross-encoder model for best performance
re_ranker = TransformersSimilarityRanker(
    model="cross-encoder/ms-marco-MiniLM-L-6-v2",
    top_k=5,
    batch_size=16
)

# Update the Pipeline
pipeline.add_component("re_ranker", re_ranker)

# Connect the joiner to the re-ranker
pipeline.connect("joiner", "re_ranker")

با تنظیم top_k=5 در مرتب‌ساز، ما زمینه ارسالی به LLM را به شدت کاهش می‌دهیم. به جای ارسال 40 سند بالقوه پر از نویز، فقط 5 سندی را ارسال می‌کنیم که کراس‌انکودر آن‌ها را به عنوان بسیار مرتبط تأیید کرده است. این معمولاً منجر به بهبود قابل اندازه‌گیری در دقت پاسخ و کاهش تأخیر به دلیل اندازه کوچک‌تر پرامپت می‌شود.

ملاحظات عملی و بهینه‌سازی

پیاده‌سازی این معماری نیاز به تعادل بین چندین عامل دارد:

  1. استراتژی تکه‌بندی: اطمینان حاصل کنید که سندها قبل از شاخص‌گذاری به درستی تکه‌بندی شده‌اند. اگر تکه‌ها خیلی بزرگ باشند، مرتب‌ساز ممکن است در یافتن جمله خاص مرتبط مشکل داشته باشد. اگر خیلی کوچک باشند، زمینه را از دست می‌دهید. محدوده 200 تا 500 توکن با 10 تا 20 درصد همپوشانی نقطه شروع خوبی است.
  2. آستانه‌های امتیازدهی: از خروجی مرتب‌ساز برای فیلتر کردن تطبیق‌های ضعیف استفاده کنید. اگر بالاترین امتیاز پس از مرتب‌سازی مجدد زیر یک آستانه خاص (مثلاً 0.4 برای امتیازات نرمال شده) باشد، اغلب بهتر است سیستم بپذیرد «نمی‌دانم» تا اینکه بر اساس شواهد ضعیف پاسخ توهمی ارائه دهد.
  3. انتخاب مدل: برای محیط‌های تولیدی، در نظر بگیرید از APIهای مرتب‌ساز میزبانی شده (مانند Rerank Cohere یا Reranker Jina AI) استفاده کنید تا هزینه محاسباتی کراس‌کدگذاری را از زیرساخت محلی خود بردارید، به ویژه برای سیستم‌های با پهنای باند بالا.

نتیجه‌گیری

RAG با دقت بالا یک ترفند جادویی نیست؛ بلکه نتیجه مهندسی یک خط لوله بازیابی مقاوم است. با بهره‌گیری از معماری مبتنی بر اجزای Haystack، می‌توانید جستجوی ترکیبی را به طور بی‌دردی یکپارچه کنید تا هم سیگنال‌های معنایی و هم واژگانی را درک کند، و سپس یک مرتب‌ساز کراس‌انکودر را اضافه کنید تا اطمینان حاصل شود که فقط زمینه‌های بسیار مرتبط به LLM می‌رسند. این رویکرد چندمرحله‌ای به طور قابل توجهی توهم‌ها را کاهش می‌دهد و دقت فکتی برنامه‌های هوش مصنوعی شما را بهبود می‌بخشد و یک چت‌بات ساده را به یک دستیار دانش سازمانی قابل اعتماد تبدیل می‌کند.

Share: