Aller au contenu principal

Exécuter l'évaluation

Mis à jour le 30 juillet 2026

Les 3 fonctions du pipeline

Le découpage en trois fonctions n’est pas une coquetterie d’architecture : chacune isole une chose qui peut varier indépendamment. Le prompt change à chaque itération, la méthode de notation change une fois (au chapitre suivant), et l’orchestration ne change jamais. Séparer les trois, c’est pouvoir remplacer l’une sans toucher aux autres.

  1. run_prompt() : fusionne un cas de test avec le template de prompt et appelle Claude
  2. run_test_case() : exécute le prompt puis note le résultat
  3. run_eval() : orchestre l’évaluation sur tous les cas de test

Le prompt à évaluer

On reprend le contexte de la leçon précédente : un assistant qui génère du code AWS.

PROMPT_TEMPLATE = """Tu es un expert AWS. Génère du code propre et fonctionnel.

Contexte : {context}
Type de sortie attendu : {type}

Requête : {input}"""

Les champs entre accolades ({context}, {type}, {input}) seront remplacés par les données de chaque cas de test.

Fonction 1 : run_prompt()

Cette fonction prend un cas de test et le template de prompt, fusionne les deux, et envoie à Claude :

import anthropic
import json

client = anthropic.Anthropic()

def run_prompt(test_case, prompt_template):
    """
    Fusionne le cas de test avec le template et appelle Claude.
    Retourne la réponse brute de Claude.
    """
    # Remplir le template avec les données du cas de test
    prompt = prompt_template.format(
        context=test_case["context"],
        type=test_case["type"],
        input=test_case["input"]
    )

    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        temperature=0,  # Déterministe pour la reproductibilité
        messages=[{"role": "user", "content": prompt}]
    )

    return response.content[0].text

Note : temperature=0 est important pour l’évaluation, et pour une raison précise. Sans cela, deux exécutions du même prompt donnent deux scores différents — et vous ne savez plus si l’écart entre V1 et V2 vient de votre modification ou du simple hasard d’échantillonnage. La température à 0 ne rend pas les réponses meilleures ; elle rend la comparaison possible.

Fonction 2 : run_test_case()

Cette fonction exécute le prompt et note le résultat. Pour l’instant, on met un score placeholder (on implémentera la notation par modèle dans la leçon suivante) :

def run_test_case(test_case, prompt_template):
    """
    Exécute un cas de test : appelle Claude puis note la réponse.
    Retourne un dictionnaire avec l'input, la réponse et le score.
    """
    # Obtenir la réponse de Claude
    response = run_prompt(test_case, prompt_template)

    # Notation placeholder (sera remplacée par notation par modèle)
    score = 10  # Score temporaire

    return {
        "input": test_case["input"],
        "type": test_case["type"],
        "context": test_case["context"],
        "difficulty": test_case.get("difficulty", "non spécifié"),
        "response": response,
        "score": score
    }

Fonction 3 : run_eval()

La fonction principale qui orchestre l’ensemble :

def run_eval(dataset, prompt_template):
    """
    Exécute l'évaluation complete sur tout le dataset.
    Retourne la liste des résultats et le score moyen.
    """
    results = []

    for i, test_case in enumerate(dataset):
        print(f"Cas {i+1}/{len(dataset)} : {test_case['input'][:50]}...")

        result = run_test_case(test_case, prompt_template)
        results.append(result)

        print(f"  Score : {result['score']}/10")

    # Calcul du score moyen
    avg_score = sum(r["score"] for r in results) / len(results)

    print(f"\n{'='*50}")
    print(f"Score moyen : {avg_score:.2f}/10")
    print(f"Cas évalués : {len(results)}")

    return results, avg_score

Charger le dataset et lancer

# Charger le dataset généré précédemment
with open("dataset.json", "r", encoding="utf-8") as f:
    dataset = json.load(f)

print(f"Dataset chargé : {len(dataset)} cas de test\n")

# Lancer l'évaluation
results, avg_score = run_eval(dataset, PROMPT_TEMPLATE)

Sortie typique :

Dataset charge : 30 cas de test

Cas 1/30 : Ecris un script qui cree un bucket S3 avec un nom ...
  Score : 10/10
Cas 2/30 : Ecris une fonction Lambda qui declenche une notifi...
  Score : 10/10
...
Cas 30/30 : Genere une regex qui valide un ARN AWS avec region...
  Score : 10/10

==================================================
Score moyen : 10.00/10
Cas evalues : 30

Évidemment, avec le score placeholder à 10, tous les résultats sont parfaits. La prochaine leçon introduit la notation par modèle pour obtenir des scores réels.

Examiner les résultats en détail

# Sauvegarder les résultats
with open("eval_results.json", "w", encoding="utf-8") as f:
    json.dump(results, f, indent=2, ensure_ascii=False)

# Analyser par categorie
from collections import defaultdict

scores_par_type = defaultdict(list)
for r in results:
    scores_par_type[r["type"]].append(r["score"])

print("\nScores par type :")
for type_code, scores in scores_par_type.items():
    avg = sum(scores) / len(scores)
    print(f"  {type_code:10s} : {avg:.2f}/10 ({len(scores)} cas)")

# Analyser par difficulte
scores_par_diff = defaultdict(list)
for r in results:
    scores_par_diff[r["difficulty"]].append(r["score"])

print("\nScores par difficulte :")
for diff, scores in scores_par_diff.items():
    avg = sum(scores) / len(scores)
    print(f"  {diff:10s} : {avg:.2f}/10 ({len(scores)} cas)")

Comparer deux prompts

C’est l’aboutissement de tout ce montage, et la seule comparaison qui ait du sens : même dataset, même notateur, même température — une seule variable change, le prompt. Tout protocole qui fait varier deux choses à la fois produit un chiffre dont personne ne peut rien conclure.

PROMPT_V1 = """Tu es un expert AWS. Génère du code propre et fonctionnel.

Contexte : {context}
Type de sortie attendu : {type}

Requête : {input}"""

PROMPT_V2 = """Tu es un ingenieur cloud AWS senior. Génère du code de qualite production.

Regles :
- Code commente et lisible
- Gestion des erreurs incluse
- Respecte les bonnes pratiques AWS

Contexte : {context}
Type de sortie : {type}

Requête : {input}"""

# Évaluer les deux versions
print("=== Évaluation V1 ===")
results_v1, score_v1 = run_eval(dataset, PROMPT_V1)

print("\n=== Évaluation V2 ===")
results_v2, score_v2 = run_eval(dataset, PROMPT_V2)

print(f"\nComparaison :")
print(f"  V1 : {score_v1:.2f}/10")
print(f"  V2 : {score_v2:.2f}/10")
print(f"  Delta : {score_v2 - score_v1:+.2f}")

Résumé

Le pipeline est en place. Les trois fonctions se décomposent clairement :

FonctionRôleEntréeSortie
run_prompt()Appeler Claudecas + templatetexte brut
run_test_case()Exécuter + notercas + templaterésultat + score
run_eval()Orchestrerdataset + templaterésultats + moyenne

Il ne manque qu’une pièce : remplacer le score placeholder par une notation réelle. C’est l’objet de la prochaine leçon.