> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Exécuter des Experiments **Ajouté dans :** `@mastra/core@1.4.0` Un Experiment fait passer chaque élément d’un Dataset par une cible (un Agent, un Workflow ou un Scorer), puis évalue éventuellement les sorties. Utilisez un Scorer comme cible lorsque vous souhaitez évaluer le juge LLM lui-même. Par défaut, les résultats sont conservés dans le stockage afin que vous puissiez comparer les exécutions entre différents prompts, modèles ou changements de code. **Pour les Agents IA :** exécutez `npx mastra api experiment run dataset_123 '{"name":"translation-baseline"}'` pour lancer directement un Experiment, sans ouvrir Studio ni écrire de script temporaire. Remplacez l’identifiant d’exemple par un identifiant de Dataset renvoyé par `npx mastra api dataset list`. La commande nécessite un serveur Mastra en cours d’exécution, doté d’un stockage de Datasets et de cibles d’Experiment enregistrées ; démarrez le serveur local avec `npx mastra dev`, ou transmettez l’URL de base du serveur accessible avec `--url`. Exécutez `npx mastra api experiment run --schema` avant de construire une entrée différente et obtenez l’accord de l’utilisateur avant de lancer un Experiment, car celui-ci peut effectuer des appels de modèle. Installez le skill Mastra avec `npx skills add mastra-ai/skills --skill mastra` pour obtenir des instructions complètes sur la découverte de la CLI API, le ciblage, les schémas, l’authentification et la gestion des erreurs. ## Experiment de base Appelez [`startExperiment()`](https://mastra.zisheng.pro/fr/reference/datasets/startExperiment) avec une cible et des Scorers : ```typescript import { mastra } from '../index' const dataset = await mastra.datasets.get({ id: 'translation-dataset-id' }) const summary = await dataset.startExperiment({ name: 'gpt-5.1-baseline', targetType: 'agent', targetId: 'translation-agent', scorers: ['accuracy', 'fluency'], }) console.log(summary.status) // 'completed' | 'failed' console.log(summary.succeededCount) // number of items that ran successfully console.log(summary.failedCount) // number of items that failed ``` `startExperiment()` bloque l’exécution jusqu’à ce que tous les éléments soient terminés. Pour une exécution sans attendre le résultat, consultez les [Experiments asynchrones](#async-experiments). ## Studio Vous pouvez également exécuter des Experiments dans [Studio](https://mastra.zisheng.pro/fr/docs/studio/overview). Après avoir ajouté un élément au Dataset, ouvrez-le, sélectionnez **Run Experiment**, puis configurez la cible, les Scorers et les options. Après l’exécution d’un Experiment, l’onglet **Experiments** affiche toutes les exécutions de ce Dataset, avec leur état, leurs décomptes et leurs horodatages. Sélectionnez un Experiment pour consulter les résultats, scores et Traces d’exécution de chaque élément. Dans l’onglet **Experiments**, sélectionnez **Compare**, puis choisissez au moins deux Experiments afin de comparer côte à côte leurs scores et leurs résultats. ## Cibles d’Experiment Vous pouvez diriger un Experiment vers un Agent, un Workflow ou un Scorer enregistré. ### Agent enregistré Ciblez un Agent enregistré dans votre instance Mastra : ```typescript const summary = await dataset.startExperiment({ name: 'agent-v2-eval', targetType: 'agent', targetId: 'translation-agent', scorers: ['accuracy'], }) ``` La valeur `input` de chaque élément est transmise directement à `agent.generate()` ; elle doit donc être de type `string`, `string[]` ou `CoreMessage[]`. #### Agents dotés de mémoire Lorsque l’Agent cible possède sa propre mémoire et que le contexte de requête contient un identifiant de ressource (`MASTRA_RESOURCE_ID_KEY`, défini par le middleware d’authentification, le `requestContext` de l’Experiment ou de l’élément, ou le formulaire **Run Experiment** de Studio), le moteur d’Experiment injecte un nouveau thread de mémoire pour chaque élément. Un identifiant de ressource dans le contexte de requête signifie « exécuter en tant que cette ressource » : la conversation de chaque élément est conservée sous forme de thread associé à cette ressource, et les éléments relancés reçoivent un nouveau thread à chaque tentative afin que les tentatives précédentes ayant échoué ne puissent pas contaminer le contexte de la nouvelle tentative. Les threads injectés sont étiquetés afin que vous puissiez les rattacher à l’exécution : leurs métadonnées contiennent l’`experimentId` ainsi que l’identifiant de l’élément du Dataset sous la clé `experimentItemId`. Aucun titre de thread n’est généré pour eux. Comme les threads appartiennent à la ressource de l’appelant, les fonctionnalités de mémoire limitées à cette ressource lisent et modifient toutes deux son état pendant l’exécution : - Les mises à jour de la mémoire de travail limitée à la ressource sont conservées dans celle-ci, et les éléments traités ultérieurement voient les mises à jour effectuées par les éléments précédents. - Le rappel sémantique limité à la ressource peut exposer à l’Experiment les conversations antérieures de cette ressource, tandis que les transcriptions de l’Experiment deviennent accessibles au rappel dans les conversations ultérieures de la même ressource. Cette approche est utile lorsque vous souhaitez évaluer un Agent à partir du contexte accumulé d’un utilisateur réel. Si vous ne voulez pas que les exécutions d’Experiment modifient l’état d’un utilisateur réel, exécutez plutôt l’Experiment avec un identifiant de ressource dédié à l’évaluation. L’injection de threads est ignorée dans les cas suivants : - Si le contexte de requête définit également `MASTRA_THREAD_ID_KEY`, le moteur utilise ce thread tel quel ; tous les éléments, ainsi que toutes leurs nouvelles tentatives, partagent donc la même conversation. - Si l’Agent n’a pas de mémoire ou si le contexte de requête ne contient aucun identifiant de ressource, l’exécution s’effectue sans mémoire et rien n’est conservé. ### Workflow enregistré Ciblez un Workflow enregistré dans votre instance Mastra : ```typescript const summary = await dataset.startExperiment({ name: 'workflow-eval', targetType: 'workflow', targetId: 'translation-workflow', scorers: ['accuracy'], }) ``` Le Workflow reçoit la valeur `input` de chaque élément comme données de déclenchement. ### Scorer enregistré Ciblez un Scorer pour évaluer un juge LLM par rapport à la vérité terrain : ```typescript const summary = await dataset.startExperiment({ name: 'judge-accuracy-eval', targetType: 'scorer', targetId: 'accuracy', }) ``` Le Scorer reçoit les valeurs `input` et `groundTruth` de chaque élément. Les juges fondés sur un LLM peuvent dériver au fil du temps lorsque les modèles sous-jacents évoluent ; il est donc important de les réaligner régulièrement sur des libellés de référence fiables. Un Dataset fournit un benchmark stable permettant de détecter cette dérive. ## Évaluer les résultats Les Scorers s’exécutent automatiquement après l’exécution de la cible pour chaque élément. Transmettez des instances de Scorer ou des identifiants de Scorers enregistrés : **Identifiants de Scorers**: ```typescript // Reference scorers registered on the Mastra instance const summary = await dataset.startExperiment({ name: 'with-registered-scorers', targetType: 'agent', targetId: 'translation-agent', scorers: ['accuracy', 'fluency'], }) ``` **Instances de Scorer**: ```typescript import { createAnswerRelevancyScorer } from '@mastra/evals/scorers/prebuilt' const relevancy = createAnswerRelevancyScorer({ model: 'openai/gpt-5-mini' }) const summary = await dataset.startExperiment({ name: 'with-scorer-instances', targetType: 'agent', targetId: 'translation-agent', scorers: [relevancy], }) ``` Les résultats de chaque élément comprennent les scores de chaque Scorer : ```typescript for (const item of summary.results) { console.log(item.itemId, item.output) for (const score of item.scores) { console.log(` ${score.scorerName}: ${score.score} — ${score.reason}`) } } ``` Consultez la [présentation des Scorers](https://mastra.zisheng.pro/fr/docs/evals/overview) pour en savoir plus sur les Scorers disponibles et personnalisés. ## Contrôler la persistance pour chaque exécution Utilisez `persistence` pour ignorer les écritures dans le stockage lors d’une exécution donnée. Les enregistrements d’Experiment et ceux des scores peuvent être désactivés indépendamment : ```typescript const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'translation-agent', scorers: ['accuracy'], persistence: { experiments: 'none', scores: 'none', }, }) ``` La cible et les Scorers continuent de s’exécuter, et `startExperiment()` renvoie toujours les résultats et les scores des éléments dans `summary`. Ces paramètres sont indépendants. Par exemple, définissez uniquement `scores: 'none'` pour conserver l’Experiment et les résultats de ses éléments sans créer d’enregistrements de scores. Les paramètres omis prennent par défaut la valeur `'default'`, qui conserve le comportement de stockage standard. Cette politique contrôle uniquement les enregistrements d’Experiment et de scores créés par l’exécution. Elle ne désactive pas le stockage utilisé par la cible, comme la mémoire de l’Agent, les vecteurs, l’observabilité ou le stockage personnalisé des Tools. Lorsque `startExperimentAsync()` s’exécute avec `experiments: 'none'`, aucun enregistrement d’Experiment, aucune mise à jour de progression ni aucun résultat d’élément ne sont conservés. La persistance des scores reste contrôlée séparément par `persistence.scores`. Sans observateur d’événements d’Experiment, l’exécution se déroule sans attendre le résultat et l’API des Experiments ne peut pas indiquer si elle a réussi ou échoué. Utilisez la méthode synchrone `startExperiment()` lorsque l’appelant a besoin du récapitulatif renvoyé. Un observateur d’événements d’Experiment peut recevoir les événements du cycle de vie et le récapitulatif final. ## Observer les événements d’un Experiment Utilisez `onEvent` pour recevoir des événements de cycle de vie versionnés et sérialisables en JSON pendant l’exécution d’un Experiment. Cette option fonctionne avec `startExperiment()`, `startExperimentAsync()` et `runExperiment()`. ```typescript import type { ExperimentEvent } from '@mastra/core/datasets' const events: ExperimentEvent[] = [] await dataset.startExperimentAsync({ task: async ({ input }) => processItem(input), persistence: { experiments: 'none' }, onEvent: async event => { events.push(event) await publishEvent(event) }, }) ``` L’observateur reçoit les types d’événements suivants : - `experiment.run.started` : identifie l’exécution, la cible, la version résolue du Dataset et le nombre d’éléments. - `experiment.item.completed` : signale le résultat enregistré d’un élément après son évaluation, notamment les scores, les erreurs, le nombre de nouvelles tentatives, les détails des mocks de Tools et l’identité stable de l’élément. - `experiment.run.finished` : signale le résultat final et les compteurs du récapitulatif. Mastra attend la fin de chaque appel de l’observateur avant de transmettre l’événement suivant. Cette transmission sérialisée applique une contre-pression et garantit que les valeurs `sequence` des événements correspondent à leur ordre de transmission, tandis que l’exécution des éléments peut rester concurrente. Si l’observateur lève une exception ou rejette la promesse, Mastra interrompt le reste de l’exécution et rejette `runExperiment()` avec une `MastraError` dont l’`id` vaut `EXPERIMENT_EVENT_OBSERVER_FAILED`. Aucun événement final n’est envoyé par l’intermédiaire de l’observateur défaillant. Avec `startExperimentAsync()`, la méthode a déjà renvoyé sa valeur lorsqu’un observateur détaché échoue ; gérez donc les échecs de transmission au sein de l’observateur lorsque l’appelant a besoin d’un signalement direct des erreurs. Mastra attend l’événement `experiment.run.finished` avant de conserver l’état final de l’Experiment. Considérez cet événement comme le signal final faisant autorité lorsque la persistance de l’Experiment est désactivée, mais ne l’utilisez pas comme signal de lecture après écriture pour le stockage. Les types d’événements exportés sont `ExperimentEvent`, `ExperimentRunStartedEvent`, `ExperimentItemCompletedEvent` et `ExperimentRunFinishedEvent`. Utilisez le champ discriminant `type` pour préciser le type d’un événement avant de lire ses propriétés spécifiques. ## Mocks de Tools Lorsqu’un Experiment exécute un Agent qui appelle des Tools produisant des effets de bord, associez des mocks statiques de Tools aux différents éléments du Dataset afin de rendre l’exécution déterministe. Pendant l’Experiment, un Tool mocké renvoie la sortie déclarée au lieu de s’exécuter. Par défaut, les Tools qui ne disposent d’aucun mock sur l’élément s’exécutent réellement. Les mocks sont stockés sur l’élément du Dataset ; ils sont donc versionnés avec la ligne et accompagnent le cas de test. Chaque mock déclare le nom d’un Tool, les arguments attendus et la sortie à renvoyer : ```typescript await dataset.addItem({ input: 'What is the weather in Seattle?', toolMocks: [ { toolName: 'getWeather', args: { city: 'Seattle' }, output: { temperature: 60, conditions: 'rainy' }, }, ], }) ``` Les mocks de Tools sont pris en charge uniquement pour les cibles `agent`. ### Bloquer les Tools non déclarés Définissez `unmockedToolPolicy: 'deny'` sur un Experiment pour bloquer tout appel de Tool dépourvu de mock. Cette option est utile lorsqu’un appel réel risque de produire des effets de bord : ```typescript const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'weather-agent', unmockedToolPolicy: 'deny', }) ``` La politique par défaut est `'allow'`. Vous pouvez remplacer la politique de l’Experiment sur un élément individuel stocké ou défini en ligne : ```typescript await dataset.addItem({ input: 'What is the weather in Seattle?', unmockedToolPolicy: 'allow', }) ``` La valeur de l’élément prévaut sur celle de l’Experiment. Un appel refusé échoue avec `TOOL_MOCK_NOT_DECLARED` avant l’exécution du Tool. Cet échec ne fait l’objet d’aucune nouvelle tentative et n’est pas ajouté à `liveCalls`. ### Correspondance et consommation La correspondance des arguments est stricte : l’ordre des clés d’objet est ignoré, l’ordre des éléments de tableau est significatif et aucune coercition de type n’est effectuée. Un mock n’est fourni que lorsque l’Agent appelle le Tool avec des arguments profondément égaux aux `args` du mock. Lorsqu’un élément déclare plusieurs mocks pour le même Tool et les mêmes arguments, ils sont consommés dans l’ordre : le premier appel reçoit le premier mock, l’appel suivant reçoit le deuxième, et ainsi de suite. L’ordre est suivi séparément pour chaque groupe `(toolName, args)` et reste indépendant entre des arguments différents. ### Mode de correspondance Par défaut, chaque mock établit une correspondance stricte avec ses `args`. Définissez `matchArgs: 'ignore'` pour établir la correspondance uniquement sur le nom du Tool : les `args` du mock ne sont alors pas comparés et le prochain mock non consommé de ce Tool est fourni, quels que soient les arguments avec lesquels l’Agent l’a appelé : ```typescript const subAgentMock = { toolName: 'agent-balanceAgent', args: { prompt: 'look up the balance for YJ' }, output: { text: "YJ's balance is $100." }, matchArgs: 'ignore', } ``` Cette option est utile lorsque les arguments d’un Tool sont instables ou générés par le modèle. Le cas le plus courant consiste à mocker la **réponse d’un sous-Agent** : un sous-Agent délégué est exposé au parent comme un Tool `agent-`, et ses arguments comprennent un `prompt` rédigé par un LLM ainsi que des champs injectés à l’exécution. Mocker `agent-` renvoie la réponse prédéfinie au lieu d’exécuter le sous-Agent et ses Tools internes. Lorsque vous créez un mock à partir d’une Trace, les appels de délégation aux sous-Agents sont automatiquement dérivés avec `matchArgs: 'ignore'`. Vous pouvez remplacer cette valeur par `'strict'` pour imposer les arguments exacts. ### Échecs Un appel de Tool fait échouer l’élément lorsqu’il enfreint la configuration des mocks : - `TOOL_MOCK_MISMATCH` : le Tool a été appelé avec des arguments ne correspondant à aucun mock. - `TOOL_MOCK_EXHAUSTED` : tous les mocks correspondants ont déjà été consommés. - `TOOL_MOCK_NOT_DECLARED` : le Tool ne possède aucun mock et la valeur effective de `unmockedToolPolicy` est `'deny'`. En cas de l’un de ces échecs, l’exécution de l’Agent est immédiatement interrompue. Le modèle ne peut donc plus appeler d’autres Tools, notamment des Tools non mockés produisant des effets de bord qui, autrement, s’exécuteraient réellement. Ces échecs étant déterministes, ils ne font l’objet d’aucune nouvelle tentative. Les mocks déclarés mais jamais utilisés ne font pas échouer l’élément ; ils sont signalés comme non consommés. Lorsque l’interception des mocks est active, les Tools de l’Agent s’exécutent séquentiellement afin que les mocks `(toolName, args)` répétés soient consommés dans l’ordre des appels du Provider. L’interception est active lorsque l’élément déclare des mocks ou que sa valeur effective de `unmockedToolPolicy` est `'deny'`. ### Diagnostic Le résultat de chaque élément contient un `toolMockReport` décrivant la manière dont l’exécution a traité les mocks de cet élément : ```typescript for (const item of summary.results) { const report = item.toolMockReport if (!report) continue console.log(report.served) // mocks matched and returned console.log(report.unconsumed) // mocks declared but never used console.log(report.liveCalls) // undeclared tools allowed to run live console.log(report.failure) // the first deterministic mock failure, if any } ``` Dans [Studio](https://mastra.zisheng.pro/fr/docs/studio/overview), modifiez un élément du Dataset pour définir les mocks de Tools sous forme de tableau JSON, puis ouvrez le résultat d’un Experiment pour consulter le même rapport. ### Limites - **Aucun span de Tool pour les appels mockés.** Un appel mocké renvoie sa sortie avant l’exécution du Tool ; il ne crée donc aucun span de Tool. Par conséquent, les Scorers de trajectoire fondés sur des Traces stockées peuvent ne pas voir les appels de Tools mockés. L’extraction de trajectoire qui se rabat sur la sortie du message de l’Agent les voit toujours ; l’évaluation de la trajectoire peut donc varier selon votre configuration d’observabilité. - **Prise en charge par le stockage.** Les mocks de Tools et leurs rapports sont conservés par les adaptateurs LibSQL, PostgreSQL, MongoDB et Spanner. L’adaptateur MySQL ne les prend pas en charge et rejette les écritures contenant des mocks de Tools ou un rapport de mocks de Tools. Tous les adaptateurs de stockage de Datasets conservent `unmockedToolPolicy`. ## Experiments asynchrones `startExperiment()` bloque l’exécution jusqu’à ce que chaque élément soit terminé. Pour les Datasets dont l’exécution est longue, utilisez [`startExperimentAsync()`](https://mastra.zisheng.pro/fr/reference/datasets/startExperimentAsync) afin de lancer l’Experiment en arrière-plan : ```typescript const { experimentId, status } = await dataset.startExperimentAsync({ name: 'large-dataset-run', targetType: 'agent', targetId: 'translation-agent', scorers: ['accuracy'], }) console.log(experimentId) // UUID console.log(status) // 'pending' ``` Interrogez régulièrement [`getExperiment()`](https://mastra.zisheng.pro/fr/reference/datasets/getExperiment) jusqu’à la fin de l’exécution : ```typescript let experiment = await dataset.getExperiment({ experimentId }) while (experiment.status === 'pending' || experiment.status === 'running') { await new Promise(resolve => setTimeout(resolve, 5000)) experiment = await dataset.getExperiment({ experimentId }) } console.log(experiment.status) // 'completed' | 'failed' ``` ## Options de configuration ### Concurrence Contrôlez le nombre d’éléments exécutés en parallèle (valeur par défaut : 5) : ```typescript const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'translation-agent', maxConcurrency: 10, }) ``` ### Délais d’expiration et nouvelles tentatives Définissez un délai d’expiration par élément, en millisecondes, ainsi qu’un nombre de nouvelles tentatives : ```typescript const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'translation-agent', itemTimeout: 30_000, // 30 seconds per item maxRetries: 2, // retry failed items up to 2 times }) ``` Les nouvelles tentatives utilisent un délai exponentiel. Les erreurs d’interruption ne font jamais l’objet d’une nouvelle tentative. ### Interrompre un Experiment Transmettez un `AbortSignal` pour annuler un Experiment en cours d’exécution : ```typescript const controller = new AbortController() // Cancel after 60 seconds setTimeout(() => controller.abort(), 60_000) const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'translation-agent', signal: controller.signal, }) ``` Les éléments restants sont marqués comme ignorés dans le récapitulatif. ### Épingler une version du Dataset Exécutez l’Experiment sur un instantané précis du Dataset : ```typescript const summary = await dataset.startExperiment({ targetType: 'agent', targetId: 'translation-agent', version: 3, // use items from dataset version 3 }) ``` ## Consulter les résultats ### Répertorier les Experiments ```typescript const { experiments, pagination } = await dataset.listExperiments({ page: 0, perPage: 10, }) for (const exp of experiments) { console.log(`${exp.name} — ${exp.status} (${exp.succeededCount}/${exp.totalItems})`) } ``` ### Détails d’un Experiment ```typescript const experiment = await dataset.getExperiment({ experimentId: 'exp-abc-123', }) console.log(experiment.status) console.log(experiment.startedAt) console.log(experiment.completedAt) ``` > **📹 À regarder:** Regardez [le Workflow des Datasets et Experiments Mastra](https://www.youtube.com/watch?v=R6pjAdGhxhQ) pour découvrir comment les Datasets et les Experiments contribuent à améliorer la fiabilité. ### Résultats par élément ```typescript const { results, pagination } = await dataset.listExperimentResults({ experimentId: 'exp-abc-123', page: 0, perPage: 50, }) for (const result of results) { console.log(result.itemId, result.output, result.error) } ``` ## Comprendre le récapitulatif `startExperiment()` renvoie un `ExperimentSummary` contenant des décomptes et les résultats de chaque élément : - `completedWithErrors` vaut `true` lorsque l’Experiment s’est terminé, mais que certains éléments ont échoué. - Les éléments annulés via `signal` sont comptabilisés dans `skippedCount`. Consultez la [référence de `startExperiment`](https://mastra.zisheng.pro/fr/reference/datasets/startExperiment) pour obtenir la documentation complète sur les paramètres et le type de retour. ## Voir aussi - [Présentation des Datasets](https://mastra.zisheng.pro/fr/docs/datasets/overview) - [Présentation des Scorers](https://mastra.zisheng.pro/fr/docs/evals/overview) - [Référence de `startExperiment`](https://mastra.zisheng.pro/fr/reference/datasets/startExperiment) - [Référence de `listExperimentResults`](https://mastra.zisheng.pro/fr/reference/datasets/listExperimentResults)