Évaluations multitours
Les évaluations multitours testent le comportement d’un agent au fil d’une conversation. Au lieu de fournir une seule input, vous fournissez un tableau inputs. Chaque entrée est envoyée successivement à l’agent dans le même thread, et les scorers voient la sortie cumulée de tous les tours.
Quand utiliser les évaluations multitoursLien direct vers Quand utiliser les évaluations multitours
- L’agent utilise la mémoire et doit se rappeler le contexte des tours précédents
- L’agent traite des questions de suivi qui dépendent de réponses antérieures
- Vous devez vérifier les séquences d’appels d’outils au fil d’une conversation
- L’agent exécute un workflow en plusieurs étapes (rechercher, confirmer, exécuter)
Démarrage rapideLien direct vers Démarrage rapide
import { runEvals } from '@mastra/core/evals'
import { checks } from '@mastra/evals/checks'
import { weatherAgent } from '../agents'
const result = await runEvals({
data: [
{
inputs: [
'What is the weather in Brooklyn?',
'What about tomorrow?',
'Compare the two forecasts.',
],
},
],
target: weatherAgent,
scorers: [checks.calledTool('get_weather', { times: 2 }), checks.includes('Brooklyn')],
})
À chaque tour, agent.generate() s’exécute avec le même ID de thread, ce qui permet à l’agent de voir l’intégralité de l’historique de la conversation. Les scorers reçoivent les messages de sortie cumulés de tous les tours.
La mémoire est requise pour se rappeler les tours précédentsLien direct vers La mémoire est requise pour se rappeler les tours précédents
Le rappel entre les tours nécessite que l’agent dispose d’un stockage de mémoire configuré. L’ID de thread partagé permet à chaque tour de voir les précédents, mais un thread ne conserve l’historique que si l’agent dispose d’une mémoire. Si aucune mémoire n’est configurée pour l’agent, les tours s’exécutent tout de même successivement et leurs sorties continuent de s’accumuler pour la notation, mais l’agent ne se rappellera pas les tours précédents (chaque entrée s’exécute de manière isolée). runEvals consigne un avertissement lorsque vous utilisez inputs avec un agent dépourvu de mémoire.
runEvals gère pour vous l’identité de la conversation : la fonction génère le threadId partagé et injecte un resourceId (la mémoire de Mastra délimite les messages par ressource et par thread ; les deux sont donc nécessaires au rappel). Par défaut, la ressource est dérivée du thread généré afin d’isoler chaque conversation. Pour imposer une ressource précise, par exemple afin de réutiliser la mémoire d’un utilisateur existant, transmettez targetOptions.memory.resource ; runEvals reste propriétaire du thread, vous n’avez donc pas à en fournir un :
await runEvals({
target: weatherAgent,
data: [{ inputs: ['What is the weather in Brooklyn?', 'What about tomorrow?'] }],
scorers: [checks.similarity('weather forecast')],
targetOptions: { memory: { resource: 'user-42' } },
})
Consultez la page Mémoire pour savoir comment configurer un stockage de mémoire.
FonctionnementLien direct vers Fonctionnement
Lorsqu’un élément de données contient un tableau inputs, runEvals :
- Crée un nouveau thread (
threadIdunique) et une ressource pour la conversation (une valeurtargetOptions.memory.resourcefournie par l’appelant est conservée) - Envoie successivement chaque entrée via
agent.generate()dans ce thread - Cumule tous les messages de sortie au fil des tours
- Transmet l’intégralité de la sortie cumulée aux scorers pour évaluation
Les scorers voient la sortie complète de la conversation, y compris chaque tour.
Sémantique de notationLien direct vers Sémantique de notation
Ces détails sont importants lors de l’écriture de scorers pour des éléments multitours :
run.outputest la sortie cumulée de chaque tour. Les scorers fondés sur la sortie, tels quechecks.includes,checks.calledTool,checks.similarityet les scorers similaires, évaluent l’ensemble de la conversation. Par exemple,checks.calledTool('get_weather', { times: 2 })compte les appels effectués au cours de tous les tours.run.inputcontient uniquement l’entrée du premier tour. Les scorers qui comparent l’entrée à la sortie (fidélité, pertinence de la réponse et autres scorers LLM relatifs à l’entrée) voient uniquement le premier message de l’utilisateur, et non la conversation complète. Pour les évaluations multitours, privilégiez les vérifications fondées sur la sortie ou créez des scorers qui lisent directement la valeur cumulée derun.output.
Assertions par tour avec turnsLien direct vers per-turn-assertions-with-turns
La forme inputs note la sortie cumulée dans son ensemble : une seule note couvre la sortie de tous les tours. Cela peut masquer des échecs propres à certains tours : une vérification fondée sur la sortie, comme checks.includes('Brooklyn'), réussit si n’importe quel tour mentionne Brooklyn, même si le tour de suivi est défaillant.
Lorsque vous devez vérifier qu’un tour précis s’est déroulé correctement, utilisez plutôt turns. Chaque tour est un objet doté de sa propre input et, éventuellement, de gates/scorers qui évaluent uniquement l’entrée et la sortie de ce tour :
import { runEvals } from '@mastra/core/evals'
import { checks } from '@mastra/evals/checks'
import { weatherAgent } from '../agents'
const result = await runEvals({
data: [
{
turns: [
{
input: 'What is the weather in Brooklyn?',
gates: [checks.calledTool('get_weather')],
},
{
// The follow-up must call the tool again — it can't be satisfied
// by the first turn's tool call.
input: 'What about tomorrow?',
gates: [checks.calledTool('get_weather')],
scorers: [{ scorer: checks.similarity('tomorrow forecast'), threshold: 0.5 }],
},
],
},
],
target: weatherAgent,
})
result.verdict // 'passed' | 'scored' | 'failed'
result.turnResults // per-turn gate/threshold/scorer outcomes
Sémantique :
- Une gate ou un scorer propre à un tour voit uniquement les valeurs
run.inputetrun.outputde ce tour, jamais la conversation cumulée. Cela corrige les deux angles morts deinputs: un autre tour ne peut pas satisfaire une vérification etrun.inputest correct pour chaque tour. - Les résultats par tour sont intégrés au verdict : l’échec d’une gate de tour fait passer le verdict à
failed. Un seuil non atteint pour un tour (si les gates réussissent) le fait passer àscored. result.turnResults[i]fournit les valeursgateResults,thresholdResultsetscoresde chaque tour, de sorte qu’un échec désigne précisément le tour concerné. Sur plusieurs conversations, la moyenne des résultats est calculée par indice de tour.- Un tour dépourvu de
gatesou descorersfait avancer la conversation. - Les
scorers/gatesde niveau supérieur continuent de s’exécuter globalement sur la sortie cumulée. Vous pouvez donc combiner « ce tour doit appeler l’outil » et « la réponse mentionne Brooklyn ». - Lorsque le stockage est configuré pour l’agent, le résultat de chaque scorer ou gate propre à un tour est conservé comme les notes de niveau supérieur, si bien que les résultats par tour apparaissent dans votre stockage de notes. Chaque note par tour ainsi stockée porte l’indice du tour (
metadata.turnIndex), partage lethreadIdde la conversation et renvoie au span de trace propre à ce tour.
Utilisez inputs lorsqu’une seule note globale pour l’ensemble de la conversation suffit. Utilisez turns lorsque la validité dépend de chaque tour. turns ne peut pas être combiné avec input ou inputs dans un même élément de données.
Combinaison avec des gates et des seuilsLien direct vers Combinaison avec des gates et des seuils
Les éléments de données multitours sont compatibles avec les gates et les verdicts. Utilisez des scorers fondés sur la sortie afin que les gates tiennent compte de l’intégralité de la conversation :
import { runEvals } from '@mastra/core/evals'
import { checks } from '@mastra/evals/checks'
const result = await runEvals({
data: [
{
inputs: ['My favorite city is Brooklyn.', 'What is the weather in my favorite city?'],
},
],
target: weatherAgent,
gates: [checks.calledTool('get_weather')],
scorers: [{ scorer: checks.similarity('Brooklyn weather forecast'), threshold: 0.5 }],
})
result.verdict // 'passed' | 'scored' | 'failed'
Mélange d’éléments monotours et multitoursLien direct vers Mélange d’éléments monotours et multitours
Un même appel à runEvals peut inclure à la fois des éléments de données monotours et multitours :
const result = await runEvals({
data: [
{ input: 'What is the weather in Brooklyn?' },
{
inputs: ['My favorite city is Brooklyn.', 'What is the weather in my favorite city?'],
},
],
target: weatherAgent,
scorers: [checks.includes('Brooklyn')],
})
Les éléments monotours utilisent input comme d’habitude. Les éléments multitours utilisent inputs et peuvent entièrement omettre input.
ValidationLien direct vers Validation
runEvals lève une MastraError si inputs est présent mais vide :
// Throws: 'inputs' must be a non-empty array
await runEvals({
data: [{ inputs: [] }],
target: myAgent,
scorers: [myScorer],
})
Pages associéesLien direct vers Pages associées
- Référence de
runEvals(): API complète des paramètres et valeurs de retour derunEvals - Gates et verdicts : imposez des exigences strictes et des seuils de qualité
- Quick Checks : micro-scorers composables sans LLM