Auswertung mit DeepEval
Dieser Leitfaden demonstriert die Verwendung von DeepEval zur Evaluierung einer Retrieval-Augmented Generation (RAG) Pipeline, die auf Milvus aufbaut.
Das RAG-System kombiniert ein Retrievalsystem mit einem generativen Modell, um neuen Text auf der Grundlage einer vorgegebenen Aufforderung zu generieren. Das System ruft zunächst relevante Dokumente aus einem Korpus mit Milvus ab und verwendet dann ein generatives Modell, um neuen Text auf der Grundlage der abgerufenen Dokumente zu erzeugen.
DeepEval ist ein Framework, das Sie bei der Bewertung Ihrer RAG-Pipelines unterstützt. Es gibt bereits Tools und Frameworks, die Ihnen bei der Erstellung dieser Pipelines helfen, aber die Evaluierung und Quantifizierung der Leistung Ihrer Pipeline kann schwierig sein. Hier kommt DeepEval 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 deepeval
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 "Restart session" 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
, alsuri
. - Wenn Sie Zilliz Cloud, den vollständig verwalteten Cloud-Service für Milvus, verwenden möchten, passen Sie
uri
undtoken
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:20<00:00, 2.26it/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 is as follows:\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.06s/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 ... |
Retriever auswerten
Bei der Evaluierung eines Retrievers in großen Sprachmodellsystemen (LLM) ist es entscheidend, Folgendes zu bewerten:
Relevanz der Rangfolge: Wie effektiv der Retriever relevante Informationen gegenüber irrelevanten Daten priorisiert.
Kontextbezogenes Abrufen: Die Fähigkeit, kontextuell relevante Informationen auf der Grundlage der Eingaben zu erfassen und abzurufen.
Ausgewogenheit: Wie gut verwaltet der Retriever die Größe von Textstücken und den Abrufumfang, um Irrelevanzen zu minimieren.
Zusammen bieten diese Faktoren ein umfassendes Verständnis dafür, wie der Retriever die nützlichsten Informationen priorisiert, erfasst und präsentiert.
from deepeval.metrics import (
ContextualPrecisionMetric,
ContextualRecallMetric,
ContextualRelevancyMetric,
)
from deepeval.test_case import LLMTestCase
from deepeval import evaluate
contextual_precision = ContextualPrecisionMetric()
contextual_recall = ContextualRecallMetric()
contextual_relevancy = ContextualRelevancyMetric()
test_cases = []
for index, row in df.iterrows():
test_case = LLMTestCase(
input=row["question"],
actual_output=row["answer"],
expected_output=row["ground_truth"],
retrieval_context=row["contexts"],
)
test_cases.append(test_case)
# test_cases
result = evaluate(
test_cases=test_cases,
metrics=[contextual_precision, contextual_recall, contextual_relevancy],
print_results=False, # Change to True to see detailed metric results
)
/Users/eureka/miniconda3/envs/zilliz/lib/python3.9/site-packages/deepeval/__init__.py:49: UserWarning: You are using deepeval version 1.1.6, however version 1.2.2 is available. You should consider upgrading via the "pip install --upgrade deepeval" command.
warnings.warn(
✨ Sie verwenden DeepEvals neueste Contextual Precision Metric! (mit gpt-4o, strict=False, async_mode=True)...
✨ Sie führen DeepEvals neueste Contextual Recall Metric aus! (unter Verwendung von gpt-4o, strict=False, async_mode=True)...
✨ Sie führen die neueste kontextuelle Relevanz-Metrik von DeepEval aus! (using gpt-4o, strict=False, async_mode=True)...
Event loop is already running. Applying nest_asyncio patch to allow async execution...
Evaluating 3 test case(s) in parallel: |██████████|100% (3/3) [Time Taken: 00:11, 3.91s/test case]
✓ Tests beendet 🎉! Führen Sie 'deepeval login' aus, um die Evaluierungsergebnisse von Confident AI zu sehen. ‼️ HINWEIS: Sie können stattdessen auch Auswertungen zu ALLEN deepeval-Metriken direkt auf Confident AI durchführen.
Evaluierung der Generierung
Um die Qualität der generierten Ausgaben in großen Sprachmodellen (LLMs) zu bewerten, ist es wichtig, sich auf zwei Schlüsselaspekte zu konzentrieren:
Relevanz: Bewerten Sie, ob die Eingabeaufforderung das LLM effektiv dazu anleitet, hilfreiche und kontextuell passende Antworten zu generieren.
Wiedergabetreue: Messen Sie die Genauigkeit des Outputs und stellen Sie sicher, dass das Modell Informationen erzeugt, die faktisch korrekt und frei von Halluzinationen oder Widersprüchen sind. Der generierte Inhalt sollte mit den im Abfragekontext bereitgestellten faktischen Informationen übereinstimmen.
Diese Faktoren zusammen gewährleisten, dass die Ergebnisse sowohl relevant als auch zuverlässig sind.
from deepeval.metrics import AnswerRelevancyMetric, FaithfulnessMetric
from deepeval.test_case import LLMTestCase
from deepeval import evaluate
answer_relevancy = AnswerRelevancyMetric()
faithfulness = FaithfulnessMetric()
test_cases = []
for index, row in df.iterrows():
test_case = LLMTestCase(
input=row["question"],
actual_output=row["answer"],
expected_output=row["ground_truth"],
retrieval_context=row["contexts"],
)
test_cases.append(test_case)
# test_cases
result = evaluate(
test_cases=test_cases,
metrics=[answer_relevancy, faithfulness],
print_results=False, # Change to True to see detailed metric results
)
✨ Sie verwenden die neueste Antwortrelevanz-Metrik von DeepEval! (mit gpt-4o, strict=False, async_mode=True)...
✨ Sie führen DeepEvals neueste Faithfulness-Metrik aus! (using gpt-4o, strict=False, async_mode=True)...
Event loop is already running. Applying nest_asyncio patch to allow async execution...
Evaluating 3 test case(s) in parallel: |██████████|100% (3/3) [Time Taken: 00:11, 3.97s/test case]
✓ Tests beendet 🎉! Führen Sie 'deepeval login' aus, um die Evaluierungsergebnisse von Confident AI zu sehen. ‼️ HINWEIS: Sie können stattdessen auch Auswertungen zu ALLEN deepeval-Metriken direkt auf Confident AI durchführen.