Exercice : évaluations de prompts
Sur cette page
Cet exercice, complément de notre adaptation, assemble toute la section : un prompt, un jeu de test, un pipeline, un notateur par modèle, une note de référence, puis une amélioration mesurée. Le sujet change pour que vous transposiez la méthode plutôt que de recopier le code AWS : résumer un CV en trois points.
Objectif
Vous développez un outil qui prend un CV et produit un résumé en trois points clés, exact, concis et complet. Vous allez :
- écrire un prompt naïf ;
- constituer un petit jeu de test ;
- écrire
run_prompt,run_test_caseetrun_eval; - écrire un notateur par modèle sur trois critères ;
- mesurer une note de référence ;
- améliorer le prompt et comparer.
Étape 1 : le prompt naïf
PROMPT_V1 = "Résume ce CV en 3 points."
Étape 2 : le jeu de test
Trois CV fictifs, de profils différents, avec pour chacun les informations que le résumé devrait faire ressortir. C’est trop peu pour conclure, assez pour monter la mécanique ; complétez-le ensuite avec la méthode de la leçon 18.
test_cases = [
{
"input": """CV - Sophie Martin
Poste actuel : directrice marketing chez TechVision (depuis 2020)
Expérience précédente : responsable communication chez DataCorp (2015-2020)
Formation : master marketing digital, HEC Paris (2014)
Compétences : SEO/SEA, management d'équipe (12 personnes), budget de 2 M€ par an
Réalisations : +45 % de prospects qualifiés en deux ans, lancement de trois produits SaaS
Langues : français (natif), anglais (C1), espagnol (B2)""",
"expected_focus": "Marketing digital, management, résultats chiffrés",
},
{
"input": """CV - Ahmed Benali
Poste actuel : développeur full-stack senior chez CloudNine (depuis 2021)
Expérience précédente : développeur backend chez StartupFlow (2018-2021), stage chez IBM (2017)
Formation : ingénieur en informatique, INSA Lyon (2018)
Compétences : Python, TypeScript, React, AWS, Docker, Kubernetes, PostgreSQL
Réalisations : architecture microservices servant 2 millions d'utilisateurs, latence réduite de 60 %
Certifications : AWS Solutions Architect, Kubernetes CKA
Langues : français (natif), anglais (C1), arabe (B1)""",
"expected_focus": "Full-stack senior, cloud et DevOps, performance à grande échelle",
},
{
"input": """CV - Marie Dupont
Situation : en recherche d'emploi, disponible immédiatement
Dernière expérience : assistante de direction chez Groupe Renard (2019-2024)
Expériences précédentes : assistante administrative chez PME Martin (2016-2019), hôtesse d'accueil chez EventPro (2014-2016)
Formation : BTS assistant de manager, lycée Condorcet (2014)
Compétences : suite bureautique avancée, gestion d'agendas, organisation d'événements, rédaction de comptes rendus
Réalisations : plus de 50 événements d'entreprise organisés, assistance simultanée de trois directeurs
Langues : français (natif), anglais (B1)""",
"expected_focus": "Assistanat de direction, organisation, polyvalence",
},
]
Étapes 3 et 4 : le pipeline et le notateur
Écrivez-les avant d’ouvrir la solution. Deux exigences : le notateur rend trois notes entières de 0 à 10 (exactitude, concision, couverture) et une courte justification, par une sortie structurée ; une notation impossible n’est jamais remplacée par une note inventée.
Voir la solution
import json
from anthropic import Anthropic
client = Anthropic()
MODEL = "claude-sonnet-5-5"
def text_of(message):
return "".join(block.text for block in message.content if block.type == "text")
def run_prompt(cv_text: str, prompt: str) -> str:
message = client.messages.create(
model=MODEL,
max_tokens=4096,
messages=[{"role": "user", "content": f"{prompt}\n\n<cv>\n{cv_text}\n</cv>"}],
)
return text_of(message)
SCHEMA_NOTES = {
"type": "object",
"properties": {
"justification": {"type": "string"},
"exactitude": {"type": "integer", "description": "0 à 10"},
"concision": {"type": "integer", "description": "0 à 10"},
"couverture": {"type": "integer", "description": "0 à 10"},
},
"required": ["justification", "exactitude", "concision", "couverture"],
"additionalProperties": False,
}
def model_grader(case: dict, summary: str):
prompt = f"""Tu évalues des résumés de CV. Note le résumé sur trois critères, de 0 à 10 chacun.
<cv>{case["input"]}</cv>
<resume>{summary}</resume>
<informations_attendues>{case["expected_focus"]}</informations_attendues>
1. Exactitude : les informations du résumé sont-elles fidèles au CV ?
2. Concision : trois points, sans superflu ?
3. Couverture : les informations les plus importantes sont-elles présentes (poste, compétences clés, réalisations) ?
Donne une courte justification, puis les trois notes."""
message = client.messages.create(
model=MODEL,
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
output_config={"format": {"type": "json_schema", "schema": SCHEMA_NOTES}},
)
try:
notes = json.loads(text_of(message))
except json.JSONDecodeError:
return None # notation impossible (réponse tronquée, refus)
notes["moyenne"] = round((notes["exactitude"] + notes["concision"] + notes["couverture"]) / 3, 2)
return notes
def run_test_case(case: dict, prompt: str) -> dict:
summary = run_prompt(case["input"], prompt)
return {"case": case, "summary": summary, "notes": model_grader(case, summary)}
def run_eval(cases: list, prompt: str) -> dict:
results = [run_test_case(case, prompt) for case in cases]
notes = [r["notes"] for r in results if r["notes"] is not None]
moyenne = round(sum(n["moyenne"] for n in notes) / len(notes), 2)
par_critere = {k: round(sum(n[k] for n in notes) / len(notes), 2)
for k in ("exactitude", "concision", "couverture")}
print(f"Moyenne : {moyenne}/10 | {par_critere} | notations impossibles : {len(results) - len(notes)}")
return {"results": results, "average": moyenne, "by_criteria": par_critere}
Étapes 5 et 6 : mesurer, améliorer, comparer
results_v1 = run_eval(test_cases, PROMPT_V1)
PROMPT_V2 = """Tu es un expert en recrutement. Résume le CV fourni en exactement trois points.
Règles :
- chaque point commence par un tiret ;
- point 1 : poste actuel et niveau d'expérience (junior, confirmé ou senior) ;
- point 2 : les compétences techniques ou métier les plus différenciantes ;
- point 3 : la réalisation chiffrée la plus marquante ;
- 25 mots au plus par point ;
- ni introduction ni conclusion."""
results_v2 = run_eval(test_cases, PROMPT_V2)
print(f"V1 : {results_v1['average']}/10 → V2 : {results_v2['average']}/10 "
f"({results_v2['average'] - results_v1['average']:+.2f})")
Lisez aussi les moyennes par critère : la V2 gagne le plus souvent en concision et en couverture, puisqu’elle dit quoi garder ; si l’exactitude baisse, c’est qu’un point est forcé alors que le CV n’a pas l’information (le troisième CV n’a pas de réalisation chiffrée au sens strict). Ajustez la règle, relancez, et faites passer chaque version deux ou trois fois avant de conclure.
À vous de jouer
Faites tourner l’exercice tel quel, puis transposez-le à votre propre tâche : vos cas, votre grille de trois critères, votre prompt. Visez une V2 qui gagne au moins un point de moyenne sans perdre sur aucun critère.
Sources officielles : Running the eval, Model based grading et Code based grading (Claude Academy) · Structured outputs (documentation Claude)
Points clés à retenir
- Un pipeline réutilisable :
run_prompt,run_test_case,run_eval, plus un notateur par modèle. - Des critères adaptés à la tâche, notés séparément : la moyenne globale ne suffit pas à comprendre un changement.
- Un verdict structuré, et aucune note inventée quand la notation échoue.
- On mesure, on améliore, on compare sur le même jeu, en répétant les exécutions.