Notation par code
Mis à jour le 30 juillet 2026
Pourquoi noter avec du code ?
Les notateurs par modèle sont puissants, mais ils ont un défaut : ils ne peuvent pas vérifier de manière fiable si une sortie est du code valide, du JSON bien formé ou une expression régulière correcte. Pour ça, rien ne vaut un validateur programmatique.
Un notateur par code (code grader) est une fonction Python qui prend la réponse de Claude et retourne un score numérique. C’est déterministe, instantané et gratuit (pas d’appel API).
Les trois fonctions de validation
1. Validation JSON
import json
def validate_json(output: str) -> int:
"""Vérifie si la sortie est du JSON valide."""
try:
json.loads(output)
return 10 # JSON valide
except json.JSONDecodeError:
return 0 # JSON invalide
2. Validation Python
import ast
def validate_python(output: str) -> int:
"""Vérifie si la sortie est du Python syntaxiquement correct."""
try:
ast.parse(output)
return 10 # Python valide
except SyntaxError:
return 0 # Syntaxe incorrecte
3. Validation Regex
import re
def validate_regex(output: str) -> int:
"""Vérifie si la sortie est une expression reguliere valide."""
try:
re.compile(output)
return 10 # Regex valide
except re.error:
return 0 # Regex invalide
Le principe est le même pour les trois : on essaie de parser la sortie avec la bibliothèque appropriée. Si ça fonctionne, score de 10. Sinon, 0. Pas de demi-mesure.
Adapter le jeu de données
Pour que le notateur par code sache quelle fonction de validation appliquer, chaque cas de test doit inclure un champ "format" :
test_cases = [
{
"input": "Génère un JSON avec les cles 'nom', 'age' et 'ville' pour une personne fictive.",
"format": "json"
},
{
"input": "Écris une fonction Python qui inverse une chaîne de caractères.",
"format": "python"
},
{
"input": "Écris une regex qui valide une adresse email simple.",
"format": "regex"
}
]
Le notateur par code complet
def code_grader(output: str, format_type: str) -> int:
"""Notateur par code qui dispatch vers la bonne fonction de validation."""
validators = {
"json": validate_json,
"python": validate_python,
"regex": validate_regex
}
validator = validators.get(format_type)
if validator is None:
raise ValueError(f"Format inconnu : {format_type}")
return validator(output)
Améliorer le prompt pour de meilleurs scores
Si le notateur par code donne de mauvais scores, c’est souvent parce que Claude ajoute du texte explicatif autour du code. Le correctif est simple : être explicite dans le prompt.
Avant (prompt vague) :
Genere du code Python qui trie une liste.
Après (prompt spécifique) :
Reponds uniquement avec du code Python, sans explication, sans markdown, sans bloc de code.
Genere une fonction qui trie une liste d'entiers par ordre croissant.
L’instruction clé : “Réponds uniquement avec du Python/JSON/Regex” élimine le bruit et permet au validateur de fonctionner correctement.
Combiner notateur par modèle et notateur par code
L’approche la plus robuste combine les deux types de notation. Le notateur par code vérifie la forme (syntaxe valide), le notateur par modèle vérifie le fond (qualité, pertinence, exactitude).
def combined_grader(output: str, test_case: dict) -> float:
"""Combine la notation par code et par modèle."""
# Score de forme (syntaxe valide ?)
format_score = code_grader(output, test_case["format"])
# Score de fond (qualité de la réponse)
quality_score = model_grader(output, test_case)
# Moyenne des deux scores
final_score = (format_score + quality_score) / 2
return final_score
Exemple d’exécution complète
import anthropic
import json
import ast
import re
client = anthropic.Anthropic()
def run_prompt(user_input: str) -> str:
"""Exécute le prompt et retourne la réponse de Claude."""
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": user_input}]
)
return response.content[0].text
def model_grader(output: str, test_case: dict) -> float:
"""Note la qualité de la réponse via un appel a Claude."""
grading_prompt = f"""Évalue cette reponse sur une echelle de 0 a 10.
Demande originale : {test_case['input']}
Réponse a evaluer : {output}
Criteres :
- La reponse est-elle correcte et fonctionnelle ?
- Est-elle concise et bien structuree ?
Réponds uniquement avec un nombre entre 0 et 10."""
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=10,
messages=[{"role": "user", "content": grading_prompt}]
)
try:
return float(response.content[0].text.strip())
except ValueError:
return 0.0
def run_eval(test_cases: list) -> dict:
"""Exécute l'évaluation complete sur tous les cas de test."""
results = []
for case in test_cases:
output = run_prompt(case["input"])
format_score = code_grader(output, case["format"])
quality_score = model_grader(output, case)
combined = (format_score + quality_score) / 2
results.append({
"input": case["input"],
"format_score": format_score,
"quality_score": quality_score,
"combined_score": combined
})
avg_score = sum(r["combined_score"] for r in results) / len(results)
return {"results": results, "average_score": avg_score}
# Lancement
eval_results = run_eval(test_cases)
print(f"Score moyen combiné : {eval_results['average_score']:.2f}/10")
for r in eval_results["results"]:
print(f" Format: {r['format_score']}/10 | Qualité: {r['quality_score']}/10 | Combiné: {r['combined_score']}/10")
Points clés
- Le notateur par code est déterministe : même entrée = même score, à chaque fois
- Utilisez
json.loads,ast.parseetre.compilepour valider la syntaxe - Ajoutez un champ
"format"dans vos cas de test pour dispatcher vers le bon validateur - Améliorez le prompt avec des instructions explicites (“Réponds uniquement avec…”)
- Combinez notation par code (forme) et notation par modèle (fond) pour une évaluation complète