Evaluer un pipeline de génération augmentée par récupération (RAG) avec RAGAS !

Evaluer un pipeline de génération augmentée par récupération (RAG) avec RAGAS !

Les grands modèles de langage (LLM), pose un défi en termes d'évaluation de performance, particulièrement pour les cas d'utilisation de génération augmentée par récupération (RAG). Contrairement aux méthodes traditionnelles d'apprentissage automatique, il n'existe pas de métriques mathématiques précises pour évaluer ces modèles.

Dans le contexte des pipelines RAG, nous n'avons pas d'autres alternatives, contrairement aux métriques comme l'ROC AUC ou le RMSE pour l'apprentissage automatique traditionnel. Les seules options disponibles sont l'évaluation humaine ou celle par LLM.

Deux principales options d'évaluation disponibles :

  1. Évaluation humaine : Efficace mais chronophage et potentiellement biaisée.
  2. Évaluation par LLM : Utilisation d'un LLM pour évaluer un autre, comme le fait le cadre Ragas. Bien que cette approche ne soit pas idéale selon les standards traditionnels, c'est une alternative nécessaire étant donné le manque d'autres options.

Ragas est un cadre d'évaluation multifacette pour tester l'efficacité des pipelines RAG. Malgré sa complexité conceptuelle, sa mise en œuvre est relativement simple.

Une approche hybride combinant évaluation humaine et Ragas pourrait être recommandée pour une évaluation plus complète.

Génération d'un jeu de données synthétique de test

Ces quatre informations sont essentielles pour utiliser le cadre Ragas. Cependant, toutes ne sont pas strictement nécessaires pour effectuer les métriques Ragas,

  1. Quelle était la question initiale de l'utilisateur ?
  2. Quel contexte a été renvoyé par la base vectorielle pour répondre à cette question ?
  3. Comment le modèle de langage a-t-il fourni une réponse basée sur ce contexte et la question de l'utilisateur ?
  4. Quelle a finalement été la réponse exacte (ground truth) à la question ?

Le prérequis pour utiliser ce générateur est d'avoir un corpus de documents qui sera utilisé dans une base vectorielle. J'ai synthétisé un jeu de données pour cet exemple, en simulant des éléments de connaissance pour une grande entreprise fictive.

df_kis = pd.read_csv('data/ragas/synthetic_knowledge_items.csv')
df_kis = df_kis[['ki_topic', 'ki_text']]

ki_doc_loader = DataFrameLoader(data_frame=df_kis, page_content_column='ki_text')

ki_docs = ki_doc_loader.load()        

Le corpus est chargé comme un groupe de documents LangChain, prêts à générer l'ensemble de test, mais avant que fait Ragas ?


Dans le contexte de Ragas, une évolution signifie simplement la manière dont une question doit évoluer (ou ne pas évoluer) pour produire un autre type de question. Ragas offre la possibilité de produire 4 types de questions différentes :

  • Simple : Une question directe et simple, sans complexité particulière.
  • Multi-Context: Deux éléments de contexte (deux parties de documents) sont utilisés pour générer une paire question-réponse, au lieu d'un seul comme dans les autres évolutions.
  • Reasoning : La question nécessite un raisonnement logique plus complexe, et la réponse est synthétisée en fonction de cette complexité.
  • Conditional : La question contient une condition particulière qui doit être remplie pour répondre correctement.

Fonctionnement

La génération de jeux de tests dans Ragas, utilise deux modèles de langage (LLM) : un générateur et un critique. Le LLM générateur crée des questions et des réponses à partir de morceaux de documents, tandis que le LLM critique évalue la qualité des questions et des réponses produites. Si le critique juge que la qualité est insuffisante, le générateur réessaye.

Le processus de génération de tests comprend plusieurs étapes :

  1. Sélection aléatoire de morceaux de documents.
  2. Le LLM critique vérifie si le morceau est pertinent.
  3. Le LLM générateur crée une question.
  4. Le critique évalue la qualité de la question.
  5. (Optionnel) Si l'évolution est « raisonnement » ou « conditionnel », la question est compressée.
  6. Le LLM générateur extrait des informations importantes du contexte.
  7. Il produit ensuite une réponse IA à la question.
  8. Le LLM critique évalue la qualité de la réponse, et le processus continue jusqu'à obtention d'une réponse satisfaisante.

