Définir des objectifs

Les objectifs vous permettent de définir des critères de réussite/échec pour les scores des évaluateurs. Lorsqu’un objectif est défini, le SDK affiche les verdicts PASS ou FAIL dans la sortie du terminal à côté de chaque score.

Un objectif est un point de contrôle binaire réussite/échec. Le sens favorable (et la façon dont les scores sont normalisés) relève de la sémantique de la métrique que vous définissez sur l’Evaluator lui-même — voir Direction et normalisation ci-dessous.

Types d’objectifs

Types d’objectifs

MéthodeSignification
Goal.gte(0,8)Le score doit être >= 0,8
Goal.lte(0,1)Le score doit être <= 0,1
Goal.between(0,2, 0,8)Le score doit être dans l’intervalle [0,2, 0,8]

Toutes les méthodes d’objectif acceptent un paramètre metric optionnel ("avg", "min", "max", "std") pour cibler une statistique spécifique au lieu de la moyenne par défaut.

Utilisation de base

Utilisation de base

from mistralai.evaluations import Evaluator, Goal

Evaluator(
    name="accuracy",
    description="1 if the expected answer appears in the output.",
    scorer=accuracy_scorer,
    goal=Goal.gte(0.8),
)
Objectifs par génération et agrégés

Objectifs par génération et agrégés

Les évaluateurs prennent en charge deux niveaux d’objectifs :

  • goal : évalué par rapport au score de chaque génération individuelle.
  • aggregate_goal : évalué par rapport au résultat agrégé sur toutes les générations.
Evaluator(
    name="accuracy",
    description="1 if the expected answer appears in the output.",
    scorer=accuracy_scorer,
    goal=Goal.gte(0.7),           # each generation must score >= 0.7
    aggregate_goal=Goal.gte(0.9), # overall average must be >= 0.9
)

Lorsque vous appelez run.show() :

  • Niveau de l’exécution : indique si l’agrégat respecte l’aggregate_goal (revient à goal sur la moyenne si aucun agrégat n’est défini).
  • Niveau de l’enregistrement (avec num_generations > 1) : indique combien de générations ont respecté le goal (par exemple, « 2/3 PASS »), avec le verdict agrégé le cas échéant.
  • Niveau de la génération : affiche PASS/FAIL pour chaque score individuel par rapport à goal.
Objectifs sur les évaluateurs d’exécution

Objectifs sur les évaluateurs d’exécution

Les évaluateurs d’exécution prennent également en charge les objectifs :

from mistralai.evaluations import RunEvaluator, Goal

RunEvaluator(
    name="f1",
    description="Harmonic mean of precision and recall across all records.",
    scorer=f1_scorer,
    goal=Goal.gte(0.85),
)
Direction et normalisation

Direction et normalisation

Un objectif ne contrôle que la réussite ou l’échec. Pour indiquer le sens favorable et l’échelle d’une métrique, définissez ces champs sur l’Evaluator :

ChampTypeDescription
direction"maximize" | "minimize"Sens dans lequel la valeur est meilleure. Déduit de l’objectif quand il n’est pas défini (gte → maximize, lte → minimize, sinon maximize).
min_value / max_valuefloatFenêtre de normalisation min-max. Définissez les deux ou aucun des deux ; min_value doit être < max_value.
weightfloatPression d’optimisation (par défaut 1.0). Définissez weight=0 pour faire de la métrique une contrainte pure : son objectif continue de contrôler la réussite, mais elle est exclue de l’objectif d’optimisation.
Evaluator(
    name="latency_ms",
    description="End-to-end response time in milliseconds.",
    scorer=latency_scorer,
    goal=Goal.lte(1000),     # gate + infers direction="minimize"
    min_value=200,
    max_value=2000,          # 850 ms normalizes to ~0.64 (lower is better)
)

Evaluator(
    name="accuracy",
    description="1 if the expected answer appears in the output.",
    scorer=accuracy_scorer,  # no goal → direction defaults to "maximize", window to [0, 1]
)
Exemple complet

Exemple complet

import asyncio
import os

from mistralai.evaluations import (
    Evaluation, Evaluator, Goal, Mistral, Project,
    RunEvaluator, RunEvaluatorContext, ScorerContext, System, TaskContext,
)

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

dataset = [
    {"prompt": "What is 2+2?", "expected": "4"},
    {"prompt": "Capital of France?", "expected": "Paris"},
    {"prompt": "Largest planet?", "expected": "Jupiter"},
]

async def task(ctx: TaskContext) -> str:
    r = await client.chat.complete_async(
        model=str(ctx.system.params["model"]),
        messages=[{"role": "user", "content": ctx.input_record["prompt"]}],
    )
    return str(r.choices[0].message.content)

def accuracy_scorer(ctx: ScorerContext) -> int:
    return 1 if ctx.input_record["expected"].lower() in str(ctx.output).lower() else 0

def accuracy_gate(ctx: RunEvaluatorContext):
    return ctx.statistics["accuracy"].avg

async def main():
    run = await client.evaluation.run(
        project=Project(name="QA Pipeline"),
        evaluation=Evaluation(name="Accuracy with Goals"),
        system=System(name="mistral-small", params={"model": "mistral-small-latest"}),
        dataset=dataset,
        task=task,
        evaluators=[
            Evaluator(
                name="accuracy",
                description="1 if the expected answer appears in the output.",
                scorer=accuracy_scorer,
                goal=Goal.gte(0.8),
                aggregate_goal=Goal.gte(0.9),
            ),
        ],
        run_evaluators=[
            RunEvaluator(
                name="accuracy_avg",
                description="Average accuracy across all records.",
                scorer=accuracy_gate,
                goal=Goal.gte(0.85),
            ),
        ],
        num_generations=3,
    )
    run.show(level="generations")

asyncio.run(main())