Search⌘ K
AI Features

استخدام RAG-Fusion لتحسين السياق

تعرف على مفهوم إعادة الترتيب، بما في ذلك التقنيات مثل RAG-Fusion، واستكشف تنفيذه خطوة بخطوة.

لنفترض أننا نبحث عن معلومات عبر الإنترنت. نكتب استعلامنا، فيُظهر النظام قائمة بالنتائج. ولكن هل هي حقًا الأكثر صلة؟ غالبًا ما تُعطي خوارزميات الترتيب التقليدية الأولوية لعوامل مثل مطابقة الكلمات المفتاحية، مما قد يُغفل المعنى الأعمق لبحثك. وهنا يأتي دور إعادة الترتيب.

ما هو إعادة الترتيب؟

إعادة الترتيب هي عملية استرجاع من مرحلتين تُحسّن صلة نتائج البحث. إليك كيفية عملها:

  • الاسترجاع الأولي: يقوم النظام الأساسي، مثل محرك البحث، باسترجاع مجموعة كبيرة من العناصر ذات الصلة المحتملة استنادًا إلى الكلمات الرئيسية أو عوامل أخرى.

  • تحسين القائمة: يقوم نموذج إعادة الترتيب، الذي يعتمد غالبًا على التعلم الآلي، بتحليل كل عنصر في المجموعة ويمنحه درجة جديدة بناءً على صلته صحيح باستعلام المستخدم. يمكن لهذه الدرجة أن تأخذ في الاعتبار عوامل مثل التشابه الدلالي وسياق المستخدم.

  • النتائج المعاد ترتيبها: أخيرًا، يتم إعادة ترتيب العناصر استنادًا إلى درجاتها الجديدة، مع عرض النتائج الأكثر صلة في الأعلى.

أنواع تقنيات إعادة الترتيب

يمكن استخدام العديد من التقنيات المبتكرة لإعادة ترتيب نتائج البحث. دعونا نستكشف نهجين بارزين:

  • دمج التوليد المعزز بالاسترجاع (RAG-Fusion): تجمع هذه التقنية بين نموذجين: مُسترجع يبحث عن مستندات ذات صلة محتملة، ونموذج توليد يفهم غرض الاستعلام. يستفيد RAG-Fusion من نقاط قوة كليهما، وغالبًا ما يستخدم مُعيد ترتيب لتحسين الاختيار النهائي للمستندات التي سيُعالجها النموذج التوليدي.

  • إعادة ترتيب المُرمِّز المتقاطع: هنا، يأخذ نموذج مُنفصل يُسمى "المُرمِّز المتقاطع" الاستعلام وكل عنصر مُسترجع إدخال. ثم يُخرِج درجة تُشير إلى مدى مُطابقة العنصر لنية المستخدم. تُعيد هذه الدرجة ترتيب القائمة الأولية وتُعرِض العناصر الأكثر تشابهًا دلاليًا في الأعلى.

ما هو RAG-Fusion؟

يجمع RAG-Fusion بين الاسترجاع (العثور على المستندات ذات الصلة) والتوليد (صياغة الاستعلامات). ويعتمد على برنامج ماجستير في إدارة الأعمال لإنشاء هذه الاستعلامات المتنوعة بناءً على سؤال المستخدم الأصلي. باستخدام برنامج ماجستير في إدارة الأعمال، يستطيع RAG-Fusion استيعاب الفروق الدقيقة في اللغة وإنشاء استعلامات تُمثل قصد المستخدم بفعالية.

