增強 RAG:選擇最佳的嵌入和重排模型

對於如何選擇最佳的嵌入模型和重排模型,給出了詳細的步驟和代碼。

在構建檢索增強生成(RAG)管道時,關鍵組件之一是檢索器。我們有多種嵌入模型可供選擇,包括 OpenAI、CohereAI 和開源的 sentence transformers。此外,還有來自 CohereAI 和 sentence transformers 的幾種重排器可供選擇。

但是,在所有這些選項中,我們如何確定最佳組合以獲得頂級的檢索性能?我們如何知道哪個嵌入模型最適合我們的數據?或者哪個重排器最能提升我們的結果?

在這篇博客文章中,我們將使用 LlamaIndex 的 檢索評估 模塊迅速確定嵌入模型和重排器模型的最佳組合。讓我們開始吧!

讓我們首先了解 檢索評估 中可用的指標。

理解檢索評估中的指標

爲了衡量我們檢索系統的效率,我們主要依賴於兩個廣泛接受的指標:命中率平均倒數排名(MRR)。讓我們深入這些指標,瞭解它們的重要性以及它們的工作原理。

命中率:

命中率計算在查詢中正確答案出現在檢索到的前 k 個文檔中的比例。簡單來說,它關乎我們的系統在前幾個猜測中正確答案出現的頻率。

平均倒數排名(MRR):

對於每個查詢,MRR 通過查看最相關文檔的最高排名來評估系統的準確性。具體來說,它是所有查詢中這些排名倒數的平均值。因此,如果第一個相關文檔是頂部結果,倒數排名就是 1;如果是第二個,倒數排名就是 1/2,以此類推。

現在我們已經確定了範圍並熟悉了這些指標,是時候深入實驗了。爲了獲得實踐經驗,您也可以通過我們的 Google Colab Notebook 進行操作。

設置環境

!pip install llama-index sentence-transformers cohere anthropic voyageai protobuf pypdf

設置 Keys

openai_api_key = 'YOUR OPENAI API KEY'
cohere_api_key = 'YOUR COHEREAI API KEY'
anthropic_api_key = 'YOUR ANTHROPIC API KEY'
openai.api_key = openai_api_key

下載數據

我們在此實驗中使用 Llama2 論文,我們下載這篇論文。

!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2307.09288.pdf" -O "llama2.pdf"

加載數據

讓我們加載數據。我們將使用第 36 頁之前的內容進行實驗,這排除了目錄、參考文獻和附錄。

然後,這些數據被解析並轉換爲節點,這些節點代表我們想要檢索的數據塊。我們使用了 512 作爲塊大小。

documents = SimpleDirectoryReader(input_files=["llama2.pdf"]).load_data()

node_parser = SimpleNodeParser.from_defaults(chunk_size=512)
nodes = node_parser.get_nodes_from_documents(documents)

生成問題 - 上下文對

爲了評估目的,我們創建了一個問答對數據集。這個數據集可以被看作是我們數據中的一組問題及其相應的上下文。爲了在評估嵌入(OpenAI/CohereAI)和重排器(CohereAI)時消除偏見,我們使用 Anthropic LLM 生成問答對。

讓我們初始化一個提示模板來生成問答對。

# Prompt to generate questions
qa_generate_prompt_tmpl = """\
Context information is below.

---------------------
{context_str}
---------------------

Given the context information and not prior knowledge.
generate only questions based on the below query.

You are a Professor. Your task is to setup \
{num_questions_per_chunk} questions for an upcoming \
quiz/examination. The questions should be diverse in nature \
across the document. The questions should not contain options, not start with Q1/ Q2. \
Restrict the questions to the context information provided.\
"""
llm = Anthropic(api_key=anthropic_api_key)
qa_dataset = generate_question_context_pairs(
    nodes, llm=llm, num_questions_per_chunk=2
)

過濾掉類似這樣的句子的函數— Here are 2 questions based on provided context

