Datasets
新增于: @mastra/core@1.4.0
数据集是测试用例的集合,你针对它们运行实验,以衡量 agents 和 workflows 的表现。每次变更都会创建一个新版本,因此你可以精确复现过去的实验。将数据集与 scorer 配合使用,可以跨提示词、模型或代码变更跟踪质量。
使用使用的直接链接
配置存储配置存储的直接链接
在 Mastra 实例中配置存储。数据集需要提供 datasets 域的存储适配器:
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',
}),
})
访问 datasets API访问 datasets API的直接链接
所有数据集操作都可以通过 mastra.datasets 使用:
const datasets = mastra.datasets
// Create a dataset
const dataset = await datasets.create({ name: 'my-dataset' })
// Retrieve an existing dataset
const existing = await datasets.get({ id: 'dataset-id' })
// List all datasets
const { datasets: all } = await datasets.list()
完整方法列表请参阅 DatasetsManager 参考。
StudioStudio的直接链接
你也可以在 Studio 中管理数据集。打开 Studio 后,从侧边栏选择 Datasets 以查看所有可用数据集或创建新数据集。
首先选择 Create Dataset,设置名称、描述和可选 schema。确认后,你会看到数据集详情页,其中有两个标签页:Items 和 Experiments。
在 Items 视图中,你可以添加、更新和删除数据项,并查看版本历史。选择 Add Item 以使用 JSON 编辑器插入新项,填写 input 和 ground truth。此视图还支持从 CSV 或 JSON 文件批量导入数据项。导入时,请将每一列映射到对应的数据集字段。
选择 Versions 可查看数据集的完整变更历史。选择 Compare Versions 后,选取任意两个版本并点击 Compare,即可查看这些版本之间新增、修改或删除的所有数据项的并排差异。
创建数据集创建数据集的直接链接
调用 create() 并传入名称和可选描述:
import { mastra } from '../index'
const dataset = await mastra.datasets.create({
name: 'translation-pairs',
description: 'English to Spanish translation test cases',
})
console.log(dataset.id) // auto-generated UUID
定义 schema定义 schema的直接链接
你可以在创建数据集时传入 Standard JSON Schema(Zod、Valibot、ArkType 等)来约束 input 和 groundTruth 的结构:
import { z } from 'zod'
import { mastra } from '../index'
const dataset = await mastra.datasets.create({
name: 'translation-pairs',
inputSchema: z.object({
text: z.string(),
sourceLang: z.string(),
targetLang: z.string(),
}),
groundTruthSchema: z.object({
translation: z.string(),
}),
})
不符合 schema 的数据项会在插入时被拒绝。
添加数据项添加数据项的直接链接
单个数据项使用 addItem(),批量插入使用 addItems():
// Single item
await dataset.addItem({
input: { text: 'Hello', sourceLang: 'en', targetLang: 'es' },
groundTruth: { translation: 'Hola' },
})
// Bulk insert
await dataset.addItems({
items: [
{
input: { text: 'Goodbye', sourceLang: 'en', targetLang: 'es' },
groundTruth: { translation: 'Adiós' },
},
{
input: { text: 'Thank you', sourceLang: 'en', targetLang: 'es' },
groundTruth: { translation: 'Gracias' },
},
],
})
存储的字段值存储的字段值的直接链接
内存、LibSQL、PostgreSQL、MySQL、MongoDB 和 Spanner 数据集存储会在 input、groundTruth 和 expectedTrajectory 中保留 JSON null,以及空字符串、数组和对象。省略的可选 JSON 字段在序列化时保持缺失。数据集 schema 仍决定数据项接受哪些值。
快照校验不会覆盖数据库限制。MongoDB 拒绝包含 NUL(\u0000)的对象属性名,即使 JSON 有效也不例外。包含此类键的批量插入会失败,不会存储任何数据项,也不会推进数据集版本。
对于配置更新,null 会清除 schema、标签、目标类型、目标 ID 或 scorer ID。这些适配器会将清除后的设置返回为 undefined,同时保留空数组和空对象。使用 scorerIds: null 更新数据项会移除其 scorer 覆盖,而 scorerIds: [] 会禁用该项的评分。省略的更新字段保持现有值不变。
使用相同 externalId 的重试会保留原始数据项的表示。为了向后兼容,插入操作在比较重试与现有项时,会将省略和 null 的 payload 字段视为等价。例如,插入一个没有 groundTruth 的项,然后用 groundTruth: null 重试,会返回没有 ground truth 的原始项。要存储显式 null,请使用数据项更新。
未设置的配置现在读取为 undefined,而某些适配器以前返回 null,因此序列化响应会省略这些属性。请使用 value ?? fallback 之类的 nullish 检查,而不要依赖显式的 null 属性。LibSQL 还会将省略的数据集描述返回为 undefined,与其声明的类型一致。
较旧的 LibSQL、PostgreSQL、MySQL 和 Spanner 写入会将可选 JSON null 值存储为 SQL NULL。这些值与省略字段无法区分。较旧的 MongoDB 写入会将省略的可选 payload 字段存储为 BSON null。存储修复会保留新的写入,但不会重建以前丢失的差异。
校验快照产物校验快照产物的直接链接
使用 @mastra/core/datasets 中的 createDatasetSnapshot() 和 parseDatasetSnapshot() 创建并校验带版本的 JSON 产物。这些是纯格式工具:它们不会从存储导出、导入数据集、分配可移植身份,也不会更改 Studio 的 JSON 导入器。
import { createDatasetSnapshot, parseDatasetSnapshot } from '@mastra/core/datasets'
const snapshot = createDatasetSnapshot({
formatVersion: 1,
datasetIdentity: '00000000-0000-4000-8000-000000000001',
configuration: { name: 'translation-pairs' },
items: [
{
itemIdentity: '00000000-0000-4000-8000-000000000002',
createdAt: '2026-09-01T09:00:00.123Z',
updatedAt: '2026-09-10T10:00:00.456Z',
payload: { input: 'Hello', groundTruth: 'Hola', scorerIds: [] },
},
],
provenance: {
exportedAt: '2026-09-11T12:00:00Z',
sourceDatasetId: 'dev-translations',
itemVersion: 1,
configurationBasis: 'export-time',
},
})
const parsed = parseDatasetSnapshot(JSON.stringify(snapshot))
console.log(parsed.digest === snapshot.digest) // true
该产物包含配置、完整的已编写数据项 payload、可移植 UUID 和来源信息。请提供稳定的小写 UUID,而不要在每次序列化时生成新身份。已编写的 externalId 值与可移植身份相互独立,并保持不变。缺失、null 和空覆盖保持区别。请省略可选属性,而不是赋值为 undefined。数据集描述也保留缺失、null 和字符串值。
每个数据项要求 createdAt 和 updatedAt 为具有毫秒精度的 UTC ISO 8601 字符串,与四位年份的 Date.toISOString() 匹配。两个时间戳都会包含在完整性摘要中。它们代表数据项的实际日期,而不是传输来源:导入器必须将它们保留为目标数据项的 createdAt 和 updatedAt,而不是用导入时间替换。导入器会在单独的接收记录中记录传输时间,而目标中的后续编辑会正常更新 updatedAt。实现存储导入仍不在这些格式工具的范围内。
此保留适用于所提供的产物内容。存储适配器在捕获之前可能已经归一化了值。格式校验既不会恢复这些差异,也不保证普通数据集 CRUD 操作能够恢复它们。例如,PostgreSQL JSONB 会拒绝包含 NUL 字符(\u0000)的字符串,即使它们在产物中有效。在写入产物内容之前,请校验目标存储的限制。
对于无效内容或大小选项,两个辅助函数都会抛出 Zod 校验错误。datasetSnapshotContentSchema.safeParse() 校验未签名内容和身份唯一性,而 datasetSnapshotSchema.safeParse() 还会检查摘要。这些 schema 不强制字节限制。对于不受信任的文本,请使用 parseDatasetSnapshot(),以便在解析前强制执行大小预算,并拒绝重复的 JSON 属性名。
这些辅助函数默认使用 4 MiB 的 UTF-8 预算(DATASET_SNAPSHOT_DEFAULT_MAX_BYTES)。将 { maxBytes } 作为第二个参数传给任一辅助函数可提高或降低该值。该值必须是正的安全整数。这是操作限制,不属于 v1 格式或摘要。例如,使用 8 MiB 预算解析上述快照:
const parsedWithLargerBudget = parseDatasetSnapshot(JSON.stringify(snapshot), {
maxBytes: 8 * 1024 * 1024,
})
createDatasetSnapshot() 会测量完整产物的紧凑 JSON.stringify() 输出,包括摘要。parseDatasetSnapshot() 会测量提供的文本,包括空白。Pretty-printing 可能超出接受紧凑产物的预算。两个辅助函数都不会截断数据。创建期间,校验、克隆和哈希会在字节大小检查之前进行。由于共享引用在 JSON 序列化期间可能扩展,该预算限制输出大小,但不限制 CPU 时间或峰值内存。添加传输层时,请单独配置 HTTP 请求体限制与此预算。
产物的最大嵌套深度为 100,从信封根开始计算。它们会拒绝未知的结构字段、重复的数据项身份或非 null 的 externalId 值、非 JSON 值和无效 Unicode。程序化内容必须使用普通对象和标准数组,而不是类实例或数组子类。已编写 payload 中的任意 JSON 会保持不变,包括轨迹预期。数据集 schema 会保留为 JSON 对象,但这些工具不会编译它们,也不会根据它们校验数据项。目标授权、引用解析和存储支持也需要单独的预检。
摘要是不含 digest 的信封的 RFC 8785 规范 JSON 表示的小写十六进制 SHA-256 哈希。哈希时按可移植身份对数据项排序,而已编写数组的顺序保持不变。来源信息也包含在内,因此新的捕获时间会改变摘要。摘要匹配可验证完整性,但不建立作者身份或审批。在创建产物之前请检查敏感数据,因为这些工具不会对其进行脱敏。
更新、删除和清除数据项更新、删除和清除数据项的直接链接
updateItem()、deleteItem() 和 deleteItems() 在修改或删除数据项时会创建新的数据集版本:
await dataset.updateItem({
itemId: 'item-abc-123',
groundTruth: { translation: '¡Hola!' },
})
await dataset.deleteItem({ itemId: 'item-abc-123' })
await dataset.deleteItems({ itemIds: ['item-1', 'item-2'] })
删除数据项会将其从当前数据集版本中隐藏,但在历史行和删除墓碑中保留其内容。使用 purgeItem() 可对数据项在现有历史中的存储内容进行脱敏:
await dataset.purgeItem({ itemId: 'item-abc-123' })
清除会将每个历史行和删除墓碑中的内容替换为脱敏值,并清除关联的实验结果 payload、标签和评论。该数据项后续提交的实验结果也会以脱敏内容存储。
清除会与并发的数据集项写入者串行化或冲突,但不保证哪个操作先完成。如果变更性的 updateItem() 调用竞争失败,它会重新读取清除标记并以 DATASET_ITEM_PURGED 拒绝。deleteItem() 保持幂等,竞争期间创建的任何删除墓碑都会保持脱敏状态。
常规数据项变更使用缓慢变化维度类型 2(SCD-2)版本控制。永久清除为了擦除数据会有意覆盖历史不可变性,同时保留数据项身份和数据集版本时间线。它不会创建数据集版本,也无法撤销。实验计数器和审查状态也会保留。避免在 externalId 中存储敏感数据,因为它是数据项的身份键,会保持不变。
此操作要求 MongoDB 存储使用支持事务的副本集或分片部署。当 MongoDB 事务不可用时,清除会在更改数据之前失败。
列出和搜索数据项列出和搜索数据项的直接链接
listItems() 支持分页和不区分大小写的子字符串搜索:
// Paginated list
const { items, pagination } = await dataset.listItems({
page: 0,
perPage: 50,
})
// Substring search
const { items: matches } = await dataset.listItems({
search: 'Hello',
})
// Search and pagination can be combined with a specific version
const { items: v2Matches } = await dataset.listItems({
version: 2,
search: 'Hello',
page: 0,
perPage: 50,
})
在未提供 search、page 或 perPage 的情况下调用 listItems({ version }) 会返回裸 DatasetItem[]。该形式已弃用。请传入 page 和 perPage,以便始终获得分页结构。
版本控制版本控制的直接链接
添加、更新或删除数据集项会提升数据集版本。使用 purgeItem() 清除数据项的存储内容不会创建新版本。这让你可以将实验固定到特定数据快照,同时在不改变版本历史的情况下擦除敏感内容。
列出各个版本列出各个版本的直接链接
使用 listVersions() 查看分页的版本历史:
const { versions, pagination } = await dataset.listVersions()
for (const v of versions) {
console.log(`Version ${v.version} — created ${v.createdAt}`)
}
查看数据项历史查看数据项历史的直接链接
使用 itemId 调用 getItemHistory(),查看特定数据项在各个版本中的变化:
const history = await dataset.getItemHistory({ itemId: 'item-abc-123' })
for (const row of history) {
console.log(`Version ${row.datasetVersion}`, row.input, row.groundTruth)
}
固定到某个版本固定到某个版本的直接链接
获取过去某个版本中确切存在的数据项:
const { items } = await dataset.listItems({ version: 2, page: 0, perPage: 100 })
你也可以将实验固定到某个版本,参见运行实验。完整的方法和参数列表请参阅 Dataset 参考。