Un agent qui « a l’air de marcher » sur trois questions ne prouve rien. Changez un mot du prompt, passez à un modèle moins cher, ajoutez un outil : comment savez-vous que vous améliorez plutôt que vous ne cassez ? Sans mesure systématique, chaque modification est un pari. L’évaluation transforme ce pari en décision étayée.

LangFuse, qu’on a branché en initiation pour tracer, fournit aussi tout l’outillage d’évaluation : scores, datasets de référence, LLM-as-a-judge et expériences comparatives.

Trois sources de score

Un score est une mesure attachée à une trace (ou à une observation). Trois façons complémentaires de le produire :

Fig.01 · Sources de score
vérité Humain annotation experte
gratuit Heuristique code déterministe
subjectif LLM-juge évalue à l'échelle
On combine les trois : l'humain pour la vérité terrain (coûteux), l'heuristique pour le déterministe (gratuit), le LLM-juge pour le subjectif à l'échelle.
  • Humain — un expert annote (pouce haut/bas, note). La référence de qualité, mais lente et coûteuse. Idéale pour constituer un jeu de validation.
  • Heuristique — du code vérifie une propriété objective : format JSON valide, présence d’une citation, longueur, latence, coût. Gratuit et déterministe.
  • LLM-as-a-judge — un modèle évalue une propriété subjective (fidélité, pertinence, ton). Le seul moyen de mesurer la qualité à l’échelle.

Attacher un score à une trace

L’API de base est create_score. On y rattache un score par l’id de la trace (qu’on récupère lors de l’exécution instrumentée).

from langfuse import Langfuse
langfuse = Langfuse()

# heuristique : la réponse cite-t-elle au moins une source ?
def score_citation(trace_id: str, reponse: str):
    a_cite = "[source" in reponse.lower()
    langfuse.create_score(
        trace_id=trace_id,
        name="cite_source",
        value=1 if a_cite else 0,
        comment="Vérifie la présence d'une citation",
    )

Les scores s’agrègent ensuite dans LangFuse : évolution dans le temps, par version, par tag — c’est ce qui rend une régression visible.

Le LLM-as-a-judge en pratique

Pour le RAG, la métrique reine est la fidélité : la réponse s’appuie-t-elle vraiment sur les documents récupérés, sans inventer ? On la mesure avec un juge.

from pydantic import BaseModel, Field

class Jugement(BaseModel):
    fidele: bool = Field(description="La réponse est-elle justifiée par les sources ?")
    note: int = Field(description="Qualité globale de 1 à 5")
    raison: str

GABARIT = """Tu es un évaluateur rigoureux. Question : {question}
Sources fournies : {sources}
Réponse de l'agent : {reponse}
La réponse est-elle fidèle aux sources et pertinente ? Sois sévère."""

def juger(trace_id, question, sources, reponse):
    juge = modele_juge.with_structured_output(Jugement)
    v = juge.invoke(GABARIT.format(question=question, sources=sources, reponse=reponse))
    langfuse.create_score(trace_id=trace_id, name="fidelite", value=int(v.fidele))
    langfuse.create_score(trace_id=trace_id, name="qualite", value=v.note, comment=v.raison)
    return v

En ligne vs hors ligne

  • Hors ligne — on évalue sur un dataset figé, à chaque changement (avant de déployer). C’est le test de non-régression.
  • En ligne — un juge tourne sur un échantillon du trafic de production, en continu, pour détecter les dérives réelles. LangFuse permet de configurer ces évaluations managées directement sur les traces entrantes.

Les datasets : une vérité terrain versionnée

Un dataset est une collection de cas (entrée, sortie attendue). C’est votre banc d’essai : on y rejoue l’agent à chaque modification.

# créer le dataset une fois
langfuse.create_dataset(name="support-qa")
langfuse.create_dataset_item(
    dataset_name="support-qa",
    input={"question": "Comment réinitialiser mon mot de passe ?"},
    expected_output="Indiquer la page Paramètres > Sécurité > Réinitialiser.",
)
# … des dizaines de cas réels, idéalement issus de vrais tickets …