# function to clean the dataset
def filter_qa_dataset(qa_dataset):
    """
    Filters out queries from the qa_dataset that contain certain phrases and the corresponding
    entries in the relevant_docs, and creates a new EmbeddingQAFinetuneDataset object with
    the filtered data.

    :param qa_dataset: An object that has 'queries', 'corpus', and 'relevant_docs' attributes.
    :return: An EmbeddingQAFinetuneDataset object with the filtered queries, corpus and relevant_docs.
    """

    # Extract keys from queries and relevant_docs that need to be removed
    queries_relevant_docs_keys_to_remove = {
        k for k, v in qa_dataset.queries.items()
        if 'Here are 2' in v or 'Here are two' in v
    }

    # Filter queries and relevant_docs using dictionary comprehensions
    filtered_queries = {
        k: v for k, v in qa_dataset.queries.items()
        if k not in queries_relevant_docs_keys_to_remove
    }
    filtered_relevant_docs = {
        k: v for k, v in qa_dataset.relevant_docs.items()
        if k not in queries_relevant_docs_keys_to_remove
    }

    # Create a new instance of EmbeddingQAFinetuneDataset with the filtered data
    return EmbeddingQAFinetuneDataset(
        queries=filtered_queries,
        corpus=qa_dataset.corpus,
        relevant_docs=filtered_relevant_docs
    )

# filter out pairs with phrases `Here are 2 questions based on provided context`
qa_dataset = filter_qa_dataset(qa_dataset)

自定義檢索器

爲了確定最優的檢索器,我們採用了嵌入模型和重排器的組合。最初,我們建立了一個基礎的 VectorIndexRetriever。檢索節點後,我們引入了重排器來進一步優化結果。值得注意的是,在這個特定的實驗中,我們將 similarity_top_k 設置爲 10,並選擇了重排器的前 5 個結果。然而,您可以根據您特定實驗的需求自由調整此參數。我們在這裏展示了使用 OpenAIEmbedding 的代碼,請參考 notebook 中其他嵌入模型的代碼。

embed_model = OpenAIEmbedding()
service_context = ServiceContext.from_defaults(llm=None, embed_model = embed_model)
vector_index = VectorStoreIndex(nodes, service_context=service_context)
vector_retriever = VectorIndexRetriever(index=vector_index, similarity_top_k = 10)
class CustomRetriever(BaseRetriever):
    """Custom retriever that performs both Vector search and Knowledge Graph search"""

    def __init__(
        self,
        vector_retriever: VectorIndexRetriever,
    ) -> None:
        """Init params."""

        self._vector_retriever = vector_retriever

    def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        """Retrieve nodes given query."""

    retrieved_nodes = self._vector_retriever.retrieve(query_bundle)

    if reranker != 'None':
      retrieved_nodes = reranker.postprocess_nodes(retrieved_nodes, query_bundle)
       else:
          retrieved_nodes = retrieved_nodes[:5]
         
       return retrieved_nodes

    async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        """Asynchronously retrieve nodes given query.

        Implemented by the user.

        """
        return self._retrieve(query_bundle)

    async def aretrieve(self, str_or_query_bundle: QueryType) -> List[NodeWithScore]:
        if isinstance(str_or_query_bundle, str):
            str_or_query_bundle = QueryBundle(str_or_query_bundle)
        return await self._aretrieve(str_or_query_bundle)

custom_retriever = CustomRetriever(vector_retriever)

評估

爲了評估我們的檢索器,我們計算了平均倒數排名(MRR)和命中率這兩個指標:

retriever_evaluator = RetrieverEvaluator.from_metric_names(
    ["mrr""hit_rate"]retriever=custom_retriever
)
eval_results = await retriever_evaluator.aevaluate_dataset(qa_dataset)

結果

我們將各種嵌入模型和重排器進行了測試。以下是我們考慮的模型:

嵌入模型:

重排器::

值得一提的是,這些結果爲這個特定數據集和任務提供了深入的性能洞察。然而,實際結果可能會因數據特性、數據集大小以及其他變量(如 chunk_size、similarity_top_k 等)而有所不同。

下面的表格展示了基於命中率和平均倒數排名(MRR)指標的評估結果:

複製再試一次分享

分析:

按嵌入模型的性能:

重排器的影響:

重排器的必要性:

總體優勢:

總結來說,爲了在命中率和 MRR 上達到最佳性能,OpenAI 或 JinaAI-Base 嵌入與 CohereRerank/bge-reranker-large 重排器的組合顯得尤爲突出。

請注意,我們的基準測試旨在爲你自己的數據提供一個可復現的腳本。儘管如此,請將這些數字視爲估計值,並在解釋它們時謹慎行事。

結論:

在這篇博客文章中,我們展示瞭如何使用不同的嵌入模型和重排器來評估和增強檢索器的性能。以下是我們的最終結論。

這些結論強調了在構建高效的檢索系統時,嵌入模型和重排器選擇的重要性,以及它們如何協同工作以提供最佳的搜索結果。

原文:https://www.llamaindex.ai/blog/boosting-rag-picking-the-best-embedding-reranker-models-42d079022e83
作者:Ravi Theja

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/nqAqbYciJKkzL78RE4DhLA