milvus-logo
LFAI
Home
  • Integrationen

Auswertung mit Arize Pheonix

Open In Colab

Diese Anleitung zeigt, wie man Arize Pheonix verwendet, um eine Retrieval-Augmented Generation (RAG) Pipeline zu evaluieren, die auf Milvus aufbaut.

Das RAG-System kombiniert ein Retrieval-System mit einem generativen Modell, um neuen Text auf der Grundlage einer vorgegebenen Aufforderung zu generieren. Das System sucht zunächst mit Milvus relevante Dokumente aus einem Korpus und verwendet dann ein generatives Modell, um neuen Text auf der Grundlage der gefundenen Dokumente zu generieren.

Arize Pheonix ist ein Framework, das Ihnen hilft, Ihre RAG-Pipelines zu bewerten. Es gibt bereits Tools und Frameworks, die Ihnen bei der Erstellung dieser Pipelines helfen, aber die Bewertung und Quantifizierung der Leistung Ihrer Pipeline kann schwierig sein. Hier kommt Arize Pheonix ins Spiel.

Voraussetzungen

Vergewissern Sie sich, dass Sie die folgenden Abhängigkeiten installiert haben, bevor Sie dieses Notizbuch ausführen:

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

Wenn Sie Google Colab verwenden, müssen Sie möglicherweise die Runtime neu starten, um die soeben installierten Abhängigkeiten zu aktivieren (klicken Sie auf das Menü "Runtime" am oberen Rand des Bildschirms und wählen Sie "Sitzung neu starten" aus dem Dropdown-Menü).

Wir werden in diesem Beispiel OpenAI als LLM verwenden. Sie sollten den Api-Schlüssel OPENAI_API_KEY als Umgebungsvariable vorbereiten.

import os

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

Definieren Sie die RAG-Pipeline

Wir werden die RAG-Klasse definieren, die Milvus als Vektorspeicher und OpenAI als LLM verwendet. Die Klasse enthält die Methode load, die die Textdaten in Milvus lädt, die Methode retrieve, die die ähnlichsten Textdaten zur gegebenen Frage abruft, und die Methode answer, die die gegebene Frage mit dem abgerufenen Wissen beantwortet.

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

Initialisieren wir die RAG-Klasse mit OpenAI- und Milvus-Clients.

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

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

Was das Argument von MilvusClient betrifft:

  • Die Einstellung von uri als lokale Datei, z.B../milvus.db, ist die bequemste Methode, da sie automatisch Milvus Lite nutzt, um alle Daten in dieser Datei zu speichern.
  • Wenn Sie große Datenmengen haben, können Sie einen leistungsfähigeren Milvus-Server auf Docker oder Kubernetes einrichten. Bei dieser Einrichtung verwenden Sie bitte die Server-Uri, z. B.http://localhost:19530, als uri.
  • Wenn Sie Zilliz Cloud, den vollständig verwalteten Cloud-Service für Milvus, verwenden möchten, passen Sie uri und token an, die dem öffentlichen Endpunkt und dem Api-Schlüssel in Zilliz Cloud entsprechen.

Führen Sie die RAG-Pipeline aus und erhalten Sie die Ergebnisse

Wir verwenden das Milvus-Entwicklungshandbuch als privates Wissen in unserer RAG, was eine gute Datenquelle für eine einfache RAG-Pipeline ist.

Laden Sie es herunter und laden Sie es in die RAG-Pipeline.

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]

Lassen Sie uns eine Abfrage über den Inhalt der Dokumentation des Entwicklungshandbuchs definieren. Und dann verwenden wir die Methode answer, um die Antwort und die abgerufenen Kontexttexte zu erhalten.

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##"])