RAG-Fusion هي تقنية تعتمد على نماذج RAG لتحسين نتائج البحث، خاصةً في سياق برامج الدردشة الآلية. إليك شرح لكيفية عملها:

  • فهم نية المستخدم: يبدأ RAG-Fusion باستعلام المستخدم. وكما هو الحال في نماذج RAG، يهدف إلى فهم النية صحيح وراء السؤال.

  • إنشاء استعلامات متعددة: يتجاوز RAG-Fusion مجرد استعلام واحد، إذ يستخدم الاستعلام الأصلي لإنشاء صيغ متعددة، ما يُعيد صياغة السؤال من زوايا مختلفة. يُساعد هذا على فهم قصد المستخدم بدقة.

  • الاسترجاع مع التضمين: تُحوَّل الاستعلامات الأصلية والمُولَّدة إلى تمثيل رقمي باستخدام نماذج التضمين. يتيح ذلك بحثًا فعّالاً ضمن مجموعة مستندات أو قاعدة معارف. يتم استرجاع المستندات ذات الصلة بكل استعلام.

  • دمج الرتب التبادلي (RRF): يستخدم RAG-Fusion تقنية دمج الرتب التبادلي (RRF). تُحدد RRF الدرجات بناءً على مدى تطابق المستندات المُسترجعة مع كل استعلام. من المرجح أن تكون المستندات ذات الدرجات العالية عبر استعلامات متعددة أكثر ملاءمةً لهدف المستخدم.

  • دمج المستندات والنتائج: أخيرًا، يجمع RAG-Fusion المستندات المسترجعة ونتائجها المقابلة. هذا يوفر مجموعة أغنى من المعلومات التي يمكن استخدامها لصياغة استجابة.

The high level workflow of RAG-Fusion technique
The high level workflow of RAG-Fusion technique

التنفيذ خطوة بخطوة

الآن، لنبدأ بتطبيق RAG-Fusion. الخطوات الخمس الأولى مشابهة لتقنية الاستعلامات المتعددة:

Steps for implementing RAG-Fusion
Steps for implementing RAG-Fusion

تعتبر هذه المكتبات والوحدات ضرورية للخطوات اللاحقة في العملية.

1. استيراد المكتبات الضرورية

سنقوم باستيراد الوحدات المطلوبة من المكتبات المثبتة لتنفيذ الاستعلامات المتعددة:

Python 3.10.4
import os
import bs4
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from operator import itemgetter
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough

2. إعداد مفاتيح API بـ LangSmith و OpenAI

يُنشئ مقتطف الكود التالي مفتاح API الخاص بـ LangChain مفتاح API OpenAI من متغيرات البيئة. سنحتاج إلى مفاتيح API صالحة للتفاعل مع نماذج لغة LangChain و OpenAI :

Python 3.10.4
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
os.environ['LANGCHAIN_ENDPOINT'] = 'https://api.smith.langchain.com'
os.environ['LANGCHAIN_API_KEY'] = '' # Add your LangSmith LangChain API key
os.environ['LANGCHAIN_PROJECT']='RAG-Fusion'
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"] = "" # Add your OpenAI API key
if OPENAI_API_KEY == "":
raise ValueError("Please set the OPENAI_API_KEY environment variable")

شرح الكود:

  • الأسطر 1-4: إعداد متغيرات بيئة LangChain:

    • LANGCHAIN_TRACING_V2 : يمكّن التتبع لعمليات LangChain.

    • LANGCHAIN_ENDPOINT : يحدد نقطة النهاية لواجهة API LangChain.

    • LANGCHAIN_API_KEY : عنصر نصي فارغ مفتاح واجهة API LangSmith LangChain. استبدله مفتاح الحالي.

    • LANGCHAIN_PROJECT : يضبط اسم المشروع لعمليات LangChain إلى'RAG-Fusion' .

  • الأسطر 6-8: إعداد مفتاح API OpenAI :

    • OPENAI_API_KEY : نص فارغ مفتاح API OpenAI . استبدله مفتاح الحالي.

    • التحقق: التحقق مما إذا كانOPENAI_API_KEY فارغ ويثيرValueError إذا كان الأمر كذلك، فتأكد من توفير مفتاح API صالح لمصادقة طلبات API OpenAI .

3. تحميل المستندات وتقسيمها

الآن، دعنا نحمل مستندات النصوص التي تريد استخدامها للاسترجاع ونقسمها:

Python 3.10.4
loaders = [
TextLoader("blog.langchain.dev_announcing-langsmith_.txt"),
TextLoader("blog.langchain.dev_automating-web-research_.txt"),
]
docs = []
for loader in loaders:
docs.extend(loader.load())
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=400, chunk_overlap=60)
splits = text_splitter.split_documents(docs)

