如何在 Mastra 中创建版本化 dataset 并针对代理运行 experiment 对比评分
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
当你改了代理的 prompt、换了模型,或者升级了某段代码后,想知道“新版本到底比旧版本好多少”,Mastra 的 datasets 和 experiments 机制就是为此设计的:把一组固定的测试用例存进 versioned dataset,让注册在 Mastra 实例上的代理逐个跑完并用 scorer 打分,再用compareExperiments()或 Studio 的对比视图把两次 experiment 的分数并排摆出来。datasets 与 experiments 均在@mastra/core@1.4.0引入,因此前提是你的项目使用 1.4.0 及以上版本,并且配置了支持datasetsdomain 的存储适配器。
前提条件:安装依赖并配置支持 datasets 的存储
在Mastra实例中配置一个提供datasetsdomain 的存储适配器,文档示例使用 LibSQL:
import { Mastra } from '@mastra/core' import { LibSQLStore } from '@mastra/libsql' export const mastra = new Mastra({ storage: new LibSQLStore({ id: 'my-store', url: 'file:./mastra.db', }), })如果使用 prebuilt scorers,还需要安装@mastra/evals:
npm install @mastra/evals@latest创建 dataset 并用 schema 约束条目结构
通过mastra.datasets.create()创建 dataset。传入inputSchema和groundTruthSchema后,不符合 schema 的条目会在插入时被拒绝:
import { z } from 'zod' import { mastra } from '../index' const dataset = await mastra.datasets.create({ name: 'translation-pairs', description: 'English to Spanish translation test cases', inputSchema: z.object({ text: z.string(), sourceLang: z.string(), targetLang: z.string(), }), groundTruthSchema: z.object({ translation: z.string(), }), }) console.log(dataset.id) // auto-generated UUID注意这里input是一个对象。如果实验目标(target)是 agent,每个 item 的input会被直接传给agent.generate(),因此它必须是string、string[]或CoreMessage[]——agent 场景下 schema 应按这个形状定义,而不是上面这种自定义对象。
批量添加条目并管理版本
用addItem()插入单条、addItems()批量插入:
// Bulk insert await dataset.addItems({ items: [ { input: 'Translate "goodbye" to Spanish.', groundTruth: { translation: 'Adiós' }, }, { input: 'Translate "thank you" to Spanish.', groundTruth: { translation: 'Gracias' }, }, ], })版本化的核心规则:添加、更新、删除条目都会提升 dataset 版本,所以你可以随时回到任意历史快照。验证版本历史用listVersions(),按版本取快照用listItems({ version: N }),查看单个条目在各版本间的变化用getItemHistory({ itemId }):
const { versions, pagination } = await dataset.listVersions() for (const v of versions) { console.log(`Version ${v.version} — created ${v.createdAt}`) } // 取第 2 版的精确快照(返回 DatasetItem[]) const v2Items = await dataset.listItems({ version: 2 })注册 scorer
experiment 的scorers选项接受注册在 Mastra 实例上的 scorer ID 或 scorer 实例。以 prebuilt 的answerRelevancy为例,在实例上注册:
import { Mastra } from '@mastra/core' import { LibSQLStore } from '@mastra/libsql' import { createAnswerRelevancyScorer } from '@mastra/evals/scorers/prebuilt' import { myAgent } from './agents/my-agent' export const mastra = new Mastra({ agents: { myAgent }, storage: new LibSQLStore({ id: 'my-store', url: 'file:./mastra.db' }), scorers: { answerRelevancy: createAnswerRelevancyScorer({ // 文档中的 '__GATEWAY_OPENAI_MODEL_MINI__' 是占位符, // 替换为你自己的模型,如 openai/gpt-4o-mini model: 'openai/gpt-4o-mini', }), }, })文档中所有__GATEWAY_OPENAI_MODEL_MINI__均为占位符,按你实际使用的模型替换。完整的内置 scorer 列表(answer-relevancy、answer-similarity、faithfulness、completeness等)见 built-in scorers 文档。
针对代理运行 experiment
startExperiment()会把 dataset 中每个 item 依次发给目标,并在每项执行后自动跑 scorer。它阻塞到全部 item 完成,然后返回ExperimentSummary:
const dataset = await mastra.datasets.get({ id: 'translation-dataset-id' }) const summary = await dataset.startExperiment({ name: 'agent-v1-eval', targetType: 'agent', targetId: 'my-agent', // Mastra 实例中注册的 agent id scorers: ['answerRelevancy'], // version: 2, // 可选:固定到 dataset 的某个版本,默认最新版本 }) console.log(summary.status) // 'completed' | 'failed' console.log(summary.succeededCount) // 成功执行的 item 数 console.log(summary.failedCount) // 失败的 item 数summary.results里是逐 item 的输出和每个 scorer 的分数,可以直接打印:
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}`) } }这就是验证点:status为'completed'且failedCount为 0 说明整个跑通;部分 item 失败时completedWithErrors为true。若想让两次对比基于同一份数据,给startExperiment()传入version固定到同一个 dataset 快照。
改完代理后,用同样的 dataset 版本和 scorers 再跑一次,例如:
const summary2 = await dataset.startExperiment({ name: 'agent-v2-eval', targetType: 'agent', targetId: 'my-agent', scorers: ['answerRelevancy'], version: 2, })对比两次 experiment 的评分
拿到两个 experiment ID 后(可通过dataset.listExperiments()列出该 dataset 的所有实验记录,返回中含 status 与计数),调用mastra.datasets.compareExperiments(),它要求至少 2 个 ID,并返回逐 item、逐 scorer 的对比数据:
const comparison = await mastra.datasets.compareExperiments({ experimentIds: ['exp-v1', 'exp-v2'], baselineId: 'exp-v1', // 可选,默认取 experimentIds 的第一个 }) for (const item of comparison.items) { console.log(`Item ${item.itemId}:`) for (const [expId, result] of Object.entries(item.results)) { if (result) { console.log( ` ${expId}: output=${JSON.stringify(result.output)}, scores=${JSON.stringify(result.scores)}`, ) } } }不想写脚本的话,Studio 提供同样的能力:打开 Studio 后在 dataset 详情页的Experimentstab 选中Compare,勾选两次及以上 experiment 即可并排查看 scores 与结果;选中单次 experiment 还能看到逐 item 结果和 execution traces。逐 item 的持久化结果也可以用dataset.listExperimentResults({ experimentId, page, perPage })拉取,返回中的result.output与result.error用于定位具体哪个 item 出了什么问题。
需要知道的边界与规则
- scorer 来源不合并:每个 item 只使用一个 scorer 来源,优先级依次为 experiment 的
scorers选项、item 的scorerIds、dataset 的scorerIds,都没有则不打分。显式传空数组[]表示“不打分”且不会回落到下一来源;某个来源里引用了不存在的 ID 会让实验 setup 直接失败(item 级过期 ID 则只使该 item 报EXPERIMENT_ITEM_SCORER_NOT_FOUND并跳过,其余 item 继续)。 - 版本语义:常规增删改提升版本,
purgeItem()(擦除条目内容)不提升版本;startExperiment()不带version时默认用最新版本。 - persistence 可独立关闭:
persistence: { experiments: 'none', scores: 'none' }可跳过本次运行的存储写入,目标与 scorer 照常执行,summary仍返回完整结果。该设置只影响 experiment/score 记录,不影响目标自身的存储(如 agent memory)。 - 工具 mock 的存储限制:LibSQL、PostgreSQL、MongoDB、Spanner 适配器会持久化工具 mock 及报告,MySQL 适配器会拒绝携带二者的写入;dataset 存储本身要求存储适配器支持
datasetsdomain。 - 长 dataset:
startExperiment()阻塞到结束;大数据集可改用startExperimentAsync()后台运行,再用dataset.getExperiment({ experimentId })轮询直到status变为'completed'或'failed'。
跑通一次基线、改完再跑一次、用compareExperiments()对照两组分数,就构成了一条可重复的“版本化数据 → 代理实验 → 评分对比”路径;后续如果要持续跑,参见 datasets 文档与 experiments 文档。
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考