Lassen Sie uns nun einige Fragen mit den entsprechenden Antworten vorbereiten. Wir erhalten die Antworten und Kontexte aus unserer RAG-Pipeline.

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]
Frage Kontexte Antwort grund_wahrheit
0 Wie lauten die spezifischen Hardware-Anforderungen... [Hardware-Anforderungen\n\nDie folgende Spezifi... Die Spezifikation der Hardware-Anforderungen für... Wenn Sie Milvus bauen und von der Quelle...
1 Welche Programmiersprache wird zum Schreiben von... [CMake & Conan\n\nDie Algorithmenbibliothek von Mil... Mit welcher Programmiersprache wird Knowher... Welche Programmiersprache wird zum Schreiben von Knowher...
2 Was sollte sichergestellt werden, bevor die Codeabdeckung... [Codeabdeckung\n\nVor dem Einreichen Ihrer Pull ... Bevor die Codeabdeckung durchgeführt wird, sollte sie... Bevor Sie Code Coverage durchführen, sollten Sie ...

Auswertung mit Arize Phoenix

Wir verwenden Arize Phoenix, um unsere Retrieval-Augmented Generation (RAG) Pipeline zu evaluieren und konzentrieren uns dabei auf zwei Schlüsselmetriken:

  • Halluzinationsauswertung: Bestimmt, ob der Inhalt faktisch oder halluzinatorisch ist (Informationen, die nicht im Kontext begründet sind), und stellt die Datenintegrität sicher.

    • Erläuterung der Halluzinationen: Erläutert, warum eine Antwort sachlich ist oder nicht.
  • QA-Auswertung: Bewertet die Genauigkeit der Modellantworten auf Eingabeabfragen.

    • QA-Erklärung: Erklärt, warum eine Antwort richtig oder falsch ist.

Phoenix Tracing Überblick

Phoenix bietet OTEL-kompatibles Tracing für LLM-Anwendungen, mit Integrationen für Frameworks wie Langchain, LlamaIndex und SDKs wie OpenAI und Mistral. Tracing erfasst den gesamten Anfragefluss und bietet Einblicke in:

  • Anwendungslatenz: Identifizieren und optimieren Sie langsame LLM-Aufrufe und die Leistung von Komponenten.
  • Token-Verwendung: Aufschlüsselung des Token-Verbrauchs zur Kostenoptimierung.
  • Laufzeitausnahmen: Erfassen Sie kritische Probleme wie Ratenbeschränkung.
  • Abgerufene Dokumente: Analysieren Sie den Abruf von Dokumenten, die Bewertung und die Reihenfolge.

Durch die Nutzung des Tracing von Phoenix können Sie Engpässe identifizieren, Ressourcen optimieren und die Systemzuverlässigkeit über verschiedene Frameworks und Sprachen hinweg sicherstellen.

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 Alt-Text

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()
Eingabe Kontexte Ausgabe Grund_Wahrheit Kontext Referenz halluzination_eval halluzination_explanation qa_eval qa_erläuterung
0 Wie lauten die spezifischen Hardware-Anforderungen... [Hardware-Anforderungen\n\nDie folgende Spezifi... Die Spezifikation der Hardware-Anforderungen für den Bau... Wenn Sie Milvus bauen und von der Quelle aus betreiben wollen... [Hardware-Anforderungen\n\nDie folgenden Spezi... [Hardware-Anforderungen\n\nDie folgenden Spezi... faktisch Um festzustellen, ob die Antwort sachlich oder hallu... richtig Um festzustellen, ob die Antwort richtig ist, müssen wir...
1 Welche Programmiersprache wird zum Schreiben von... [CMake & Conan\n\nDie Algorithmenbibliothek von Mil... Mit welcher Programmiersprache wird Knowher... Die Programmiersprache, mit der Knowher... [CMake & Conan\n\nDie Algorithmus-Bibliothek von Mil... [CMake & Conan\n\nDie Algorithmus-Bibliothek von Mil... faktisch Um festzustellen, ob die Antwort sachlich oder hallu... richtig Um festzustellen, ob die Antwort richtig ist, müssen wir...
2 Was sollte vor der Durchführung der Code Coverage... [Codeabdeckung\n\nVor dem Einreichen Ihrer Pull ... Bevor die Codeabdeckung durchgeführt wird, sollte sie... Bevor Sie Code Coverage durchführen, sollten Sie ... [Codeabdeckung\n\nBevor Sie Ihre Pull-Datei einreichen ... [Codeabdeckung\n\nBefore submitting your pull ... sachlich Der Referenztext gibt an, dass vor der Ausführung der ... richtig Um festzustellen, ob die Antwort richtig ist, müssen wir...

Übersetzt vonDeepLogo

Feedback

War diese Seite hilfreich?