> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # 多輪 Evals 多輪 Evals 會測試 Agent 在一段對話中的行為。你不必提供單一 `input`,而是提供 `inputs` 陣列。每個項目都會在同一個 thread 上依序傳送給 Agent,評分器則會看到所有對話輪次累積的輸出。 ## 多輪 Evals 的適用時機 - Agent 使用記憶體,而且必須回想先前對話輪次的內容 - Agent 會處理依賴先前回應的後續問題 - 你需要驗證對話中的 Tool 呼叫順序 - Agent 會執行多步驟 Workflow(搜尋、確認、執行) ## 快速入門 ```typescript 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')], }) ``` 每個對話輪次都會使用相同的 thread ID 執行 `agent.generate()`,因此 Agent 能看到完整對話記錄。評分器會收到所有對話輪次累積的輸出訊息。 ## 跨輪回想需要記憶體 多輪回想需要 Agent 已**設定記憶體儲存區**。共用 thread ID 可讓每個對話輪次看到先前輪次,但只有 Agent 設有記憶體時,thread 才會保存記錄。若 Agent 未設定記憶體,對話輪次仍會依序執行,輸出也仍會累積供評分使用,但 Agent 不會記得先前輪次(每筆輸入都會獨立執行)。當你對未設定記憶體的 Agent 使用 `inputs` 時,`runEvals` 會記錄警告。 `runEvals` 會替你管理對話識別資訊:它會產生共用 `threadId` 並注入 `resourceId`(Mastra 記憶體會依資源與 thread 界定訊息範圍,因此兩者都是回想功能的必要條件)。資源預設衍生自產生的 thread,讓每段對話彼此隔離。若要固定特定資源,例如重複使用現有使用者的記憶體,請傳入 `targetOptions.memory.resource`;thread 仍由 `runEvals` 管理,因此不必提供: ```typescript 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' } }, }) ``` 如需記憶體儲存區的設定方式,請參閱[記憶體](https://mastra.zisheng.pro/zh-TW/docs/memory/overview)。 ## 運作方式 當資料項目含有 `inputs` 陣列時,`runEvals` 會: 1. 為對話建立新的 thread(不重複的 `threadId`)與資源(會保留呼叫端提供的 `targetOptions.memory.resource`) 2. 在該 thread 上透過 `agent.generate()` 依序傳送每筆輸入 3. 累積所有對話輪次的輸出訊息 4. 將完整的累積輸出傳給評分器進行評估 評分器會看到完整對話輸出,包括每個對話輪次。 ## 評分語意 為多輪項目撰寫評分器時,請注意以下細節: - **`run.output` 是每個對話輪次的累積輸出。** 輸出式評分器(如 `checks.includes`、`checks.calledTool`、`checks.similarity` 等)會評估整段對話。例如,`checks.calledTool('get_weather', { times: 2 })` 會計算所有對話輪次中的呼叫次數。 - **`run.input` 只包含第一輪輸入。** 比較輸入與輸出的評分器(忠實度、答案相關性與其他輸入相對式 LLM 評分器)只會看到第一則使用者訊息,而非完整對話。對多輪評估而言,請優先使用輸出式檢查,或建立直接讀取累積 `run.output` 的評分器。 ## 使用 `turns` 進行逐輪斷言 `inputs` 形式會將**累積**輸出視為整體評分,也就是針對所有對話輪次的輸出給出單一分數。這可能掩蓋個別輪次的失敗:只要\_任一\_輪提到 Brooklyn,`checks.includes('Brooklyn')` 之類的輸出式檢查就會通過,即使後續輪次已出錯也是如此。 若要斷言**特定對話輪次**的行為正確,請改用 `turns`。每個對話輪次都是一個物件,包含自己的 `input`,並可選擇提供只評估**該輪**輸入與輸出的 `gates`/`scorers`: ```typescript 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 ``` 語意如下: - 逐輪閘門或評分器**只會看到該輪的** `run.input` 與 `run.output`,絕不會看到累積對話。這解決了 `inputs` 的兩個盲點:錯誤的對話輪次無法滿足檢查,而且每一輪的 `run.input` 都正確無誤。 - 逐輪結果會納入[判定結果](https://mastra.zisheng.pro/zh-TW/docs/evals/gates-and-verdicts):某一輪的閘門失敗會使判定結果成為 `failed`;若閘門皆通過,但某輪未達臨界值,則結果為 `scored`。 - `result.turnResults[i]` 會回報各輪的 `gateResults`、`thresholdResults` 與 `scores`,因此能精確指出失敗的對話輪次。若有多段對話,則依對話輪次索引計算平均結果。 - 未設定 `gates` 或 `scorers` 的對話輪次仍會推進對話。 - 頂層 `scorers`/`gates` 仍會針對累積輸出整體執行,因此你可以結合「這一輪必須呼叫 Tool」與「答案提到 Brooklyn」等條件。 - Agent 設有儲存區時,每個逐輪評分器/閘門結果都會像頂層分數一樣保存,因此逐輪結果會出現在分數儲存區中。每個已儲存的逐輪分數都會標示其對話輪次索引(`metadata.turnIndex`)、共用該段對話的 `threadId`,並連結至該輪自己的 Trace span。 若整段對話只需一個整體分數,請使用 `inputs`;若正確性取決於個別對話輪次,請使用 `turns`。同一資料項目中的 `turns` 不能與 `input` 或 `inputs` 結合使用。 ## 結合閘門與臨界值 多輪資料項目可搭配[閘門與判定結果](https://mastra.zisheng.pro/zh-TW/docs/evals/gates-and-verdicts)使用。請使用輸出式評分器,讓閘門判斷反映完整對話: ```typescript 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' ``` ## 混用單輪與多輪項目 單次 `runEvals` 呼叫可以同時包含單輪與多輪資料項目: ```typescript 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`: ```typescript // Throws: 'inputs' must be a non-empty array await runEvals({ data: [{ inputs: [] }], target: myAgent, scorers: [myScorer], }) ``` ## 相關資源 - [`runEvals()` 參考](https://mastra.zisheng.pro/zh-TW/reference/evals/run-evals):`runEvals` 參數與傳回值的完整 API - [閘門與判定結果](https://mastra.zisheng.pro/zh-TW/docs/evals/gates-and-verdicts):強制執行必要要求與品質臨界值 - [Quick Checks](https://mastra.zisheng.pro/zh-TW/docs/evals/quick-checks):不使用 LLM 的可組合微型評分器