Jeux de données

Un ensemble de données est l'ensemble de cas de test qui pilote une évaluation hors ligne. Dans l'SDK d'évaluation, un ensemble de données est soit une liste de dicts Python, où chaque dict est un enregistrement d'entrée et où vous définissez les clés pour correspondre à ce que votre fonction de tâche attend, soit un ensemble de données Studio que le SDK récupère pour vous.

Structure des enregistrements

Structure des enregistrements

Chaque enregistrement est un dictionnaire simple. Les clés dépendent de vous :

dataset = [
    {"sentence": "Hello, how are you?", "groundtruth": "English"},
    {"sentence": "Bonjour, comment ça va?", "groundtruth": "French"},
    {"sentence": "Hola, ¿cómo estás?", "groundtruth": "Spanish"},
]

Dans votre tâche et votre notation, accédez à l'enregistrement via ctx.input_record :

from mistralai.evaluations import TaskContext, ScorerContext

async def task(ctx: TaskContext) -> str:
    return ctx.input_record["sentence"]  # access any key you defined

def scorer(ctx: ScorerContext) -> int:
    return 1 if ctx.input_record["groundtruth"].lower() == str(ctx.output).lower() else 0
Utiliser un ensemble de données Studio

Utiliser un ensemble de données Studio

Si vous gérez vos enregistrements dans Studio, passez l'ensemble de données à evaluation.run() avec Dataset, par slug ou par ID. Le SDK récupère chaque enregistrement avant le démarrage de l'exécution :

from mistralai.evaluations import Dataset, Evaluation, Evaluator, Project

run = await client.evaluation.run(
    project=Project(name="Language Detection"),
    evaluation=Evaluation(name="Managed Dataset Eval"),
    dataset=Dataset(slug="language-detection-golden-set"),
    task=task,
    evaluators=[Evaluator(name="accuracy", scorer=scorer)],
)
SélecteurUtilisez-le quand
Dataset(slug="language-detection-golden-set")Vous voulez un script lisible et stable.
Dataset(id="018f879d-20cd-7e9f-a1bc-2f4f08b6f170")Vous disposez déjà de l'UUID de l'ensemble de données.

Passez exactement un seul des deux : id ou slug. L'ensemble de données doit déjà exister : le sélectionner par slug ne le crée jamais.

Le payload de chaque enregistrement devient l'enregistrement d'entrée, tel quel : ctx.input_record contient le même dict qu'un enregistrement en ligne équivalent. Pour l'exemple de détection de langue, utilisez des enregistrements Studio structurés ainsi :

payload = {"sentence": "Bonjour, comment ça va?", "groundtruth": "French"}

Lorsque vous importez ces enregistrements depuis JSONL, encapsulez chaque payload dans le format d'importation de jeu de données Studio :

{"payload":{"sentence":"Bonjour, comment ça va?","groundtruth":"French"},"properties":{}}

Les propriétés des enregistrements et les informations sur leur source ne sont pas ajoutées à l'enregistrement d'entrée. Sur les exécutions enregistrées dans Studio, l'exécution conserve l'ID de l'ensemble de données, et chaque enregistrement d'entrée conserve l'ID de l'enregistrement Studio dont il provient.

i
Information

Les ensembles de données Studio ne sont pas des instantanés

Chaque exécution lit les enregistrements qui existent au moment de son démarrage, jusqu'à 10 000. Les modifications ultérieures de l'ensemble de données n'affectent que les exécutions futures. Si des enregistrements sont ajoutés ou supprimés pendant que le SDK les récupère, l'exécution échoue avant de démarrer plutôt que de s'exécuter sur un ensemble incohérent.

Dataset est accepté par evaluation.run(). Optimization et Retry failed records prennent une liste d'enregistrements.

Transformer les enregistrements avant l'exécution

Transformer les enregistrements avant l'exécution

Quand vos enregistrements Studio ne correspondent pas à la structure attendue par votre tâche, ou quand vous avez besoin d'une liste d'enregistrements, par exemple pour optimiser, récupérez-les et transformez-les vous-même.

Récupérez les enregistrements avec le SDK Mistral et adaptez le payload de chaque enregistrement vous-même. L'endpoint de liste est paginé. Cet utilitaire récupère chaque page et valide les enregistrements sous la forme d'un LangItem :

from typing import Any, TypedDict

from mistralai.evaluations import Mistral

class LangItem(TypedDict):
    sentence: str
    groundtruth: str

def as_dict(value: Any) -> dict[str, Any]:
    if isinstance(value, dict):
        return value
    if hasattr(value, "model_dump"):
        return value.model_dump(mode="json")
    return dict(value)

def require_string(value: Any, *, record_id: str, field: str) -> str:
    if isinstance(value, str) and value:
        return value
    raise ValueError(f"Dataset record {record_id} is missing {field}")

def to_lang_item(record: Any) -> LangItem:
    payload = as_dict(record.payload)

    return {
        "sentence": require_string(payload.get("sentence"), record_id=record.id, field="payload.sentence"),
        "groundtruth": require_string(
            payload.get("groundtruth"),
            record_id=record.id,
            field="payload.groundtruth",
        ),
    }

async def fetch_eval_dataset(client: Mistral, dataset_id: str) -> list[LangItem]:
    dataset: list[LangItem] = []
    page = 1
    page_size = 100

    while True:
        result = await client.beta.observability.datasets.list_records_async(
            dataset_id=dataset_id,
            page_size=page_size,
            page=page,
        )
        records = result.records.results

        dataset.extend(to_lang_item(record) for record in records)

        if not result.records.next:
            break
        page += 1

    return dataset

