milvus-logo
LFAI
Home
  • Intégrations
    • Évaluation et observabilité

Évaluation avec Arize Pheonix

Open In Colab GitHub Repository

Ce guide montre comment utiliser Arize Pheonix pour évaluer un pipeline de génération assistée par récupération (RAG) construit à partir de Milvus.

Le système RAG combine un système de recherche avec un modèle génératif pour générer un nouveau texte basé sur une invite donnée. Le système récupère d'abord les documents pertinents d'un corpus à l'aide de Milvus, puis utilise un modèle génératif pour générer un nouveau texte basé sur les documents récupérés.

Arize Pheonix est un cadre qui vous aide à évaluer vos pipelines RAG. Il existe des outils et des cadres existants qui vous aident à construire ces pipelines, mais il peut être difficile de les évaluer et de quantifier leur performance. C'est là qu'Arize Pheonix intervient.

Conditions préalables

Avant d'exécuter ce notebook, assurez-vous que les dépendances suivantes sont installées :

$ pip install --upgrade pymilvus openai requests tqdm pandas "arize-phoenix>=4.29.0" nest_asyncio

Si vous utilisez Google Colab, pour activer les dépendances qui viennent d'être installées, vous devrez peut-être redémarrer le runtime (cliquez sur le menu "Runtime" en haut de l'écran, et sélectionnez "Restart session" dans le menu déroulant).

Nous utiliserons OpenAI comme LLM dans cet exemple. Vous devez préparer la clé api OPENAI_API_KEY comme variable d'environnement.

import os

# os.environ["OPENAI_API_KEY"] = "sk-*****************"

Définir le pipeline RAG

Nous allons définir la classe RAG qui utilise Milvus comme magasin de vecteurs et OpenAI comme LLM. La classe contient la méthode load, qui charge les données textuelles dans Milvus, la méthode retrieve, qui récupère les données textuelles les plus similaires à la question donnée, et la méthode answer, qui répond à la question donnée à l'aide des connaissances récupérées.

from typing import List
from tqdm import tqdm
from openai import OpenAI
from pymilvus import MilvusClient


class RAG:
    """
    RAG(Retrieval-Augmented Generation) class built upon OpenAI and Milvus.
    """

    def __init__(self, openai_client: OpenAI, milvus_client: MilvusClient):
        self._prepare_openai(openai_client)
        self._prepare_milvus(milvus_client)

    def _emb_text(self, text: str) -> List[float]:
        return (
            self.openai_client.embeddings.create(input=text, model=self.embedding_model)
            .data[0]
            .embedding
        )

    def _prepare_openai(
        self,
        openai_client: OpenAI,
        embedding_model: str = "text-embedding-3-small",
        llm_model: str = "gpt-4o-mini",
    ):
        self.openai_client = openai_client
        self.embedding_model = embedding_model
        self.llm_model = llm_model
        self.SYSTEM_PROMPT = """
            Human: You are an AI assistant. You are able to find answers to the questions from the contextual passage snippets provided.
        """
        self.USER_PROMPT = """
            Use the following pieces of information enclosed in <context> tags to provide an answer to the question enclosed in <question> tags.
            <context>
            {context}
            </context>
            <question>
            {question}
            </question>
        """

    def _prepare_milvus(
        self, milvus_client: MilvusClient, collection_name: str = "rag_collection"
    ):
        self.milvus_client = milvus_client
        self.collection_name = collection_name
        if self.milvus_client.has_collection(self.collection_name):
            self.milvus_client.drop_collection(self.collection_name)
        embedding_dim = len(self._emb_text("demo"))
        self.milvus_client.create_collection(
            collection_name=self.collection_name,
            dimension=embedding_dim,
            metric_type="IP",
            consistency_level="Strong",
        )

    def load(self, texts: List[str]):
        """
        Load the text data into Milvus.
        """
        data = []
        for i, line in enumerate(tqdm(texts, desc="Creating embeddings")):
            data.append({"id": i, "vector": self._emb_text(line), "text": line})
        self.milvus_client.insert(collection_name=self.collection_name, data=data)

    def retrieve(self, question: str, top_k: int = 3) -> List[str]:
        """
        Retrieve the most similar text data to the given question.
        """
        search_res = self.milvus_client.search(
            collection_name=self.collection_name,
            data=[self._emb_text(question)],
            limit=top_k,
            search_params={"metric_type": "IP", "params": {}},  # inner product distance
            output_fields=["text"],  # Return the text field
        )
        retrieved_texts = [res["entity"]["text"] for res in search_res[0]]
        return retrieved_texts[:top_k]

    def answer(
        self,
        question: str,
        retrieval_top_k: int = 3,
        return_retrieved_text: bool = False,
    ):
        """
        Answer the given question with the retrieved knowledge.
        """
        retrieved_texts = self.retrieve(question, top_k=retrieval_top_k)
        user_prompt = self.USER_PROMPT.format(
            context="\n".join(retrieved_texts), question=question
        )
        response = self.openai_client.chat.completions.create(
            model=self.llm_model,
            messages=[
                {"role": "system", "content": self.SYSTEM_PROMPT},
                {"role": "user", "content": user_prompt},
            ],
        )
        if not return_retrieved_text:
            return response.choices[0].message.content
        else:
            return response.choices[0].message.content, retrieved_texts

