執行實驗
新增於: @mastra/core@1.4.0
實驗會讓資料集中的每個項目通過一個目標(Agent、Workflow 或評分器),再視需要為輸出評分。若要評估 LLM 判定器本身,請使用評分器作為目標。結果預設會保存至儲存區,讓你比較不同提示詞、模型或程式碼變更下的執行結果。
基本實驗「基本實驗」的直接連結
呼叫 startExperiment(),並傳入目標與評分器:
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() 會封鎖至所有項目完成。若要啟動後不等待結果,請參閱非同步實驗。
Studio「Studio」的直接連結
你也可以在 Studio 中執行實驗。新增資料集項目後,開啟該項目並選取 Run Experiment,再設定目標、評分器與選項。
執行實驗後,Experiments 分頁會顯示該資料集的所有執行記錄(包括狀態、數量與時間戳記)。選取實驗即可查看逐項結果、分數與執行 Trace。
在 Experiments 分頁中選取 Compare,再選擇兩個以上的實驗,即可並排比較其分數與結果。
實驗目標「實驗目標」的直接連結
實驗可指向已註冊的 Agent、Workflow 或評分器。
已註冊的 Agent「已註冊的 Agent」的直接連結
指向 Mastra 執行個體上已註冊的 Agent:
const summary = await dataset.startExperiment({
name: 'agent-v2-eval',
targetType: 'agent',
targetId: 'translation-agent',
scorers: ['accuracy'],
})
每個項目的 input 都會直接傳給 agent.generate(),因此必須是 string、string[] 或 CoreMessage[]。
啟用記憶體的 Agent「啟用記憶體的 Agent」的直接連結
當目標 Agent 擁有自己的記憶體,且 request context 帶有資源 ID(MASTRA_RESOURCE_ID_KEY,由驗證中介軟體、實驗或項目的 requestContext,或 Studio Run Experiment 表單設定)時,實驗執行器會為每個項目注入新的記憶體討論串。request context 中的資源 ID 表示「以此資源執行」:各項目的對話會保存為該資源下的討論串,而重試項目每次嘗試都會取得新討論串,避免先前失敗嘗試的內容洩漏至重試 context。
注入的討論串會加上標記,以便對應回該次執行:討論串中繼資料包含 experimentId,並以 experimentItemId 保存資料集項目 ID。系統不會為這些討論串產生標題。
由於討論串屬於呼叫者的資源,資源範圍記憶體功能在執行期間會讀寫該資源的狀態:
- 資源範圍工作記憶體的更新會保存至資源,同次執行中的後續項目可看到較早項目所做的更新。
- 資源範圍語意回憶可向實驗提供該資源先前的對話;實驗逐字稿也能在該資源後續的對話中被回憶。
若要使用真實使用者累積的 context 評估 Agent,此功能很實用。若不希望實驗執行接觸真實使用者狀態,請改用專用的評估資源 ID 執行實驗。
下列情況會略過討論串注入:
- 若 request context 也設定
MASTRA_THREAD_ID_KEY,執行器會直接使用該討論串,因此所有項目(及重試)都共用同一段對話。 - 若 Agent 沒有記憶體,或 request context 沒有資源 ID,執行過程不會使用記憶體,也不會保存任何內容。
已註冊的 Workflow「已註冊的 Workflow」的直接連結
指向 Mastra 執行個體上已註冊的 Workflow:
const summary = await dataset.startExperiment({
name: 'workflow-eval',
targetType: 'workflow',
targetId: 'translation-workflow',
scorers: ['accuracy'],
})
Workflow 會接收每個項目的 input 作為觸發資料。
已註冊的評分器「已註冊的評分器」的直接連結
指向評分器,以標準答案評估 LLM 判定器:
const summary = await dataset.startExperiment({
name: 'judge-accuracy-eval',
targetType: 'scorer',
targetId: 'accuracy',
})
評分器會接收每個項目的 input 與 groundTruth。隨著底層模型變更,LLM 型判定器可能會逐漸偏移,因此必須定期以已知正確的標籤重新校準。資料集可提供穩定基準,用來偵測這類偏移。
評分結果「評分結果」的直接連結
每個項目的目標執行後,評分器會自動執行。請傳入評分器執行個體或已註冊的評分器 ID:
- 評分器 ID
- 評分器執行個體
// Reference scorers registered on the Mastra instance
const summary = await dataset.startExperiment({
name: 'with-registered-scorers',
targetType: 'agent',
targetId: 'translation-agent',
scorers: ['accuracy', 'fluency'],
})
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],
})
每個項目的結果都包含各評分器的分數:
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}`)
}
}
如需可用及自訂評分器的詳情,請參閱評分器概觀。
控制每次執行的保存方式「控制每次執行的保存方式」的直接連結
使用 persistence 可略過特定執行的儲存區寫入。實驗記錄與分數記錄可分別停用:
const summary = await dataset.startExperiment({
targetType: 'agent',
targetId: 'translation-agent',
scorers: ['accuracy'],
persistence: {
experiments: 'none',
scores: 'none',
},
})
目標與評分器仍會執行,startExperiment() 也仍會在 summary 中傳回項目結果與分數。這些設定彼此獨立。例如,只設定 scores: 'none' 可保存實驗與項目結果,但不建立分數記錄。
省略的設定預設為 'default',會保留標準儲存行為。此原則只控制該次執行建立的實驗與分數記錄,不會停用目標使用的儲存功能,例如 Agent 記憶體、向量、可觀測性或自訂 Tool 儲存區。
以 experiments: 'none' 執行 startExperimentAsync() 時,不會保存實驗記錄、進度更新或項目結果。分數保存仍由 persistence.scores 分別控制。若沒有實驗事件觀察器,此執行會啟動後即不再追蹤,實驗 API 無法回報完成或失敗。
呼叫者需要傳回的摘要時,請使用同步的 startExperiment()。實驗事件觀察器可接收生命週期事件與最終摘要。
觀察實驗事件「觀察實驗事件」的直接連結
使用 onEvent 可在實驗執行期間接收具版本且可安全轉為 JSON 的生命週期事件。此功能適用於 startExperiment()、startExperimentAsync() 與 runExperiment()。
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)
},
})
觀察器會接收下列事件類型:
experiment.run.started:識別執行、目標、解析後的資料集版本與項目數量。experiment.item.completed:回報評分後已提交的項目結果,包括分數、錯誤、重試次數、Tool mock 詳情與穩定的項目識別資訊。experiment.run.finished:回報最終結果與摘要計數器。
Mastra 會等待每次觀察器呼叫完成後再傳遞下一個事件。這種序列化傳遞會施加背壓,並確保事件 sequence 值符合傳遞順序,同時仍可並行執行項目。
若觀察器擲回錯誤或拒絕,Mastra 會中止剩餘執行,並以 id 為 EXPERIMENT_EVENT_OBSERVER_FAILED 的 MastraError 拒絕 runExperiment()。系統不會透過失敗的觀察器傳送最終事件。對 startExperimentAsync() 而言,分離的觀察器失敗時方法已傳回,因此呼叫者需要直接錯誤回報時,請在觀察器內處理傳遞失敗。
Mastra 會等待 experiment.run.finished 事件完成後,才保存最終實驗狀態。停用實驗保存時,請將此事件視為具權威性的最終訊號,但不要將其當作儲存區的寫入後讀取訊號。
匯出的事件類型包括 ExperimentEvent、ExperimentRunStartedEvent、ExperimentItemCompletedEvent 與 ExperimentRunFinishedEvent。讀取事件特有屬性前,請使用可辨識的 type 欄位縮小事件類型。
Tool mock「Tool mock」的直接連結
當實驗執行會呼叫具副作用 Tool 的 Agent 時,請將靜態 Tool mock 附加至個別資料集項目,使執行結果具確定性。實驗期間,被 mock 的 Tool 會傳回宣告的輸出,而不會實際執行。項目上沒有 mock 的 Tool 預設會實際執行。
Mock 儲存在資料集項目上,因此會隨資料列建立版本並與測試案例一同移動。每個 mock 都會宣告 Tool 名稱、預期引數與要傳回的輸出:
await dataset.addItem({
input: 'What is the weather in Seattle?',
toolMocks: [
{
toolName: 'getWeather',
args: { city: 'Seattle' },
output: { temperature: 60, conditions: 'rainy' },
},
],
})
Tool mock 僅支援 agent 目標。
封鎖未宣告的 Tool「封鎖未宣告的 Tool」的直接連結
在實驗上設定 unmockedToolPolicy: 'deny',即可封鎖所有沒有 mock 的 Tool 呼叫。實際呼叫可能造成副作用時,此設定很實用:
const summary = await dataset.startExperiment({
targetType: 'agent',
targetId: 'weather-agent',
unmockedToolPolicy: 'deny',
})
預設原則為 'allow'。你可以在個別已儲存或內嵌項目上覆寫實驗原則:
await dataset.addItem({
input: 'What is the weather in Seattle?',
unmockedToolPolicy: 'allow',
})
項目值的優先順序高於實驗值。遭拒的呼叫會在 Tool 執行前以 TOOL_MOCK_NOT_DECLARED 失敗;此失敗不會重試,也不會加入 liveCalls。
比對與取用「比對與取用」的直接連結
引數採嚴格比對:物件鍵順序會忽略、陣列順序則具有意義,且不進行型別強制轉換。只有當 Agent 呼叫 Tool 的引數與 mock 的 args 深度相等時,才會提供該 mock。
若項目為相同 Tool 與引數宣告多個 mock,系統會依序取用:第一次呼叫取得第一個 mock,下一次取得第二個,依此類推。順序會按每個 (toolName, args) 群組追蹤,不同引數之間彼此獨立。
比對模式「比對模式」的直接連結
每個 mock 預設會嚴格比對其 args。設定 matchArgs: 'ignore' 可只比對 Tool 名稱;系統不會比較 mock 的 args,無論 Agent 如何呼叫,都會提供該 Tool 下一個尚未取用的 mock:
const subAgentMock = {
toolName: 'agent-balanceAgent',
args: { prompt: 'look up the balance for YJ' },
output: { text: "YJ's balance is $100." },
matchArgs: 'ignore',
}
Tool 引數包含雜訊或由模型產生時,此設定很實用。最常見的情況是模擬子 Agent 的回應:委派的子 Agent 會以 agent-<name> Tool 的形式提供給父 Agent,其引數包含 LLM 撰寫的 prompt 與執行階段注入欄位。模擬 agent-<name> 會傳回預設回應,不執行子 Agent 及其內部 Tool。從 Trace 建立 mock 時,系統會自動以 matchArgs: 'ignore' 衍生子 Agent 委派呼叫;你可以改為 'strict' 以鎖定確切引數。
失敗「失敗」的直接連結
Tool 呼叫違反 mock 設定時,該項目會失敗:
TOOL_MOCK_MISMATCH:呼叫 Tool 所用的引數沒有相符的 mock。TOOL_MOCK_EXHAUSTED:所有相符的 mock 都已取用。TOOL_MOCK_NOT_DECLARED:Tool 沒有 mock,且實際生效的unmockedToolPolicy為'deny'。
發生上述任何失敗時,Agent 執行會立即中止,因此模型無法繼續呼叫任何 Tool,包括原本會實際執行且具副作用的未 mock Tool。這些失敗具有確定性,因此不會重試。已宣告但從未使用的 mock 不會使項目失敗,而會回報為尚未取用。
啟用 mock 攔截時,Agent 的 Tool 會依序執行,使重複的 (toolName, args) mock 按 Provider 的呼叫順序取用。項目宣告 mock 或實際生效的 unmockedToolPolicy 為 'deny' 時,攔截功能便會啟用。
診斷「診斷」的直接連結
每個項目結果都帶有 toolMockReport,說明該次執行如何處理項目的 mock:
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
}
在 Studio 中編輯資料集項目,即可以 JSON 陣列撰寫 Tool mock;開啟實驗結果可查看相同報告。
限制「限制」的直接連結
- Mock 呼叫沒有 Tool span。 Mock 呼叫會在 Tool 執行前傳回輸出,因此不會建立 Tool span。由已儲存 Trace 支援的軌跡評分器可能看不到 mock Tool 呼叫;退回使用 Agent 訊息輸出的軌跡擷取仍能看到,因此軌跡評分結果可能會隨可觀測性設定而異。
- 儲存區支援。 LibSQL、PostgreSQL、MongoDB 與 Spanner 配接器會保存 Tool mock 及 Tool mock 報告。MySQL 配接器不支援這些資料,並會拒絕帶有 Tool mock 或 Tool mock 報告的寫入。所有資料集儲存配接器都會保存
unmockedToolPolicy。
非同步實驗「非同步實驗」的直接連結
startExperiment() 會封鎖至每個項目完成。對於長時間執行的資料集,請使用 startExperimentAsync() 在背景啟動實驗:
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'
使用 getExperiment() 輪詢完成狀態:
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'
設定選項「設定選項」的直接連結
並行處理「並行處理」的直接連結
控制並行執行的項目數(預設:5):
const summary = await dataset.startExperiment({
targetType: 'agent',
targetId: 'translation-agent',
maxConcurrency: 10,
})
逾時與重試「逾時與重試」的直接連結
設定每個項目的逾時時間(毫秒)與重試次數:
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
})
重試採用指數退避。中止錯誤一律不會重試。
中止實驗「中止實驗」的直接連結
傳入 AbortSignal 以取消執行中的實驗:
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,
})
其餘項目會在摘要中標示為已略過。
鎖定資料集版本「鎖定資料集版本」的直接連結
針對資料集的特定快照執行:
const summary = await dataset.startExperiment({
targetType: 'agent',
targetId: 'translation-agent',
version: 3, // use items from dataset version 3
})
查看結果「查看結果」的直接連結
列出實驗「列出實驗」的直接連結
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})`)
}
實驗詳細資料「實驗詳細資料」的直接連結
const experiment = await dataset.getExperiment({
experimentId: 'exp-abc-123',
})
console.log(experiment.status)
console.log(experiment.startedAt)
console.log(experiment.completedAt)
觀看 Mastra 資料集與實驗工作流程,瞭解資料集與實驗如何協助提升可靠性。
項目層級結果「項目層級結果」的直接連結
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)
}
瞭解摘要「瞭解摘要」的直接連結
startExperiment() 會傳回 ExperimentSummary,其中包含計數與逐項結果:
- 實驗已完成但部分項目失敗時,
completedWithErrors為true。 - 透過
signal取消的項目會計入skippedCount。
如需完整的參數與傳回類型文件,請參閱 startExperiment 參考文件。