Une expérience : rejouer l’agent sur le dataset

Une expérience exécute l’agent sur chaque item du dataset, relie chaque trace à son item, et applique les évaluateurs. On compare ensuite les versions.

dataset = langfuse.get_dataset("support-qa")

for item in dataset.items:
    # item.run() relie automatiquement la trace au dataset et à cette exécution
    with item.run(run_name="prompt-v3") as root_span:
        reponse = agent.invoke({"messages": [{"role": "user", "content": item.input["question"]}]})
        sortie = reponse["messages"][-1].content

        # scores : heuristique + LLM-juge
        root_span.score_trace(name="longueur_ok", value=int(len(sortie) < 1200))
        juger(root_span.trace_id, item.input["question"], item.metadata, sortie)

Dans LangFuse, les exécutions prompt-v2 et prompt-v3 s’affichent côte à côte : score de fidélité moyen, coût, latence. La décision « déployer ou non » devient lecture de tableau, pas intuition.

Fig.02 · Boucle d'évaluation
entrée Dataset cas de référence
exécution Run agent sur chaque cas
mesure Score juge + heuristiques
décision Compare v_n vs v_n-1
Le cycle vertueux : on rejoue le dataset, on score, on compare les versions, et chaque régression de production enrichit le dataset.

Non-régression en intégration continue

L’aboutissement : brancher l’expérience dans la CI. À chaque pull request, on rejoue le dataset et on bloque si un score moyen chute sous un seuil.

# eval_ci.py — exécuté par la CI
resultats = lancer_experience("support-qa", run_name=os.environ["GIT_SHA"])
fidelite = moyenne(r.scores["fidelite"] for r in resultats)

assert fidelite >= 0.9, f"Régression de fidélité : {fidelite:.2f} < 0.90"
print(f"✓ Fidélité {fidelite:.2f} — OK pour merge")

Bonnes pratiques & pièges

Bonnes pratiques
  • Combinez les trois sources : heuristiques (gratuites), LLM-juge (échelle), humain (vérité).
  • Constituez le dataset depuis la production, surtout les cas d'échec ; faites-le vivre.
  • Calibrez le LLM-juge contre des annotations humaines sur un échantillon.
  • Préférez des verdicts binaires et une grille stricte aux notes floues sur 10.
  • Branchez la non-régression en CI : bloquez le merge si un score moyen chute.
  • Évaluez en ligne sur un échantillon de prod pour capter les dérives réelles.
Pièges à éviter
  • Confondre tracer et évaluer : la trace ne dit pas si la réponse était bonne.
  • Juger sur 3 exemples à la main : aucune garantie statistique, aucune non-régression.
  • Faire confiance au LLM-juge sans calibration : il favorise le verbeux et se laisse flatter.
  • Un dataset figé jamais mis à jour : il finit déconnecté du trafic réel.
  • Optimiser un seul score (fidélité) en cassant les autres (latence, coût) sans les suivre.

Ce qu’il faut retenir

  • Un score attaché aux traces rend la qualité mesurable et son évolution visible.
  • Trois sources : humaine (vérité), heuristique (déterministe), LLM-juge (subjectif à l’échelle) — à combiner et à calibrer.
  • Un dataset est votre vérité terrain versionnée ; nourrissez-le depuis la production.
  • Une expérience rejoue l’agent sur le dataset et compare les versions côte à côte.
  • La non-régression en CI est le filet qui autorise à itérer vite et sans peur.

Mesurer la qualité ferme la boucle de l’ingénierie d’agents. Reste un dernier maillon, côté expérience utilisateur : restituer le travail de l’agent en temps réel. C’est l’objet du deep-dive sur le streaming.

#langfuse#evaluation#llm-judge#datasets#production