شرح الكود:

  • الأسطر من 1 إلى 4: يتم تعريف المحملات لقراءة ملفات النصوص باستخدامTextLoader ، تحديد مسارات الملفات للمستندات التي سيتم تحميلها.

  • الأسطر 6-8: قائمة فارغةdocs يتم إنشاء حلقة، ويتم تكرارها عبر المحملات، وتحميل محتوى كل مستند وتوسيعهdocs قائمة بالمحتوى المحمل.

  • Lines 10–11: A RecursiveCharacterTextSplitter is initialized with a chunk size of 400400 characters and an overlap of 6060 characters between chunks. The splitter then processes the docs list, splitting each document into smaller chunks suitable for processing by large language models (LLMs).

4. فهرسة الوثائق

بعد تقسيم النص، نُنشئ مخزن متجهات لتخزين واسترجاع أجزاء المستند بكفاءة. بالإضافة إلى ذلك، نُنشئ تضمينات لكل جزء لالتقاط معناه الدلالي.

Python 3.10.4
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()

شرح الكود:

  • السطر 1: نستخدمChroma لإنشاء متجر المتجهات (vectorstore كروما هي مكتبة مصممة لتخزين واسترجاع المستندات بكفاءة. ثم نسميهاfrom_documents لملء المتجر بقطع النصوص التي قمنا بإعدادها (splits ). لفهم معنى كل جزء، نقوم بإنشاء تضمينات باستخدامOpenAIEmbeddings التضمينات هي تمثيلات رقمية تلتقط العلاقات الدلالية بين الكلمات في مقتطف نصي. هذا يسمح لمخزن المتجهات باسترجاع المستندات ذات الصلة باستعلام المستخدم بكفاءة من خلال مقارنة تضمين الاستعلام بتضمينات الكتل المخزنة.

  • الخط 2: نقوم بتحويل مخزن المتجهات إلى مسترد باستخدامas_retriever() . وهذا يسمح لنا باسترجاع المستندات استنادًا إلى استعلام التضمين.

5. RAG-Fusion: إنشاء الاستعلامات

يتطرق مقتطف التعليمات البرمجية التالي إلى المفهوم الأساسي لـ RAG-Fusion: إنشاء أشكال استعلام متعددة استنادًا إلى السؤال الأصلي للمستخدم.

Python 3.10.4
template = """You are an AI language model assistant tasked with generating seach queries for a vector search engine.
The user has a question: "{question}"
Your goal/task is to create five variations of this {question} that capture different aspects of the user's intent. These variations will help the search engine retrieve relevant documents even if they don't use the exact keywords as the original question.
Provide these alternative questions, each on a new line.**
Original question: {question}"""
rag_fusion_prompt_template = ChatPromptTemplate.from_template(template)
generate_queries = (
rag_fusion_prompt_template
| ChatOpenAI(temperature=0)
| StrOutputParser()
| (lambda x: x.split("\n"))
)

شرح الكود:

  • الأسطر من 1 إلى 5: نقوم بتعريف متغير سلسلة متعدد الأسطرtemplate يعمل هذا كموجه لبرنامج LLM (ChatOpenAI في هذه الحالة). يُرشد هذا الموجه برنامج LLM للعمل كمساعد لمحرك بحث متجه. كما يوفر سياقًا لسؤال المستخدم ({question} ) والهدف من إنشاء استعلامات بديلة (five variations يجب أن تعكس هذه الاختلافات جوانب مختلفة من نية المستخدم لتحسين الاسترجاع. كما يحدد الموجه تنسيق إخراج المطلوب: كل اختلاف في سطر جديد، يتبع"Original question: {question}" شكل.

  • السطر 7: نستخدمChatPromptTemplate.from_template(template) لتحويل قالب السلسلة إلى قالب منظمChatPromptTemplate هدف.

  • الأسطر 9-14: نقوم بإنشاء سلسلة معالجة تسمىgenerate_queries تتضمن هذه السلسلة عدة خطوات:

    • الخطوة الأولى تتضمنrag_fusion_prompt_template هدف.

    • ثم تستخدم السلسلةChatOpenAI(temperature=0) . يشير ChatOpenAI إلى نموذج لغة OpenAI وtemperature=0 يضمن إخراج حتميًا (نفس النتائج لمطالبة معينة في كل مرة).

    • يتم بعد ذلك تحليل النص الناتج من LLM باستخدامStrOutputParser() ، وتحويلها من بنية بيانات معقدة محتملة إلى سلسلة عادية.

    • وأخيرا،lambda تقوم الوظيفة بتقسيم السلسلة إلى قائمة من الاختلافات الفردية في الاستعلام باستخدام حرف السطر الجديد (\n ) كفاصل.

6. الاسترجاع باستخدام اندماج الرتبة المتبادلة (RRF)

في هذه الخطوة، سوف نقوم باسترجاع المستندات استنادًا إلى اختلافات الاستعلام المُولّدة وتحسين النتائج باستخدام Reciprocal Rank Fusion (RRF):

Python 3.10.4
def reciprocal_rank_function(results: list[list], k=60):
""" Reciprocal_rank_fusion that takes multiple lists of ranked documents
and an optional parameter k used in the RRF formula """
# Initialize a dictionary to hold fused scores for each unique document
fused_scores = {}
# Iterate through each list of ranked documents
for docs in results:
# Iterate through each document in the list, with its rank (position in the list)
for rank, doc in enumerate(docs):
# Convert the document to a unique string identifier
doc_str = str(doc) # Simple string conversion
# If the document is not yet in the fused_scores dictionary, add it with an initial score of 0
if doc_str not in fused_scores:
fused_scores[doc_str] = 0
# Retrieve the current score of the document, if any
previous_score = fused_scores[doc_str]
# Update the score of the document using the RRF formula: 1 / (rank + k)
fused_scores[doc_str] += 1 / (rank + k)
# Sort the documents based on their fused scores in descending order to get the final reranked results
reranked_results = [
(doc, score)
for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
]
# Return the reranked results as a list of tuples, each containing the document and its fused score
return reranked_results
question = "What is LangSmith, and why do we need it?"
retrieval_chain = generate_queries | retriever.map() | reciprocal_rank_function
docs = retrieval_chain.invoke({"question":question})
len(docs)

شرح الكود:

  • الأسطر من 1 إلى 29: دالة اندماج الرتبة المتبادلة

    • Line 1: Define the function reciprocal_rank_function, which takes a list of lists (results) containing ranked documents and an optional parameter k (default value is 6060).

    • السطر 6: تهيئة قاموس فارغfused_scores لتخزين النتائج التراكمية لكل مستند فريد تم مواجهته أثناء عملية الدمج.

    • الأسطر 9: ابدأ بالتكرار على كل قائمة من المستندات المصنفة (docs ) فيresults قائمة.

    • السطر 11: لكل قائمة من المستندات، قم بالتكرار خلال كل مستند (doc ) ورتبتها المقابلة (rank ) باستخدامenumerate وظيفة.

    • السطر 13: تحويل المستند إلى معرف سلسلة فريد (doc_str ) استخدامstr(doc) .

    • Lines 15-16: Check if the document is already in the fused_scores dictionary. If not, add it with an initial score of 00.

    • السطر 18: استرداد النتيجة الحالية للمستند منfused_scores قاموس.

    • السطر 20: تحديث درجة المستند باستخدام صيغة RRF:1 / (rank + k) . أضف هذه قيمة إلى النتيجة الحالية فيfused_scores قاموس.

    • الأسطر 23-26: بعد معالجة جميع المستندات، قم بفرزهاfused_scores قاموس قائم على النتائج مرتبة تنازليًا. خزّن النتائج المفرزة كقائمة من الثنائيات (reranked_results ), كل منها يحتوي على الوثيقة ونتيجتها المدمجة.

    • السطر 29: إرجاعreranked_results قائمة توفر المستندات التي تمت إعادة ترتيبها ونتائجها المدمجة.

  • السطر 31: حدد سؤال المستخدم (question ) مثل"What is LangSmith, and why do we need it?" لتكون بمثابة مثال لعملية الاسترجاع.

  • السطر 32: إنشاءretrieval_chain من خلال الجمع بين عدة مكونات باستخدام الأنبوب (| ) المشغل:

    • generate_queries :يُنشئ تنويعات متعددة للاستعلام.

    • retriever.map() :يتم تطبيق كل تنوع في الاستعلام على مسترد المستندات، مما يؤدي إلى استرداد قائمة مرتبة من المستندات لكل استعلام.

    • reciprocal_rank_function :يجمع ويعيد ترتيب المستندات المسترجعة استنادًا إلى درجاتها عبر جميع أشكال الاستعلام المختلفة.

  • السطر 33: استدعاءretrieval_chain مع سؤال المستخدم المقدم في القاموس ({"question": question} ). يؤدي هذا إلى تشغيل عملية الاسترجاع وRRF بأكملها، وتخزين المستندات الناتجة فيdocs متغير.

  • السطر 34: احسب وأرجع عدد المستندات المستردة والمُعاد ترتيبها بواسطةretrieval_chain باستخدامlen(docs) وظيفة.

بايت تعليمي: باستخدام RRF، يمكننا الاستفادة من المعلومات المستقاة من كل تنوع في الاستعلام لإنتاج مجموعة أكثر شمولاً وارتباطاً بالمستندات المسترجعة. المستندات التي تحتل مرتبة عالية باستمرار عبر تنوعات متعددة من الاستعلامات غالبًا ما تكون أكثر ارتباطًا بقصد المستخدم، حتى لو لم تتطابق تمامًا مع الكلمات الرئيسية المستخدمة في أي استعلام.

7. تشغيل نموذج RAG

يوضح مقطع الكود التالي توليد الإجابات باستخدام RAG (التوليد المعزز بالاسترجاع). باستخدام LLM، يستفيد من المستندات المسترجعة (السياق) للإجابة على سؤال المستخدم:

Python 3.10.4
template = """Answer the following question based on this context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
llm = ChatOpenAI(temperature=0)
final_rag_chain = (
{"context": retrieval_chain,
"question": itemgetter("question")}
| prompt
| llm
| StrOutputParser()
)
final_rag_chain.invoke({"question":question})

شرح الكود:

  • الأسطر من 1 إلى 4: تعريف متغير سلسلة متعدد الأسطرtemplate يعمل كموجه لنموذج اللغة (LLM). يُرشد هذا القالب نموذج اللغة (LLM) للإجابة على سؤال المستخدم ({question} ) بناءً على السياق المقدم ({context} ). سيتكون السياق من المستندات المسترجعة ذات الصلة بالسؤال.

  • السطر 6: تحويل قالب السلسلة إلى قالب منظمChatPromptTemplate كائن باستخدامChatPromptTemplate.from_template(template) .

  • السطر 8: قم بتهيئة LLM باستخدامChatOpenAI بدرجة حرارة 0، مما يضمن إخراج حتميًا (نفس النتائج لمطالبة معينة في كل مرة).

  • الأسطر من 10 إلى 16: إنشاء سلسلة معالجة جديدة باسمfinal_rag_chain باستخدام الأنبوب (| ) المشغل، والذي يتضمن عدة مكونات:

    • السطرين 11-12: يتم استخدام القاموس لتوفير مدخلين:

      • "context" : يشير إلى إخراجretrieval_chain ، تحتوي على المستندات المسترجعة.

      • "question" :يستعيد سؤال المستخدم باستخدامitemgetter("question") وظيفة منoperator وحدة.

    • الخط 13:prompt يحتوي الكائن على قالب إنشاء الإجابة.

    • الخط 14:llm معالجة المطالبة والسياق والسؤال لتوليد استجابة.

    • الخط 15:StrOutputParser() يقوم بتحويل إخراج LLM إلى سلسلة عادية.

  • الخط 18: اتصلfinal_rag_chain.invoke({"question": question}) ، مع توفير سؤال المستخدم إدخال. يؤدي هذا إلى بدء عملية توليد الإجابة بالكامل باستخدام المستندات المسترجعة (context ) وسؤال المستخدم. بعد معالجة السياق والسؤال، ستكون استجابة النهائية من برنامج الماجستير في القانون هي الإجابة المُولَّدة.

بايت تعليمي: من خلال الجمع بين الاسترجاع وتوليد الإجابة، يستخدم RAG المستندات المسترجعة لتوفير إجابة أكثر إعلامًا وشاملة لاستعلام المستخدم.

لانج سميث

LangSmith أداة فعّالة لاستكشاف نماذج اللغة. سنستخدمها لتصور وفهم آلية عمل استعلاماتنا.

سنفهم كيفية معالجة نموذج اللغة واستجابته لمطالباتنا من خلال فحص الاستعلامات الفرعية والمدخلات والمخرجات:

canvasAnimation-image
1 / 11

جربها بنفسك

يمكنك التدرب على تنفيذ هذا الكود بنفسك في Jupyter Notebook أدناه:

Please login to launch live app!