Exercice : evaluations de prompts
Objectif
Construire un pipeline d’evaluation complet pour un prompt de resume de CV. Vous allez :
- Ecrire un prompt initial
- Creer un jeu de donnees de test
- Implementer les fonctions d’evaluation
- Ajouter un notateur par modele
- Mesurer un score de reference
- Ameliorer le prompt et comparer les scores
Contexte
Vous developpez un outil qui prend un CV professionnel et produit un resume en 3 points cles. L’outil doit extraire les informations les plus importantes de maniere concise et precise.
Etape 1 : Le prompt initial (naif)
Commencez avec un prompt simple, sans optimisation :
PROMPT_V1 = "Resume ce CV en 3 points."
Etape 2 : Creer le jeu de donnees de test
Creez 3 CV fictifs couvrant des profils differents. Vous pouvez les ecrire vous-meme ou demander a Claude de les generer.
test_cases = [
{
"input": """CV - Sophie Martin
Poste actuel : Directrice Marketing chez TechVision (2020-present)
Experience precedente : Responsable Communication chez DataCorp (2015-2020)
Formation : Master Marketing Digital, HEC Paris (2014)
Competences : SEO/SEA, gestion d'equipe (12 personnes), budget 2M EUR/an
Realisations : +45% de leads qualifies en 2 ans, lancement de 3 produits SaaS
Langues : Francais (natif), Anglais (C1), Espagnol (B2)""",
"expected_focus": "Marketing digital, management, resultats chiffres"
},
{
"input": """CV - Ahmed Benali
Poste actuel : Developpeur Full-Stack Senior chez CloudNine (2021-present)
Experience precedente : Developpeur Backend chez StartupFlow (2018-2021), Stage chez IBM (2017)
Formation : Ingenieur Informatique, INSA Lyon (2018)
Competences : Python, TypeScript, React, AWS, Docker, Kubernetes, PostgreSQL
Realisations : Architecture microservices servant 2M utilisateurs, reduction latence de 60%
Certifications : AWS Solutions Architect, Kubernetes CKA
Langues : Francais (natif), Anglais (C1), Arabe (B1)""",
"expected_focus": "Full-stack senior, cloud/DevOps, performance a grande echelle"
},
{
"input": """CV - Marie Dupont
Poste actuel : Recherche d'emploi (disponible immediatement)
Derniere experience : Assistante de direction chez Groupe Renard (2019-2024)
Experiences precedentes : Assistante administrative chez PME Martin (2016-2019), Hotesse d'accueil chez EventPro (2014-2016)
Formation : BTS Assistant de Manager, Lycee Condorcet (2014)
Competences : Pack Office avance, gestion d'agenda, organisation d'evenements, redaction de comptes-rendus
Realisations : Organisation de 50+ evenements corporate, gestion simultanee de 3 directeurs
Langues : Francais (natif), Anglais (B1)""",
"expected_focus": "Assistanat de direction, organisation, polyvalence"
}
]
Etape 3 : Implementer le pipeline d’evaluation
import anthropic
client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-20250514"
def run_prompt(cv_text: str, prompt_template: str) -> str:
"""Envoie le CV a Claude avec le prompt donne et retourne la reponse."""
full_prompt = f"{prompt_template}\n\n{cv_text}"
response = client.messages.create(
model=MODEL,
max_tokens=512,
messages=[{"role": "user", "content": full_prompt}]
)
return response.content[0].text
def run_test_case(test_case: dict, prompt_template: str) -> dict:
"""Execute un cas de test et retourne la reponse avec les metadonnees."""
output = run_prompt(test_case["input"], prompt_template)
return {
"input": test_case["input"],
"expected_focus": test_case["expected_focus"],
"output": output
}
Etape 4 : Le notateur par modele
Le notateur evalue chaque resume sur trois criteres : exactitude, concision et couverture des informations cles.
def model_grader(result: dict) -> dict:
"""Note le resume sur 3 criteres via un appel a Claude."""
grading_prompt = f"""Tu es un evaluateur de resumes de CV. Evalue le resume suivant sur 3 criteres, chacun note de 0 a 10.
CV original :
{result['input']}
Resume produit :
{result['output']}
Informations cles attendues : {result['expected_focus']}
Criteres :
1. **Exactitude** : Les informations du resume sont-elles correctes et fideles au CV ?
2. **Concision** : Le resume est-il court et va-t-il a l'essentiel (3 points, pas de superflu) ?
3. **Couverture** : Les informations les plus importantes sont-elles presentes (poste, competences cles, realisations) ?
Reponds UNIQUEMENT au format JSON :
{{"exactitude": X, "concision": X, "couverture": X}}"""
response = client.messages.create(
model=MODEL,
max_tokens=100,
messages=[{"role": "user", "content": grading_prompt}]
)
import json
try:
scores = json.loads(response.content[0].text)
scores["moyenne"] = round(
(scores["exactitude"] + scores["concision"] + scores["couverture"]) / 3, 2
)
return scores
except (json.JSONDecodeError, KeyError):
return {"exactitude": 0, "concision": 0, "couverture": 0, "moyenne": 0}
Etape 5 : La fonction d’evaluation complete
def run_eval(test_cases: list, prompt_template: str) -> dict:
"""Execute l'evaluation complete et retourne les resultats."""
print(f"\n{'='*60}")
print(f"EVALUATION DU PROMPT")
print(f"{'='*60}")
print(f"Prompt : {prompt_template[:80]}...")
print(f"Nombre de cas de test : {len(test_cases)}\n")
all_scores = []
for i, case in enumerate(test_cases):
print(f"--- Cas de test {i+1} ---")
result = run_test_case(case, prompt_template)
scores = model_grader(result)
print(f"Resume produit :\n{result['output']}\n")
print(f"Scores : Exactitude={scores['exactitude']}, "
f"Concision={scores['concision']}, "
f"Couverture={scores['couverture']}, "
f"Moyenne={scores['moyenne']}")
print()
all_scores.append(scores)
# Score global
avg_exactitude = round(sum(s["exactitude"] for s in all_scores) / len(all_scores), 2)
avg_concision = round(sum(s["concision"] for s in all_scores) / len(all_scores), 2)
avg_couverture = round(sum(s["couverture"] for s in all_scores) / len(all_scores), 2)
avg_global = round(sum(s["moyenne"] for s in all_scores) / len(all_scores), 2)
print(f"{'='*60}")
print(f"SCORES GLOBAUX")
print(f" Exactitude : {avg_exactitude}/10")
print(f" Concision : {avg_concision}/10")
print(f" Couverture : {avg_couverture}/10")
print(f" MOYENNE : {avg_global}/10")
print(f"{'='*60}")
return {
"detail": all_scores,
"average": avg_global,
"by_criteria": {
"exactitude": avg_exactitude,
"concision": avg_concision,
"couverture": avg_couverture
}
}
Etape 6 : Executer, ameliorer, comparer
Baseline (prompt naif)
PROMPT_V1 = "Resume ce CV en 3 points."
results_v1 = run_eval(test_cases, PROMPT_V1)
Prompt ameliore
PROMPT_V2 = """Tu es un expert en recrutement. Analyse le CV ci-dessous et produis un resume en exactement 3 points cles.
Regles :
- Chaque point commence par un tiret (-)
- Point 1 : Poste actuel et niveau d'experience (junior/confirme/senior)
- Point 2 : Competences techniques ou metier les plus differenciantes
- Point 3 : Realisation chiffree la plus marquante
- Maximum 25 mots par point
- Pas d'introduction ni de conclusion, uniquement les 3 points"""
results_v2 = run_eval(test_cases, PROMPT_V2)
Comparaison des resultats
print(f"\n{'='*60}")
print(f"COMPARAISON")
print(f"{'='*60}")
print(f"Prompt V1 (naif) : {results_v1['average']}/10")
print(f"Prompt V2 (ameliore): {results_v2['average']}/10")
print(f"Amelioration : {results_v2['average'] - results_v1['average']:+.2f} points")
Solution complete
Voici le code complet en un seul fichier :
"""
Pipeline d'evaluation complet pour un resume de CV.
Necessite : pip install anthropic
Variable d'environnement : ANTHROPIC_API_KEY
"""
import anthropic
import json
client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-20250514"
# --- Jeu de donnees ---
test_cases = [
{
"input": """CV - Sophie Martin
Poste actuel : Directrice Marketing chez TechVision (2020-present)
Experience precedente : Responsable Communication chez DataCorp (2015-2020)
Formation : Master Marketing Digital, HEC Paris (2014)
Competences : SEO/SEA, gestion d'equipe (12 personnes), budget 2M EUR/an
Realisations : +45% de leads qualifies en 2 ans, lancement de 3 produits SaaS
Langues : Francais (natif), Anglais (C1), Espagnol (B2)""",
"expected_focus": "Marketing digital, management, resultats chiffres"
},
{
"input": """CV - Ahmed Benali
Poste actuel : Developpeur Full-Stack Senior chez CloudNine (2021-present)
Experience precedente : Developpeur Backend chez StartupFlow (2018-2021), Stage chez IBM (2017)
Formation : Ingenieur Informatique, INSA Lyon (2018)
Competences : Python, TypeScript, React, AWS, Docker, Kubernetes, PostgreSQL
Realisations : Architecture microservices servant 2M utilisateurs, reduction latence de 60%
Certifications : AWS Solutions Architect, Kubernetes CKA
Langues : Francais (natif), Anglais (C1), Arabe (B1)""",
"expected_focus": "Full-stack senior, cloud/DevOps, performance a grande echelle"
},
{
"input": """CV - Marie Dupont
Poste actuel : Recherche d'emploi (disponible immediatement)
Derniere experience : Assistante de direction chez Groupe Renard (2019-2024)
Experiences precedentes : Assistante administrative chez PME Martin (2016-2019), Hotesse d'accueil chez EventPro (2014-2016)
Formation : BTS Assistant de Manager, Lycee Condorcet (2014)
Competences : Pack Office avance, gestion d'agenda, organisation d'evenements, redaction de comptes-rendus
Realisations : Organisation de 50+ evenements corporate, gestion simultanee de 3 directeurs
Langues : Francais (natif), Anglais (B1)""",
"expected_focus": "Assistanat de direction, organisation, polyvalence"
}
]
# --- Fonctions du pipeline ---
def run_prompt(cv_text: str, prompt_template: str) -> str:
full_prompt = f"{prompt_template}\n\n{cv_text}"
response = client.messages.create(
model=MODEL,
max_tokens=512,
messages=[{"role": "user", "content": full_prompt}]
)
return response.content[0].text
def run_test_case(test_case: dict, prompt_template: str) -> dict:
output = run_prompt(test_case["input"], prompt_template)
return {
"input": test_case["input"],
"expected_focus": test_case["expected_focus"],
"output": output
}
def model_grader(result: dict) -> dict:
grading_prompt = f"""Tu es un evaluateur de resumes de CV. Evalue le resume suivant sur 3 criteres, chacun note de 0 a 10.
CV original :
{result['input']}
Resume produit :
{result['output']}
Informations cles attendues : {result['expected_focus']}
Criteres :
1. Exactitude : Les informations sont-elles correctes et fideles au CV ?
2. Concision : Le resume va-t-il a l'essentiel (3 points, pas de superflu) ?
3. Couverture : Les informations les plus importantes sont-elles presentes ?
Reponds UNIQUEMENT au format JSON :
{{"exactitude": X, "concision": X, "couverture": X}}"""
response = client.messages.create(
model=MODEL,
max_tokens=100,
messages=[{"role": "user", "content": grading_prompt}]
)
try:
scores = json.loads(response.content[0].text)
scores["moyenne"] = round(
(scores["exactitude"] + scores["concision"] + scores["couverture"]) / 3, 2
)
return scores
except (json.JSONDecodeError, KeyError):
return {"exactitude": 0, "concision": 0, "couverture": 0, "moyenne": 0}
def run_eval(test_cases: list, prompt_template: str) -> dict:
print(f"\n{'='*60}")
print(f"EVALUATION")
print(f"{'='*60}\n")
all_scores = []
for i, case in enumerate(test_cases):
result = run_test_case(case, prompt_template)
scores = model_grader(result)
print(f"Cas {i+1} — Moyenne: {scores['moyenne']}/10")
print(f" Resume: {result['output'][:120]}...\n")
all_scores.append(scores)
avg = round(sum(s["moyenne"] for s in all_scores) / len(all_scores), 2)
print(f"SCORE MOYEN : {avg}/10\n")
return {"detail": all_scores, "average": avg}
# --- Execution ---
PROMPT_V1 = "Resume ce CV en 3 points."
PROMPT_V2 = """Tu es un expert en recrutement. Analyse le CV ci-dessous et produis un resume en exactement 3 points cles.
Regles :
- Chaque point commence par un tiret (-)
- Point 1 : Poste actuel et niveau d'experience
- Point 2 : Competences les plus differenciantes
- Point 3 : Realisation chiffree la plus marquante
- Maximum 25 mots par point
- Pas d'introduction ni de conclusion"""
print("=== PROMPT V1 (naif) ===")
r1 = run_eval(test_cases, PROMPT_V1)
print("=== PROMPT V2 (ameliore) ===")
r2 = run_eval(test_cases, PROMPT_V2)
print(f"\nCOMPARAISON : V1={r1['average']}/10 → V2={r2['average']}/10 ({r2['average']-r1['average']:+.2f})")
Ce que vous apprenez
- Structurer un pipeline d’evaluation avec des fonctions reutilisables
- Definir des criteres de notation adaptes a votre cas d’usage
- Mesurer l’impact d’un changement de prompt avec des metriques chiffrees
- Iterer sur un prompt de maniere methodique plutot qu’au feeling