Initialisons la classe RAG avec les clients OpenAI et Milvus.

openai_client = OpenAI()
milvus_client = MilvusClient(uri="./milvus_demo.db")

my_rag = RAG(openai_client=openai_client, milvus_client=milvus_client)

En ce qui concerne l'argument de MilvusClient:

  • Définir uri comme un fichier local, par exemple./milvus.db, est la méthode la plus pratique, car elle utilise automatiquement Milvus Lite pour stocker toutes les données dans ce fichier.
  • Si vous avez des données à grande échelle, vous pouvez configurer un serveur Milvus plus performant sur docker ou kubernetes. Dans cette configuration, veuillez utiliser l'uri du serveur, par exemplehttp://localhost:19530, comme votre uri.
  • Si vous souhaitez utiliser Zilliz Cloud, le service cloud entièrement géré pour Milvus, ajustez les adresses uri et token, qui correspondent au point de terminaison public et à la clé Api dans Zilliz Cloud.

Exécuter le pipeline RAG et obtenir des résultats

Nous utilisons le guide de développement Milvus comme connaissance privée dans notre RAG, ce qui constitue une bonne source de données pour un pipeline RAG simple.

Téléchargez-le et chargez-le dans le pipeline RAG.

import urllib.request
import os

url = "https://raw.githubusercontent.com/milvus-io/milvus/master/DEVELOPMENT.md"
file_path = "./Milvus_DEVELOPMENT.md"

if not os.path.exists(file_path):
    urllib.request.urlretrieve(url, file_path)
with open(file_path, "r") as file:
    file_text = file.read()

text_lines = file_text.split("# ")
my_rag.load(text_lines)
Creating embeddings: 100%|██████████| 47/47 [00:12<00:00,  3.84it/s]

Définissons une question sur le contenu de la documentation du guide de développement. Utilisons ensuite la méthode answer pour obtenir la réponse et les textes contextuels récupérés.

question = "what is the hardware requirements specification if I want to build Milvus and run from source code?"
my_rag.answer(question, return_retrieved_text=True)
('The hardware requirements specification to build and run Milvus from source code are:\n\n- 8GB of RAM\n- 50GB of free disk space',
 ['Hardware Requirements\n\nThe following specification (either physical or virtual machine resources) is recommended for Milvus to build and run from source code.\n\n```\n- 8GB of RAM\n- 50GB of free disk space\n```\n\n##',
  'Building Milvus on a local OS/shell environment\n\nThe details below outline the hardware and software requirements for building on Linux and MacOS.\n\n##',
  "Software Requirements\n\nAll Linux distributions are available for Milvus development. However a majority of our contributor worked with Ubuntu or CentOS systems, with a small portion of Mac (both x86_64 and Apple Silicon) contributors. If you would like Milvus to build and run on other distributions, you are more than welcome to file an issue and contribute!\n\nHere's a list of verified OS types where Milvus can successfully build and run:\n\n- Debian/Ubuntu\n- Amazon Linux\n- MacOS (x86_64)\n- MacOS (Apple Silicon)\n\n##"])

