マルチターン Evals
マルチターン Evals は、会話全体にわたる Agent の動作をテストします。単一の input の代わりに、inputs 配列を指定します。各要素は同じ Thread 上で Agent に順番に送信され、Scorer はすべての Turn から蓄積された出力を参照します。
マルチターン Evals を使用する場面マルチターン Evals を使用する場面への直接リンク
- Agent が Memory を使用し、前の Turn のコンテキストを記憶する必要がある
- Agent が以前の応答に依存するフォローアップ質問を処理する
- 会話全体にわたる Tool 呼び出しの順序を検証する必要がある
- Agent が複数ステップの Workflow(検索、確認、実行)を実行する
クイックスタートクイックスタートへの直接リンク
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')],
})
各 Turn では同じ Thread ID を使用して agent.generate() が実行されるため、Agent は会話履歴全体を参照できます。Scorer は、すべての Turn から蓄積された出力メッセージを受け取ります。
Turn をまたぐ記憶には Memory が必要Turn をまたぐ記憶には Memory が必要への直接リンク
マルチターンでの記憶は、Agent に Memory Store が設定されていることに依存します。共有 Thread ID によって各 Turn から前の Turn を参照できますが、Thread の履歴が永続化されるのは Agent に Memory がある場合だけです。Agent に Memory が設定されていない場合も、Turn は順番に実行され、その出力は採点用に蓄積されますが、Agent は前の Turn を記憶しません(各入力は独立して実行されます)。Memory のない Agent で inputs を使用すると、runEvals は警告を記録します。
runEvals は会話 ID を自動的に管理します。共有 threadId を生成し、resourceId を注入します(Mastra Memory は Resource と Thread の組み合わせでメッセージのスコープを設定するため、記憶を機能させるには両方が必要です)。デフォルトでは、生成された Thread から Resource が派生するため、各会話は分離されます。既存ユーザーの Memory を再利用する場合など、特定の Resource に固定するには targetOptions.memory.resource を渡します。Thread は引き続き runEvals が管理するため、指定する必要はありません。
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' } },
})
Memory Store の設定方法については、Memoryを参照してください。
仕組み仕組みへの直接リンク
データ項目に inputs 配列がある場合、runEvals は次の処理を行います。
- 会話用に新しい Thread(一意の
threadId)と Resource を作成する(呼び出し元が指定したtargetOptions.memory.resourceは維持される) - その Thread 上で
agent.generate()を介して各入力を順番に送信する - すべての Turn の出力メッセージを蓄積する
- 蓄積した完全な出力を評価用に Scorer へ渡す
Scorer は、すべての Turn を含む完全な会話出力を参照します。
採点のセマンティクス採点のセマンティクスへの直接リンク
マルチターン項目用の Scorer を作成する際は、次の詳細が重要です。
run.outputはすべての Turn から蓄積された出力です。checks.includes、checks.calledTool、checks.similarityなどの出力ベースの Scorer は、会話全体を評価します。たとえば、checks.calledTool('get_weather', { times: 2 })は、すべての Turn にわたる呼び出しを数えます。run.inputは最初の Turn の入力だけです。 入力と出力を比較する Scorer(Faithfulness、Answer Relevancy、その他の入力相対型 LLM Scorer)には、会話全体ではなく最初のユーザーメッセージだけが渡されます。マルチターンでは出力ベースのチェックを優先するか、蓄積されたrun.outputを直接読み取る Scorer を作成してください。
turns による Turn ごとの検証per-turn-assertions-with-turnsへの直接リンク
inputs 形式では、蓄積された出力全体を、すべての Turn の出力に対する単一の Score として採点します。このため、Turn ごとの失敗が見えなくなる可能性があります。checks.includes('Brooklyn') のような出力ベースのチェックは、フォローアップの Turn が壊れていても、いずれかの Turn で Brooklyn に言及していれば合格します。
特定の Turn が正しく動作したことを検証する必要がある場合は、代わりに turns を使用します。各 Turn は、独自の input と、その Turn の入力と出力だけを評価する任意の gates/scorers を持つオブジェクトです。
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
セマンティクスは次のとおりです。
- Turn ごとの Gate または Scorer が参照するのは、その Turn の
run.inputとrun.outputだけであり、蓄積された会話は参照しません。これにより、inputsにある2つの盲点が解消されます。別の Turn でチェックを満たすことはできず、各 Turn で正しいrun.inputが使用されます。 - Turn ごとの結果は Verdict に集約されます。Turn の Gate が失敗すると Verdict は
failedになります。Gate が合格していても Turn の Threshold を満たさなければ、scoredになります。 result.turnResults[i]は、各 Turn のgateResults、thresholdResults、scoresを報告するため、失敗した正確な Turn を特定できます。複数の会話では、Turn のインデックスごとに結果が平均されます。gatesもscorersもない Turn は、会話を次へ進めます。- トップレベルの
scorers/gatesは、引き続き蓄積された出力全体に対して実行されるため、「この Turn では Tool を呼び出す必要がある」と「回答で Brooklyn に言及する」を組み合わせられます。 - Agent に Storage が設定されている場合、Turn ごとの各 Scorer/Gate の結果はトップレベルの Score と同様に永続化され、Score Store に表示されます。保存された Turn ごとの各 Score には Turn のインデックス(
metadata.turnIndex)が付けられ、会話のthreadIdを共有し、その Turn 固有の Trace Span にリンクされます。
会話全体に対する単一の Score で十分な場合は inputs を使用します。正しさが個々の Turn に依存する場合は turns を使用します。同じデータ項目で turns と input または inputs を組み合わせることはできません。
Gate と Threshold との組み合わせGate と Threshold との組み合わせへの直接リンク
マルチターンのデータ項目は、Gate と Verdictに対応しています。Gate が会話全体を反映するよう、出力ベースの Scorer を使用してください。
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'
シングルターンとマルチターンの混在シングルターンとマルチターンの混在への直接リンク
1 回の runEvals 呼び出しには、シングルターンとマルチターンの両方のデータ項目を含められます。
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')],
})
シングルターンの項目では通常どおり input を使用します。マルチターンの項目では inputs を使用し、input は完全に省略できます。
検証検証への直接リンク
inputs が存在していて空の場合、runEvals は MastraError をスローします。
// Throws: 'inputs' must be a non-empty array
await runEvals({
data: [{ inputs: [] }],
target: myAgent,
scorers: [myScorer],
})
関連情報関連情報への直接リンク
runEvals()リファレンス:runEvalsのパラメーターと戻り値に関する完全な API- Gate と Verdict: 厳格な要件と品質 Threshold を適用する
- Quick Checks: LLM 不要で組み合わせ可能なマイクロ Scorer