J'utilise ici le même LLM pour les deux rôles, bien que cela ne soit pas idéal...

chat_model = ChatOpenAI(model='gpt-4o-mini')
embeddings = OpenAIEmbeddings()

testset_generator = TestsetGenerator.from_langchain(
    generator_llm=chat_model,
    critic_llm=chat_model,
    embeddings=embeddings
)

testset = testset_generator.generate_with_langchain_docs(
    documents=ki_docs,
    test_size=10,
    distributions={
        simple: 0.5,
        reasoning: 0.2,
        multi_context: 0.2,
        conditional: 0.1
    }
)

df_testset = testset.to_pandas()        

La génération de test avec Ragas peut être longue en raison du grand nombre d'appels à l'API, et qu'il est possible de rencontrer des erreurs liées à la limite de taux. De plus, Ragas ne génère pas toutes les données nécessaires : il produit une question et une colonne "ground_truth", mais cette dernière est davantage une réponse générée par IA. je vais renommer cette "ground_truth" en "answer" et créer une nouvelle "ground_truth" en utilisant une invite personnalisée.

Dans le cas d'un RAG en production, ces étapes ne sont pas nécessaires car le jeu de données devrait fournir les réponses exact.
df_testset.rename(columns={'ground_truth': 'answer'}, inplace=True)
df_testset['ground_truth'] = ''        

Génération

GT_SIMULATION_PROMPT = '''vous êtes un évaluateur expert pour les systèmes de réponse aux questions. Votre tâche consiste à fournir la réponse idéale basée sur la vérité en fonction de la question et du contexte donnés. Veuillez suivre les lignes directrices suivantes:

1. Question: {question}

2. Context: {context}

3. Instructions:
   - Analyser attentivement la question et le contexte fourni.
   - Formulez une réponse complète et précise en vous basant uniquement sur les informations fournies dans le contexte.
   - Veillez à ce que votre réponse réponde directement à la question.
   - Incluez toutes les informations pertinentes du contexte, mais n'ajoutez pas de connaissances externes.
   - Si le contexte ne contient pas suffisamment d'informations pour répondre entièrement à la question, indiquez-le clairement et donnez la meilleure réponse partielle possible.
   - Utilisez un ton formel et objectif.

N'oubliez pas que votre objectif est de fournir la réponse idéale qui servira de référence pour évaluer les performances de l'IA.'''

# Create the prompt template
gt_generation_prompt = ChatPromptTemplate.from_messages(messages=[
    HumanMessagePromptTemplate.from_template(template=GT_SIMULATION_PROMPT)
])

llama_model = Ollama(model='llama3.2')

# Create LLMChain to link the prompt and the model
gt_generation_chain = LLMChain(
    llm=llama_model,
    prompt=gt_generation_prompt
)

def generate_ground_truth_text(row):
    '''
    Génère un texte simulé en fonction de la question et du contexte fournis.
    
    Inputs:
        - row (Pandas DataFrame record): Un seul enregistrement du DataFrame Pandas
        
    Returns:
        - gt_text (str): Le texte généré par le modèle d'IA pour l'enregistrement
    '''
    if row['ground_truth'] == '':
        gt_text = gt_generation_chain.predict(
            question=row['question'],
            context=row['contexts']
        )
        
        return gt_text.strip()
    
    else:
        return row['ground_truth']

df_testset['ground_truth'] = df_testset.apply(generate_ground_truth_text, axis=1)

df_testset.to_csv('data/ragas/df_testset.csv', index=False)

df_testset = pd.read_csv('data/ragas/df_testset.csv')        

J'ai maintenant un DataFrame Pandas qui contient les quatre éléments d'information nécessaires au calcul des métriques Ragas !

Calcul des métriques de Ragas

Actuellement, le jeu de test est sous forme de DataFrame Pandas, mais Ragas ne peut pas traiter directement ces DataFrames. Nous devons donc les convertir dans un format compatible. Plus précisément, Ragas requiert que les données soient dans un format de jeu de données spécifique à Hugging Face.