Passez ensuite la liste obtenue à dataset :

import asyncio
import os

from mistralai.evaluations import (
    Evaluation, Evaluator, Mistral, Project, ScorerContext, TaskContext,
)

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

async def task(ctx: TaskContext) -> str:
    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {
                "role": "user",
                "content": (
                    "What language is this sentence in? Reply with ONLY the language name. "
                    f"Sentence: {ctx.input_record['sentence']}"
                ),
            }
        ],
    )
    return str(response.choices[0].message.content)

def scorer(ctx: ScorerContext) -> int:
    groundtruth = ctx.input_record["groundtruth"].lower()
    predicted = str(ctx.output).lower()
    return 1 if groundtruth == predicted else 0

async def main():
    dataset_id = os.environ["MISTRAL_DATASET_ID"]
    dataset = await fetch_eval_dataset(client, dataset_id=dataset_id)

    run = await client.evaluation.run(
        project=Project(name="Language Detection"),
        evaluation=Evaluation(name="Managed Dataset Eval"),
        dataset=dataset,
        task=task,
        evaluators=[
            Evaluator(
                name="accuracy",
                description="1 if the detected language matches the groundtruth.",
                scorer=scorer,
            ),
        ],
        metadata={
            "studio_dataset_id": dataset_id,
            "record_count": len(dataset),
        },
    )
    run.show(level="records")

asyncio.run(main())

Validez les champs dont vous avez besoin depuis record.payload, puis renvoyez la structure de dict exacte attendue par votre tâche et vos scorers.

Sécurité des types avec TypedDict

Sécurité des types avec TypedDict

Utilisez TypedDict pour rendre les schémas des enregistrements explicites et obtenir une autocomplétion dans l'IDE :

from typing import TypedDict

class LanguageRecord(TypedDict):
    sentence: str
    groundtruth: str

dataset: list[LanguageRecord] = [
    {"sentence": "Hello, how are you?", "groundtruth": "English"},
    {"sentence": "Bonjour, comment ça va?", "groundtruth": "French"},
]
Que mettre dans les enregistrements

Que mettre dans les enregistrements

Les enregistrements peuvent contenir tout ce dont votre tâche ou votre notation a besoin :

Type de champObjectifExemple
Entrées de tâcheCe que la tâche traiteprompt, contexte, texte, question
Vérité de référenceSortie de référence pour la notationexpected, groundtruth, reference_answer
MétadonnéesContexte supplémentaire pour les notateurs ou les juges LLMcategory, difficulty, grading_guidance

Incluez la vérité de référence dans les enregistrements lorsque vous souhaitez comparer la sortie de la tâche à une réponse connue comme correcte :

dataset = [
    {
        "prompt": "What is the capital of France?",
        "expected": "Paris",
        "difficulty": "easy",
    },
    {
        "prompt": "Explain the difference between precision and recall.",
        "expected": "Precision measures true positives over predicted positives; recall measures true positives over actual positives.",
        "difficulty": "medium",
    },
]

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

Bonnes pratiques

Gardez les jeux de données ciblés

Un jeu de données construit autour d'une seule tâche ou capacité produit des signaux plus clairs qu'une collection large et multithème. Maintenez des jeux de données séparés pour des objectifs d'évaluation distincts (par exemple, language_detection, qa_factual, code_generation).

Sélectionnez des données représentatives

  • Incluez des cas particuliers et des modes de défaillance, pas uniquement des exemples faciles.
  • Équilibrez votre jeu de données : si 90 % des enregistrements sont des cas faciles, l'évaluation ne révélera pas de problèmes réels.
  • Supprimez les enregistrements où même un humain ne pourrait pas noter la réponse de manière fiable (les entrées ambiguës ajoutent du bruit).

Versionnez vos jeux de données

Figez votre ensemble de données entre les exécutions si vous voulez suivre les performances dans le temps. Même de petites modifications d'enregistrements peuvent rendre les exécutions incomparables. Les ensembles de données Studio sont modifiables : chaque exécution lit leurs enregistrements en l'état. Utilisez des noms explicites comme qa_baseline_2025_06 plutôt que test_data.

La qualité de la vérité de référence est cruciale

Une vérité terrain inexacte ou ambiguë produit des scores bruités. Si vous utilisez un LLM comme juge (voir Évaluateurs), ajoutez un champ grading_guidance pour fournir au juge des consignes de notation explicites par enregistrement.

Organisation dans Studio

Organisation dans Studio

Le SDK d'évaluation organise les résultats par Projets, Évaluations et Exécutions dans Studio, et non par l'ensemble de données lui-même. Passez votre ensemble de données à evaluation.run() :

from mistralai.evaluations import Evaluation, Project

run = await client.evaluation.run(
    project=Project(name="Language Detection"),
    evaluation=Evaluation(name="Accuracy Eval"),
    dataset=dataset,  # your list of dicts, or a Dataset
    task=task,
    evaluators=[...],
)

Les balises et métadonnées de l'exécution vous aident à retracer quelle version du jeu de données a été utilisée :

run = await client.evaluation.run(
    ...
    tags=["dataset:qa_baseline_2025_06", "model:mistral-small"],
    metadata={"dataset_version": "2025-06", "record_count": len(dataset)},
)
FAQ

FAQ