Développement de RAG axé sur les métriques
Lors d’une récente présentation au Zilliz Unstructured Data Meetup, Jithin James et Shahul Es, mainteneurs de Ragas, ont partagé des perspectives sur l’utilisation du développement piloté par les métriques pour évaluer les systèmes de génération augmentée par récupération (RAG). Les développeurs peuvent ajuster leurs systèmes en fonction des résultats d’évaluation afin d’obtenir de meilleures performances.
Dans leur intervention, Jithin et Shahul ont abordé à la fois les fondements théoriques et les applications pratiques de l’évaluation des systèmes RAG. Ils ont expliqué comment la compréhension de la théorie derrière le code d’évaluation peut fournir des perspectives plus approfondies sur son fonctionnement. Après cette partie, ils ont démontré le processus d’évaluation à l’aide d’un véritable système RAG propulsé par Milvus, une base de données vectorielle open source de premier plan, réputée pour son efficacité dans la recherche de similarité et les applications d’IA.
Pour une compréhension plus détaillée, regardez le replay de la présentation du meetup.
Comment évaluer les performances des systèmes RAG
Shahul a abordé la manière dont Ragas calcule la véracité d’une réponse générée par le système RAG. Il s’agit d’une métrique d’évaluation cruciale, car la réponse est ce que voit l’utilisateur final. Ralentissons un peu et approfondissons. Ragas utilise la formule suivante pour calculer la véracité d’une réponse :
Fig 1- Formule de calcul de la métrique answer_truthfulness de Ragas
Calculer la correction d’une réponse dans les systèmes de génération augmentée par récupération (RAG)
Le processus implique deux métriques principales : la similarité factuelle et la similarité sémantique. Ces métriques aident à déterminer la qualité et la pertinence de la réponse générée par rapport à la vérité terrain.
Métriques clés
Similarité factuelle :
- Cette métrique mesure la correction factuelle de la réponse générée en comparant la présence d’informations factuelles entre la vérité terrain et la réponse générée.
Similarité sémantique :
- Cette métrique mesure à quel point la réponse générée est sémantiquement similaire à la vérité terrain, en s’assurant que le sens transmis par la réponse générée correspond à la vérité terrain.
Étapes pour calculer la correction d’une réponse
Identifier les vrais positifs (TP), les faux positifs (FP) et les faux négatifs (FN) :
Vrais positifs : Énoncés correctement présents à la fois dans la vérité terrain et dans la réponse générée.
Faux positifs : Énoncés présents dans la réponse générée mais pas dans la vérité terrain.
Faux négatifs : Énoncés présents dans la vérité terrain mais pas dans la réponse générée.
Calculer le score F1 :
- Le score F1 est une moyenne de la précision et du rappel, fournissant un équilibre entre les deux. La formule du score F1 est présentée dans la Figure 1.
Exemple pratique
Considérons un énoncé de vérité terrain et une réponse générée :
Vérité terrain : "Alan Turing a développé le concept de la machine de Turing."
Réponse générée : "Alan Turing est connu pour avoir développé le concept de la machine de Turing et de l’intelligence artificielle."
Étape 1 : Identifier les TP, FP et FN
Vrais positifs (TP) :
- "Alan Turing a développé le concept de la machine de Turing."
Faux positifs (FP) :
- "Alan Turing est connu pour avoir développé l’intelligence artificielle."
Faux négatifs (FN) :
- Aucun (puisque la réponse générée inclut tous les éléments de la vérité terrain).
Étape 2 : Calculer le score F1
TP = 1
FP = 1
FN = 0
F1 = 1 / (1 + 0.5 * (1 + 0))
= 1 / 1.5
≈ 0.67
Interprétation<
Similarité factuelle : La réponse générée est factuellement correcte, car elle inclut les informations essentielles de la vérité terrain.
Similarité sémantique : La réponse générée maintient un alignement sémantique avec la vérité terrain, bien qu’elle inclue des informations supplémentaires.
Le score F1 combine ces aspects pour fournir une mesure de l’exactitude de la réponse, en équilibrant la précision et le rappel. Cette méthode aide à évaluer dans quelle mesure la réponse générée correspond à la vérité terrain en termes de contenu factuel et de signification globale.
Mais la véracité de la réponse n’est pas la seule métrique que vous pouvez utiliser pour évaluer vos systèmes RAG. D’autres métriques sont la fidélité, la pertinence de la réponse, le rappel du contexte et la précision du contexte. Examinons concrètement comment vous pouvez évaluer et améliorer un système RAG propulsé par Mivus.
Évaluer et améliorer un système RAG propulsé par Milvus
Maintenant que vous avez compris la base théorique de l’évaluation des systèmes RAG, plongeons dans un exemple pratique de RAG construit avec la base de données vectorielle Milvus. Nous allons parcourir la configuration, l’implémentation et l’évaluation d’un système RAG. Sur la base des résultats, nous verrons ensuite comment améliorer le système.
Configuration de l’environnement
Tout d’abord, nous devons configurer notre environnement de développement. Pour ce faire, installez d’abord toutes les bibliothèques requises :
!pip install pymilvus[model] ragas langchain langchain_openai python-dotenv nest_asyncio pypdf langchain_community
Décomposons l’utilisation de chaque bibliothèque dans le code :
Pymilvus[model]vous aidera à vous connecter à Milvus, à créer des collections, à insérer des données et à effectuer des recherches de similarité.Ragasfournira des métriques d’évaluation, générera des jeux de tests synthétiques et évaluera les pipelines RAG.Langchainchargera les documents, les divisera en fragments et préparera les données textuelles pour l’embedding et les requêtes.Langchain_openaiservira d’interface avec les modèles OpenAI, générera des embeddings et répondra aux questions à l’aide d’appels API.Python-dotenvchargera les variables d’environnement depuis un fichier .env afin de gérer les informations sensibles comme les clés API.Nest_asynciopermettra les opérations asynchrones imbriquées dans des environnements synchrones. En particulier si vous utilisez des notebooks Jupiter.Pypdfchargera les documents PDF, extraira le contenu et préparera le texte pour le traitement.Langchain_communityfournira des chargeurs de documents supplémentaires et des utilitaires pour intégrer des ressources apportées par la communauté. Après avoir installé les bibliothèques, importez-les dans votre code et configurez vos clés API :
import os
import pandas as pd
import nest_asyncio
import openai
from pymilvus import MilvusClient, model
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_recall,
context_precision,
answer_correctness,
)
from ragas.testset.generator import TestsetGenerator
from ragas.testset.evolutions import simple, reasoning, multi_context
from langchain_community.document_loaders import DirectoryLoader
from langchain.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from dotenv import load_dotenv
from datasets import Dataset
# Load environment variables
# Apply nest_asyncio to allow nested event loops
nest_asyncio.apply()
# Set up OpenAI API key
os.environ["OPENAI_API_KEY"] = "Your API Key"
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
L’importation des bibliothèques et des modules dans le code vous permettra d’appeler et d’utiliser leurs fonctions. La clé OpenAI vous aidera à vous authentifier auprès d’OpenAI lors des appels API. Si vous n’en avez pas, rendez-vous sur la page API d’OpenAI et générez-en une.
Chargement et préparation des documents
Ensuite, nous allons charger nos documents et les préparer pour le traitement :
# Load PDF documents from a directory
pdf_loader = DirectoryLoader("/content/data", loader_cls=PyPDFLoader)
documents = pdf_loader.load()
# Ensure each document has a filename in its metadata
for document in documents:
document.metadata['filename'] = document.metadata['source'
Le code charge des documents PDF depuis un répertoire à l’aide de la classe PyPDFLoader. Il crée ensuite une instance de DirectoryLoader, charge les documents et parcourt chaque document pour ajouter un attribut filename à ses métadonnées. Cela garantit que chaque document est correctement identifié et géré avec son nom de fichier correspondant. Cette étape est cruciale, car elle constitue la base de connaissances de notre système RAG. Nous utilisons des documents PDF dans cet exemple, mais vous pourriez l’adapter à d’autres types de documents si nécessaire.
Génération d’un jeu de test
Maintenant que vous avez chargé les données, vous avez besoin d’un ensemble diversifié de questions de test pour aider à évaluer efficacement notre système RAG. Nous utiliserons le framework Ragas pour générer un jeu de test synthétique.
# Initialize OpenAI models for test set generation
generator_llm = ChatOpenAI(model="gpt-3.5-turbo-16k")
critic_llm = ChatOpenAI(model="gpt-4")
embeddings = OpenAIEmbeddings()
# Create a TestsetGenerator
generator = TestsetGenerator.from_langchain(
generator_llm,
critic_llm,
embeddings
)
# Generate synthetic test set with 10 samples
testset = generator.generate_with_langchain_docs(documents, test_size=10, distributions={simple: 0.5, reasoning: 0.25, multi_context: 0.25})
# Convert test set to Pandas DataFrame
testset_df = testset.to_pandas()
print(testset_df)
Ce code initialise deux modèles de langage (gpt-3.5-turbo-16k pour générer des jeux de test et gpt-4 pour l’évaluation) ainsi qu’un modèle d’embedding d’OpenAI. Il crée ensuite une instance de TestsetGenerator à l’aide de ces modèles. Le générateur produit un jeu de test synthétique de 10 échantillons à partir des documents PDF chargés, avec des distributions spécifiées pour différents types de questions. Ce jeu de test vous aidera à évaluer divers aspects des performances de votre système RAG, notamment sa capacité à traiter des requêtes simples, des tâches de raisonnement et des questions nécessitant plusieurs contextes. Voici un exemple de jeu de test généré.
Fig 2- Jeu de test généré avec Ragas
La vérité terrain est la réponse réelle à une question donnée. Nous l’utiliserons plus tard pour mesurer les performances de notre système RAG en évaluant à quel point sa sortie est proche de ces réponses de référence. Comme Shahul le souligne dans la présentation, générer le jeu de test synthétique avec Ragas ne signifie pas que vous devez l’utiliser aveuglément. Vous devez filtrer et utiliser les échantillons dont vous avez besoin.
Puisque vous disposez du jeu de test, construisons un système RAG simple alimenté par Milvus, puis évaluons-le à l’aide du jeu de test ci-dessus.
Configuration de Milvus et insertion des embeddings de documents
Maintenant, configurons notre base de données vectorielle Milvus et insérons nos embeddings de documents. Assurez-vous que Milvus est installé et en cours d’exécution. Si ce n’est pas le cas, suivez ce guide complet d’installation de Milvus.
# Connect to Milvus instance
milvus_client = MilvusClient(uri="http://localhost:19530")
# Define collection name
collection_name = "pdf_collection"
# Drop the collection if it already exists
if milvus_client.has_collection(collection_name):
milvus_client.drop_collection(collection_name)
# Create a new collection
milvus_client.create_collection(
collection_name=collection_name,
dimension=768, # Dimension of vectors
overwrite=True
)
# Initialize the embedding function
embedding_fn = model.DefaultEmbeddingFunction()
# Extract document texts and generate embeddings
expanded_docs = [doc.page_content for doc in documents]
expanded_vectors = embedding_fn.encode_documents(expanded_docs)
# Prepare data for insertion
expanded_data = [
{"id": i, "vector": expanded_vectors[i], "text": expanded_docs[i], "subject": "pdf_documents"}
for i in range(len(expanded_vectors))
]
# Insert expanded data into the collection
milvus_client.insert(data=expanded_data, collection_name=collection_name)
Le code ci-dessus se connecte à une instance Milvus et configure une collection nommée pdf_collection pour stocker les vecteurs de documents. Si la collection existe déjà, il la supprime et la recrée avec une dimension de 768 pour les vecteurs. Il initialise une fonction d’embedding, extrait le texte des documents chargés et génère leurs embeddings. Le code prépare ensuite les données avec les embeddings et le texte associé, puis insère ces données dans la collection Milvus. C’est à cette étape que Milvus excelle vraiment, car il vous permet d’effectuer des recherches de similarité rapides et efficaces sur les embeddings des données stockées, ce qui est crucial pour la partie récupération de votre système RAG.
Effectuer une recherche de similarité
Une fois vos documents indexés dans Milvus, vous pouvez désormais effectuer des recherches de similarité afin de récupérer des contextes pertinents pour nos questions :
# Define the search parameters
search_params = {"metric_type": "COSINE", "params": {"nprobe": 20}} # nprobe for better recall
# Perform the search
query_vectors = embedding_fn.encode_queries(testset_df['question'].tolist())
results = milvus_client.search(
collection_name=collection_name,
data=query_vectors,
anns_field="vector", # specify the vector field name
search_params=search_params,
limit=3, # number of top results to retrieve
output_fields=["id", "text"]
)
Le code ci-dessus définit les paramètres de recherche pour la collection Milvus en utilisant la similarité cosinus et une valeur nprobe de 20 pour un meilleur rappel. Il encode les questions de l’ensemble de test en vecteurs de requête et effectue une recherche dans la collection pdf_collection, en récupérant les trois vecteurs les plus similaires pour chaque requête. Les résultats de recherche incluent les IDs et le text des documents correspondants.
Générer des réponses à l’aide d’un grand modèle de langage
Une fois les contextes pertinents récupérés, vous pouvez désormais générer des réponses à l’aide d’un modèle de langage. Dans ce cas, nous utiliserons GPT 3.5 turbo.
# Function to generate answers using OpenAI
def generate_answer(question, contexts):
context_text = " ".join(contexts)
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": f"Context: {context_text}nnQuestion: {question}nAnswer:"}
]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
max_tokens=100,
temperature=0.7,
)
return response.choices[0].message.content.strip()
# Extract contexts and generate answers using OpenAI
contexts = []
answers = []
for i, result in enumerate(results):
context = [match['entity']['text'] for match in result]
contexts.append(context)
question = testset_df['question'].iloc[i]
answer = generate_answer(question, context)
answers.append(answer)
Le code définit une fonction generate_answer qui utilise le modèle gpt-3.5-turbo d’OpenAI pour générer des réponses à partir d’une question et d’un contexte donnés. Il prépare les messages pour l’appel API, concatène le contexte et interroge le modèle. Il extrait ensuite la réponse générée et la renvoie. La boucle suivante parcourt les résultats de recherche et utilise la fonction generate_answer pour générer des réponses pour chaque question de l’ensemble de test, en stockant les contextes et les réponses dans des listes. Les questions utilisées dans la boucle pour générer les réponses sont les mêmes que celles générées dans l’ensemble de test.
Puisque vous disposez maintenant des réponses générées par le système RAG et des réponses de référence, évaluons les performances du système RAG.
Évaluer le système RAG
Enfin, nous évaluerons les performances de notre système RAG à l’aide des métriques abordées précédemment :
# Ensure all lists are the same length
min_length = min(len(testset_df['question']), len(testset_df['ground_truth']), len(answers), len(contexts))
questions = testset_df['question'][:min_length]
ground_truths = testset_df['ground_truth'][:min_length]
answers = answers[:min_length]
contexts = contexts[:min_length]
# Create the dataset with correct column names
data = {
"question": questions,
"answer": answers,
"contexts": contexts,
"ground_truth": ground_truths
}
from datasets import Dataset
# Convert dict to dataset
dataset = Dataset.from_pandas(pd.DataFrame(data))
# Evaluate using RAGAS
metrics = evaluate(
dataset=dataset,
metrics=[
answer_correctness,
context_precision,
context_recall,
faithfulness,
answer_relevancy,
],
raise_exceptions=False #handle async issues
)
# Convert result to DataFrame for better readability
result_df = metrics.to_pandas()
print(result_df)
Le code garantit la cohérence du processus d’évaluation en réduisant toutes les listes pertinentes à la même longueur minimale. Cela évite les longueurs non concordantes qui pourraient provoquer des erreurs lors de l’évaluation. Il crée ensuite un dictionnaire avec ces listes tronquées et le convertit en un DataFrame Pandas, qui est ensuite transformé en un Dataset Hugging Face. Cet ensemble de données structuré permet une évaluation systématique à l’aide du framework RAGAS, qui compare les réponses générées aux vérités terrain. Les métriques d’évaluation (exactitude de la réponse, précision du contexte, rappel du contexte, fidélité et pertinence de la réponse) fournissent une évaluation des performances du pipeline RAG.
Jetez un œil aux résultats de l’évaluation ci-dessous :
Fig 3- Résultats de l’évaluation du système RAG avec Ragas
La précision du contexte de notre système RAG et le rappel sont excellents, et la pertinence de la réponse est louable. Mais l’exactitude de la réponse est assez faible.
Le côté récupération est bon grâce à un excellent rappel et une excellente précision du contexte. Nous pouvons donc conclure que la partie génération pourrait affecter l’exactitude de nos réponses. Pour l’améliorer, vous pouvez utiliser un modèle de génération de réponses plus puissant comme GPT-4.
Conclusion
L’évaluation et l’amélioration des systèmes de génération augmentée par récupération (RAG) constituent une tâche nuancée mais essentielle dans le domaine de la récupération d’informations pilotée par l’IA. En tirant parti d’une approche fondée sur les métriques, comme l’ont démontré Jithin James et Shahul Es, vous pouvez affiner systématiquement vos systèmes RAG afin de garantir qu’ils fournissent des informations exactes, pertinentes et fiables.
Pour plus de détails sur ce sujet, regardez la rediffusion de la conférence sur YouTube.
Ressources supplémentaires
Continuer à lire

Zilliz Named "Highest Performer" and "Easiest to Use" in G2's Summer 2025 Grid® Report for Vector Databases
Zilliz shines in G2's Summer 2025 Grid® Report as both "Highest Performer" and "Easiest to Use," solving the performance-usability dilemma.

Why AI Databases Don't Need SQL
Whether you like it or not, here's the truth: SQL is destined for decline in the era of AI.

DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding
Explore DeepSeek-VL2, the open-source MoE vision-language model. Discover its architecture, efficient training pipeline, and top-tier performance.