def pandas_to_ragas(df):
    '''
    Convertit un DataFrame Pandas en un jeu de données compatible avec Ragas
    
    Inputs:
        - df (Pandas DataFrame): Le DataFrame d'entrée à convertir
        
    Returns:
        - ragas_testset (Hugging Face Dataset): Un jeu de données Hugging Face compatible avec Ragas
    '''
    text_columns = ['question', 'ground_truth', 'answer']
    for col in text_columns:
        df[col] = df[col].fillna('').astype(str)

    df['contexts'] = df['contexts'].fillna('').astype(str).apply(lambda x: [x] if x else [])

    data_dict = df[['question', 'contexts', 'answer', 'ground_truth']].to_dict('list')

    ragas_testset = Dataset.from_dict(data_dict)
    
    return ragas_testset

ragas_testset = pandas_to_ragas(df=df_testset)        

Ragas est prêt à être lancé !


ragas_scores = evaluate(
    dataset=ragas_testset,
    llm=ChatOpenAI(model='gpt-4o-mini'),
    metrics=[
        faithfulness,
        answer_relevancy,
        context_precision,
        context_recall,
        context_entity_recall,
        answer_similarity,
        answer_correctness
    ]
)

df_ragas_scores = ragas_scores.to_pandas()

df_ragas_scores.to_csv('data/ragas/ragas_scores.csv', index=False)

df_ragas_scores = pd.read_csv('data/ragas/ragas_scores.csv')

# Display various Ragas scores
print(df_ragas_scores[['question', 'contexts', 'answer', 'faithfulness']])
print(df_ragas_scores[['answer', 'contexts', 'answer_relevancy']])
print(df_ragas_scores[['question', 'contexts', 'ground_truth', 'context_recall']])
print(df_ragas_scores[['question', 'contexts', 'answer', 'context_precision']])
print(df_ragas_scores[['question', 'contexts', 'answer']])
print(df_ragas_scores[['contexts', 'ground_truth', 'context_entity_recall']])
print(df_ragas_scores[['answer', 'ground_truth', 'answer_similarity']])
print(df_ragas_scores[['question', 'answer', 'ground_truth', 'answer_correctness']])
print(df_ragas_scores[['question', 'answer', 'contexts', 'ground_truth']])        

Ragas regroupe les différentes métriques d'évaluation en trois grandes catégories :

Évaluation par composant :

Ces métriques évaluent des éléments spécifiques des données RAG. Elles incluent :

  • Faithfulness : Cohérence factuelle entre la réponse IA et le contexte.
  • Answer Relevancy : Pertinence de la réponse par rapport à la question.
  • Context Precision : Pertinence du contexte pour répondre à la question.
  • Context Recall : Vérification si les déclarations de la réponse correspondent au contexte.
  • Context Relevancy : Vérification de la pertinence des phrases du contexte pour répondre à la question.
  • Context Entity Recall : Comparaison des entités présentes dans le contexte et la réponse.

Évaluation de bout en bout :

Ces métriques mesurent l'efficacité de la réponse finale de l'IA à la question originale.

  • Answer Semantic Similarity : Similarité sémantique entre la réponse de l'IA et la réponse exacte (ground truth).
  • Answer Correctness : Précision de la réponse de l'IA par rapport à la vérité terrain, basée sur un score F1 et la similarité sémantique.

Critique d'aspects :

Bien que Ragas ne classe pas officiellement ces métriques dans une catégorie, elles évaluent différents aspects de la réponse, chaque aspect étant jugé par le LLM. Ces critiques incluent :

  • Harmfulness : La réponse peut-elle causer des dommages ?
  • Maliciousness : La réponse est-elle intentionnellement nuisible ?
  • Coherence : La réponse est-elle logique et bien organisée ?
  • Correctness : La réponse est-elle factuellement correcte ?
  • Conciseness : La réponse est-elle claire et concise ?

Chaque aspect est évalué indépendamment avec un score de 0 ou 1.

Conclusion

Il est bon de se rappeler que, bien qu'il ne soit pas idéal d'évaluer un modèle avec un autre modèle, il faut tirer le meilleur parti de la situation en utilisant les ressources disponibles. Ragas calcule de nombreuses métriques, ce qui évite de se fier uniquement à une seule mesure pouvant être ambiguë. La précision et le rappel du contexte, reflètent des métriques statistiques connues. Ragas est donc un cadre intéressant.


Identifiez-vous pour afficher ou ajouter un commentaire

Autres pages consultées

Explorer les sujets