Aller au contenu principal

Notation par code

Pourquoi noter avec du code ?

Les notateurs par modele sont puissants, mais ils ont un defaut : ils ne peuvent pas verifier de maniere fiable si une sortie est du code valide, du JSON bien forme ou une expression reguliere correcte. Pour ca, rien ne vaut un validateur programmatique.

Un notateur par code (code grader) est une fonction Python qui prend la reponse de Claude et retourne un score numerique. C’est deterministe, instantane et gratuit (pas d’appel API).

Les trois fonctions de validation

1. Validation JSON

import json

def validate_json(output: str) -> int:
    """Verifie 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:
    """Verifie 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:
    """Verifie 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 meme pour les trois : on essaie de parser la sortie avec la bibliotheque appropriee. Si ca fonctionne, score de 10. Sinon, 0. Pas de demi-mesure.

Adapter le jeu de donnees

Pour que le notateur par code sache quelle fonction de validation appliquer, chaque cas de test doit inclure un champ "format" :

test_cases = [
    {
        "input": "Genere un JSON avec les cles 'nom', 'age' et 'ville' pour une personne fictive.",
        "format": "json"
    },
    {
        "input": "Ecris une fonction Python qui inverse une chaine de caracteres.",
        "format": "python"
    },
    {
        "input": "Ecris 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)

Ameliorer 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 : etre explicite dans le prompt.

Avant (prompt vague) :

Genere du code Python qui trie une liste.

Apres (prompt specifique) :

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 cle : “Reponds uniquement avec du Python/JSON/Regex” elimine le bruit et permet au validateur de fonctionner correctement.

Combiner notateur par modele et notateur par code

L’approche la plus robuste combine les deux types de notation. Le notateur par code verifie la forme (syntaxe valide), le notateur par modele verifie le fond (qualite, pertinence, exactitude).

def combined_grader(output: str, test_case: dict) -> float:
    """Combine la notation par code et par modele."""

    # Score de forme (syntaxe valide ?)
    format_score = code_grader(output, test_case["format"])

    # Score de fond (qualite de la reponse)
    quality_score = model_grader(output, test_case)

    # Moyenne des deux scores
    final_score = (format_score + quality_score) / 2
    return final_score

Exemple d’execution complete

import anthropic
import json
import ast
import re

client = anthropic.Anthropic()

def run_prompt(user_input: str) -> str:
    """Execute le prompt et retourne la reponse de Claude."""
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        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 qualite de la reponse via un appel a Claude."""
    grading_prompt = f"""Evalue cette reponse sur une echelle de 0 a 10.

Demande originale : {test_case['input']}
Reponse a evaluer : {output}

Criteres :
- La reponse est-elle correcte et fonctionnelle ?
- Est-elle concise et bien structuree ?

Reponds uniquement avec un nombre entre 0 et 10."""

    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        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:
    """Execute l'evaluation 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 combine : {eval_results['average_score']:.2f}/10")
for r in eval_results["results"]:
    print(f"  Format: {r['format_score']}/10 | Qualite: {r['quality_score']}/10 | Combine: {r['combined_score']}/10")

Points cles

  • Le notateur par code est deterministe : meme entree = meme score, a chaque fois
  • Utilisez json.loads, ast.parse et re.compile pour valider la syntaxe
  • Ajoutez un champ "format" dans vos cas de test pour dispatcher vers le bon validateur
  • Ameliorez le prompt avec des instructions explicites (“Reponds uniquement avec…”)
  • Combinez notation par code (forme) et notation par modele (fond) pour une evaluation complete