التقييم باستخدام Arize Pheonix
يوضّح هذا الدليل كيفية استخدام Arize Pheonix لتقييم خط أنابيب الاسترجاع والتوليد المعزز (RAG) المبني على Milvus.
يجمع نظام RAG بين نظام الاسترجاع والنموذج التوليدي لتوليد نص جديد بناءً على مطالبة معينة. يقوم النظام أولاً باسترجاع المستندات ذات الصلة من مجموعة مستندات باستخدام Milvus، ثم يستخدم نموذجًا توليدًا لتوليد نص جديد بناءً على المستندات المسترجعة.
Arize Pheonix هو إطار عمل يساعدك على تقييم خطوط أنابيب RAG الخاصة بك. هناك أدوات وأطر عمل حالية تساعدك على بناء خطوط الأنابيب هذه، ولكن قد يكون من الصعب تقييمها وتحديد أداء خط الأنابيب الخاص بك. وهنا يأتي دور Arize Pheonix.
المتطلبات الأساسية
قبل تشغيل هذا الدفتر، تأكد من تثبيت التبعيات التالية:
$ pip install --upgrade pymilvus openai requests tqdm pandas "arize-phoenix>=4.29.0" nest_asyncio
إذا كنت تستخدم Google Colab، لتمكين التبعيات المثبتة للتو، فقد تحتاج إلى إعادة تشغيل وقت التشغيل (انقر على قائمة "وقت التشغيل" في أعلى الشاشة، وحدد "إعادة تشغيل الجلسة" من القائمة المنسدلة).
سنستخدم OpenAI باعتباره LLM في هذا المثال. يجب عليك إعداد مفتاح api OPENAI_API_KEY
كمتغير بيئة.
import os
# os.environ["OPENAI_API_KEY"] = "sk-*****************"
تعريف خط أنابيب RAG
سنقوم بتعريف فئة RAG التي تستخدم Milvus كمخزن متجه، و OpenAI كـ LLM. تحتوي الفئة على طريقة load
، التي تقوم بتحميل البيانات النصية إلى Milvus، وطريقة retrieve
، التي تسترجع البيانات النصية الأكثر تشابهًا مع السؤال المعطى، وطريقة answer
، التي تجيب على السؤال المعطى باستخدام المعرفة المسترجعة.
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
لنقم بتهيئة فئة RAG مع عملاء OpenAI و Milvus.
openai_client = OpenAI()
milvus_client = MilvusClient(uri="./milvus_demo.db")
my_rag = RAG(openai_client=openai_client, milvus_client=milvus_client)
أما بالنسبة لحجة MilvusClient
:
- إن تعيين
uri
كملف محلي، على سبيل المثال./milvus.db
، هي الطريقة الأكثر ملاءمة، حيث تستخدم تلقائيًا Milvus Lite لتخزين جميع البيانات في هذا الملف. - إذا كان لديك حجم كبير من البيانات، يمكنك إعداد خادم Milvus أكثر أداءً على docker أو kubernetes. في هذا الإعداد، يُرجى استخدام الخادم uri، على سبيل المثال
http://localhost:19530
، كـuri
. - إذا كنت ترغب في استخدام Zilliz Cloud، الخدمة السحابية المدارة بالكامل لـ Milvus، اضبط
uri
وtoken
، والتي تتوافق مع نقطة النهاية العامة ومفتاح Api في Zilliz Cloud.
تشغيل خط أنابيب RAG والحصول على النتائج
نحن نستخدم دليل تطوير Milvus ليكون بمثابة المعرفة الخاصة في RAG الخاص بنا، وهو مصدر بيانات جيد لخط أنابيب RAG بسيط.
قم بتنزيله وتحميله في خط أنابيب 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]
دعونا نحدد سؤال استعلام عن محتوى وثائق دليل التطوير. ثم استخدم الطريقة answer
للحصول على الإجابة ونصوص السياق المسترجعة.
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##"])
الآن دعونا نعد بعض الأسئلة مع إجابات الحقيقة الأساسية المقابلة لها. نحصل على الإجابات والسياقات من خط أنابيب 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]
السؤال | السياقات | إجابة | الحقيقة_الأرضية | |
---|---|---|---|---|
0 | ما هي مواصفات متطلبات الأجهزة التالية؟ | [مواصفات متطلبات الأجهزة \n\nالمواصفات التالية... | ما هي مواصفات متطلبات الأجهزة اللازمة لبناء.... | إذا كنت ترغب في إنشاء برنامج Milvus وتشغيله من المصدر... |
1 | ما هي لغة البرمجة المستخدمة في كتابة... | [CMake & Conan \n\nمكتبة خوارزمية ميلفوس | ما هي لغة البرمجة المستخدمة لكتابة خوارزمية... | ما هي لغة البرمجة المستخدمة في كتابة نوير؟ |
2 | ما الذي يجب التأكد منه قبل تشغيل الرمز البرمجي.... | [تغطية الشيفرة البرمجية \nقبل إرسال عملية السحب.... | قبل تشغيل تغطية التعليمات البرمجية، يجب التأكد من... | قبل تشغيل تغطية التعليمات البرمجية، يجب التأكد ... |
التقييم باستخدام أريز فينيكس
نستخدم Arize Phoenix لتقييم خط أنابيب التوليد المعزز للاسترجاع (RAG) الخاص بنا، مع التركيز على مقياسين رئيسيين:
تقييم الهلوسة: يُحدد ما إذا كان المحتوى واقعيًا أم هلوسة (معلومات لا تستند إلى سياق)، مما يضمن سلامة البيانات.
- شرح الهلوسة: يوضح سبب كون الإجابة واقعية أم لا.
تقييم ضمان الجودة: تقييم دقة إجابات النموذج على استفسارات الإدخال.
- شرح ضمان الجودة: تفاصيل سبب كون الإجابة صحيحة أو غير صحيحة.
نظرة عامة على تتبع فينيكس
يوفر Phoenix تتبعًا متوافقًا مع OTEL لتطبيقات LLM، مع تكامل أطر عمل مثل Langchain وLlamaIndex وحزم SDK مثل OpenAI وMistral. يلتقط التتبع تدفق الطلبات بالكامل، ويقدم رؤى حول:
- كمون التطبيق: تحديد وتحسين بطء استدعاءات LLM وأداء المكونات.
- استخدام الرمز المميز: تقسيم استهلاك الرمز المميز لتحسين التكلفة.
- استثناءات وقت التشغيل: التقاط المشكلات الحرجة مثل تحديد المعدل.
- المستندات المسترجعة: تحليل استرجاع المستندات والنتيجة والترتيب.
من خلال استخدام تتبع فينيكس، يمكنك تحديد الاختناقات وتحسين الموارد وضمان موثوقية النظام عبر مختلف الأطر واللغات.
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
نص بديل
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()
الإدخال | السياقات | الإخراج | الحقيقة_الأرضية | السياق | المرجع | هلوسة_حقيقة | هلوسة_تفسير_الهلوسة | qa_eval | تفسير_الهلوسة | |
---|---|---|---|---|---|---|---|---|---|---|
0 | ما هي مواصفات متطلبات الأجهزة التالية؟ | [متطلبات الأجهزة \n\nما هي مواصفات متطلبات الأجهزة التالية... | ما هي مواصفات متطلبات الأجهزة اللازمة لبناء نظام..... | إذا كنت ترغب في إنشاء برنامج Milvus وتشغيله من المصدر... | [متطلبات الأجهزة \\nالمواصفات التالية لبناء... | [متطلبات الأجهزة \n\nالمواصفات التالية... | واقعية | لتحديد ما إذا كانت الإجابة واقعية أم هالو... | صحيحة | لتحديد ما إذا كانت الإجابة صحيحة، نحتاج إلى... |
1 | ما هي لغة البرمجة المستخدمة في كتابة... | [CMake & Conan \n\nمكتبة خوارزمية من لغة البرمجة... | ما هي لغة البرمجة المستخدمة لكتابة خوارزمية.... | ما هي لغة البرمجة المستخدمة في كتابة... | [CMake & Conan \n\nمكتبة الخوارزميات الخاصة ب... | [CMake & Conan \n\nمكتبة الخوارزميات الخاصة بـ Mil... | واقعية | لتحديد ما إذا كانت الإجابة واقعية أو هالو... | صحيحة | لتحديد ما إذا كانت الإجابة صحيحة، نحتاج إلى... |
2 | ما الذي يجب التأكد منه قبل تشغيل كود التغطية البرمجية؟ | [تغطية الشيفرة البرمجية \nقبل إرسال عملية السحب... | قبل تشغيل تغطية التعليمات البرمجية، يجب التأكد من... | قبل تشغيل تغطية التعليمات البرمجية، يجب التأكد ... | [تغطية التعليمات البرمجية \n\nقبل إرسال عملية السحب ... | [تغطية التعليمات البرمجية \n\nقبل إرسال السحب الخاص بك ... | واقعي | ينص النص المرجعي على أنه قبل تشغيل التغطية البرمجية... | صحيح | لتحديد ما إذا كانت الإجابة صحيحة، نحتاج إلى... |