Préparons maintenant quelques questions avec les réponses de vérité terrain correspondantes. Nous obtenons les réponses et les contextes à partir de notre pipeline RAG.

from datasets import Dataset
import pandas as pd

question_list = [
    "what is the hardware requirements specification if I want to build Milvus and run from source code?",
    "What is the programming language used to write Knowhere?",
    "What should be ensured before running code coverage?",
]
ground_truth_list = [
    "If you want to build Milvus and run from source code, the recommended hardware requirements specification is:\n\n- 8GB of RAM\n- 50GB of free disk space.",
    "The programming language used to write Knowhere is C++.",
    "Before running code coverage, you should make sure that your code changes are covered by unit tests.",
]
contexts_list = []
answer_list = []
for question in tqdm(question_list, desc="Answering questions"):
    answer, contexts = my_rag.answer(question, return_retrieved_text=True)
    contexts_list.append(contexts)
    answer_list.append(answer)

df = pd.DataFrame(
    {
        "question": question_list,
        "contexts": contexts_list,
        "answer": answer_list,
        "ground_truth": ground_truth_list,
    }
)
rag_results = Dataset.from_pandas(df)
df
/Users/eureka/miniconda3/envs/zilliz/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
Answering questions: 100%|██████████| 3/3 [00:03<00:00,  1.04s/it]
question contextes réponse vérité_de_sol
0 Quelle est la spécification des exigences matérielles... [Exigences en matière de matériel Les spécificités suivantes... La spécification des exigences matérielles pour bui... Si vous souhaitez construire Milvus et l'exécuter à partir d...
1 Quel est le langage de programmation utilisé pour écrire... [CMake & Conan La bibliothèque d'algorithmes de Mil... Le langage de programmation utilisé pour écrire Knowher... Le langage de programmation utilisé pour écrire Knowher...
2 Qu'est-ce qui doit être assuré avant d'exécuter la cov... [Couverture de code Avant de soumettre votre pull... Avant d'exécuter la couverture du code, il faut s'assur... Avant d'exécuter la couverture du code, vous devez ...

Évaluation avec Arize Phoenix

Nous utilisons Arize Phoenix pour évaluer notre pipeline RAG (retrieval-augmented generation), en nous concentrant sur deux mesures clés :

  • Évaluation de l'hallucination: Détermine si le contenu est factuel ou hallucinatoire (informations non fondées sur le contexte), en garantissant l'intégrité des données.

    • Explication de l'hallucination: Explique pourquoi une réponse est factuelle ou non.
  • Évaluation de l'assurance qualité: Évalue l'exactitude des réponses du modèle aux requêtes d'entrée.

    • Explication de l'AQ: Explique en détail pourquoi une réponse est correcte ou incorrecte.

Vue d'ensemble du traçage Phoenix

Phoenix fournit un traçage compatible OTEL pour les applications LLM, avec des intégrations pour des frameworks comme Langchain, LlamaIndex, et des SDK comme OpenAI et Mistral. Le traçage capture l'ensemble du flux de requêtes, ce qui permet d'obtenir des informations sur les points suivants

  • La latence de l'application: Identifier et optimiser les invocations LLM lentes et les performances des composants.
  • Utilisation des jetons: Décomposition de la consommation de jetons pour l'optimisation des coûts.
  • Exceptions d'exécution: Capturez les problèmes critiques tels que la limitation du débit.
  • Documents récupérés: Analyse de la récupération, du score et de l'ordre des documents.

En utilisant le traçage de Phoenix, vous pouvez identifier les goulots d'étranglement, optimiser les ressources et garantir la fiabilité du système dans différents cadres et langages.

import phoenix as px
from phoenix.trace.openai import OpenAIInstrumentor

# To view traces in Phoenix, you will first have to start a Phoenix server. You can do this by running the following:
session = px.launch_app()

# Initialize OpenAI auto-instrumentation
OpenAIInstrumentor().instrument()
🌍 To view the Phoenix app in your browser, visit http://localhost:6006/
📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix

Alt Text Texte Alt

import nest_asyncio

from phoenix.evals import HallucinationEvaluator, OpenAIModel, QAEvaluator, run_evals

nest_asyncio.apply()  # This is needed for concurrency in notebook environments

# Set your OpenAI API key
eval_model = OpenAIModel(model="gpt-4o")

# Define your evaluators
hallucination_evaluator = HallucinationEvaluator(eval_model)
qa_evaluator = QAEvaluator(eval_model)

# We have to make some minor changes to our dataframe to use the column names expected by our evaluators
# for `hallucination_evaluator` the input df needs to have columns 'output', 'input', 'context'
# for `qa_evaluator` the input df needs to have columns 'output', 'input', 'reference'
df["context"] = df["contexts"]
df["reference"] = df["contexts"]
df.rename(columns={"question": "input", "answer": "output"}, inplace=True)
assert all(
    column in df.columns for column in ["output", "input", "context", "reference"]
)

# Run the evaluators, each evaluator will return a dataframe with evaluation results
# We upload the evaluation results to Phoenix in the next step
hallucination_eval_df, qa_eval_df = run_evals(
    dataframe=df,
    evaluators=[hallucination_evaluator, qa_evaluator],
    provide_explanation=True,
)
run_evals |██████████| 6/6 (100.0%) | ⏳ 00:03<00:00 |  1.64it/s
results_df = df.copy()
results_df["hallucination_eval"] = hallucination_eval_df["label"]
results_df["hallucination_explanation"] = hallucination_eval_df["explanation"]
results_df["qa_eval"] = qa_eval_df["label"]
results_df["qa_explanation"] = qa_eval_df["explanation"]
results_df.head()
input contextes sortie vérité_fondamentale contexte référence hallucination_eval hallucination_explanation qa_eval qa_explanation
0 Quelle est la spécification des exigences matérielles... [Exigences en matière de matériel Les spécificités suivantes... La spécification des exigences matérielles pour bui... Si vous souhaitez construire Milvus et l'exécuter à partir d... [Exigences en matière de matériel Les spécific... [Exigences en matière de matériel Les spécificités suivantes... factuel Pour déterminer si la réponse est factuelle ou hallu... correct Pour déterminer si la réponse est correcte, il faut...
1 Quel est le langage de programmation utilisé pour écrire... [CMake & Conan La bibliothèque d'algorithmes de Mil... Le langage de programmation utilisé pour écrire Knowher... Le langage de programmation utilisé pour écrire Knowher... [CMake & Conan\n- La bibliothèque d'algorithmes de Mil... [CMake & Conan\n\nLa bibliothèque d'algorithmes de Mil... factuel Pour déterminer si la réponse est factuelle ou hallu... correct Pour déterminer si la réponse est correcte, nous avons besoin...
2 Qu'est-ce qui doit être assuré avant d'exécuter la cov... [Couverture de code Avant de soumettre votre pull... Avant d'exécuter la couverture du code, il faut s'assur... Avant d'exécuter la couverture du code, il faut s'assurer ... [Code coverage\nBefore submitting your pull ... [Code coverage\NBefore submitting your pull ... factuel Le texte de référence précise qu'avant d'exécuter ... correct Pour déterminer si la réponse est correcte, il faut...

Traduit parDeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

Cette page a-t - elle été utile ?