Mastra Studio Vercel PR 预览指南:独立 Workspace、种子数据与 Serverless 构建全解析
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
本文围绕 Mastra 仓库中的 Studio Preview 应用(packages/playground/vercel-preview)展开,讲清楚它如何作为 Mastra Studio 的 Vercel PR 预览目标:如何以独立 workspace 的方式被部署、如何用内存存储与确定性种子数据让 Studio 各页面开箱即有数据,以及本地安装、Vercel 项目配置、模型选择与链接依赖构建的完整实操链路。读完后你能复现一个“打开预览 URL 即可测试可用 Agent 页面”的 Studio 预览环境,并理解其中每个关键设计(独立 lockfile、link:依赖、冷启动重新种子化)背后的源码依据。
这个应用是什么,为什么放在 packages/playground 里
Studio Preview 是 Mastra Studio 的 Vercel PR 预览目标应用:它把 Studio 前端和一个最小化的 Mastra API 一起部署,评审人打开预览 URL 就能测试一个真正可运行的 Agent 页面。
从源码结构看,该应用刻意与 monorepo 其余部分保持隔离,核心机制是其自带的 pnpm-workspace.yaml:
packages: - '.' pnpm: overrides: hono@<4.12.34: 4.12.34 # a dependency install script this project never needed must not fail a preview deploy strictDepBuilds: falsepackages: ['.']使该目录成为自己的 workspace root:它拥有独立的 pnpm-lock.yaml,永远不会作为 monorepo 的一部分被安装。仓库原 README 指出这样做的目的有二:
- 它只是内部预览基础设施,不属于发布产物,monorepo 特有的模式(
link:依赖、根目录 turbo 构建)不应被复制到面向用户的示例中; - 该目录的任何改动对 turbo 和 changeset-bot 来说都算 playground 变更。这一代价被接受——因为应用很少变更,且纯预览用途的修改无需 changeset。
应用定位(package.json)也印证了其内部工具属性:
{ "name": "studio-preview", "type": "module", "private": true, "version": "0.0.0", "license": "Apache-2.0", "packageManager": "pnpm@11.21.0+sha512...." }private: true保证它不会被意外发布;自带的packageManager字段固定了 pnpm 版本,供后面的依赖安装脚本读取。
Serverless 友好的应用设计
README 明确该应用是“intentionally serverless-friendly”的,源码中每一条约束都有对应实现:
- 仅内存存储——无文件型存储,无 LibSQL / DuckDB 依赖。store.ts 只有一行核心代码:
import { InMemoryStore } from '@mastra/core/storage'; export const storage = new InMemoryStore();注释强调这个实例同时交给 Mastra、Agent 的Memory和种子例程使用,因此种子写入的数据都能通过 Studio 实际查询的那几个 store 读回。
一个确定性工具——preview-status.ts 定义了
preview-status工具,输入是一个枚举area(studio | agent | api | vercel),返回对应区域的确定性检查清单(如 “Mastra API routes are served under /api/*”)和status: 'ready'。它不访问任何外部服务,评审人可以拿它验证工具执行链路是否打通。一个启用 Memory 的 Agent——studio-preview-agent.ts 中注册了
studio-preview-agent,可在/agents/studio-preview-agent/chat/new打开。它启用 Memory 但只保留历史消息、关闭语义召回:
memory: new Memory({ storage, options: { lastMessages: 20, semanticRecall: false, }, }),注释说明这样做的效果:聊天侧边栏会报告 memory 可用,种子线程能显示出来,且实时聊天也持久化到同一个共享内存 store。同文件还注册了一个editorShowcaseAgent——它不持有 instructions/tools,而是通过editor: { instructions: true, tools: true }声明这两项由 Studio Editor 接管,专门用于演示编辑器版本管理流程。
- 启动时种子化的确定性演示数据——见下一节。
Mastra 实例的入口把这些部件组装起来,其中几处配置值得注意:
export const mastra = new Mastra({ agents: { studioPreviewAgent, editorShowcaseAgent }, tools: { previewStatusTool }, editor: new MastraEditor({ source: 'db' }), scorers: previewScorers, storage, bundler: { sourcemap: true }, deployer: new VercelDeployer({ studio: true, maxDuration: 60 }), server: { build: { openAPIDocs: true, swaggerUI: true } }, }); void seedStudioPreview();源码注释解释了两个关键取舍:
- Editor 必须用
source: 'db'而非'code'——code 模式会拉起 FilesystemStore 并尝试mkdir一个mastra/editor目录,在 Vercel 只读的 serverless 文件系统上会抛 ENOENT 并让所有 API 路由 504;db模式把编辑器数据留在共享内存 store 里,随冷启动一起重置。 - 种子调用是
void seedStudioPreview(),故意不 await——写入是同步且极快的,这样种子永远不会阻塞服务启动。
种子演示数据:确定性、免调用、24 小时窗口内
启动时应用会向共享内存 store 写入一套共享演示数据,让评审人无需手动创建任何东西即可预览 Studio 中数据密集的页面。按 README 的清单:
- Threads——预览 Agent 的几个带消息的聊天线程(Agent 聊天页侧边栏);
- Traces——带 model 与 tool span 的 Agent 运行(Observability 页面);
- Metrics——token 用量、模型成本、agent/tool 延迟、活跃线程/资源,全部落在默认 24 小时窗口内(对应 Model Usage & Cost、Token usage by agent、Traces volume、Latency、Memory 卡片);
- Scores——两个确定性 scorer(
answer-relevance、tone-quality)的分数行与聚合; - Datasets——两个带条目的数据集。
这套数据“确定且免费产生”——不发起模型调用,种子本身不需要任何 provider key。
种子写入的实现细节
seed.ts 的seedStudioPreview有三个工程特征:
- 进程内幂等:种子 Promise 被 memoize,重复调用只执行一次;
- 域间隔离:memory / observability / scores / datasets 四个域各自 try/catch,一个域失败不影响其他域写入;
- 写入路径与 Studio 查询路径一致:直接调用
storage.getStore('memory' | 'observability' | 'scores' | 'datasets')的saveThread、saveMessages、batchCreateSpans、batchCreateMetrics、saveScore、createDataset、batchInsertItems等真实存储 API。
seed-data.ts 的头部注释解释了数据构造策略:
- 所有时间戳相对
now(冷启动时刻)计算,保证永远落在 Studio 默认指标窗口的最近 24 小时内; - 无随机数——同样的
now产生同样的数据,预览可复现; - 指标名称与列 key 精确镜像 Studio 各指标卡片的查询方式,因此表格能直接渲染出内容。
示例数据中还包括固定的模型目录(gpt-4o-mini、gpt-4o及其 per-1M token 美元费率)和几个虚构的调用方会话(web-session-anita、api-key-acme等),用来填充 Memory 的“top resources / threads”表格。
为什么“不持久”是刻意为之
因为 store 是内存型的,它不持久:每次冷启动各自进程重新种子化。演示数据因此永远存在,但预览会话中实时创建的内容可能不会跨 serverless 实例存活。README 强调这一点“对预览场景是有意为之”——评审者要的是“打开就有数据”,不是真实状态。
两个 scorer 的实现(preview-scorers.ts)也贯彻“免费且确定”的原则:
export const answerRelevanceScorer = createScorer({ id: 'answer-relevance', type: 'agent', }).generateScore(() => 0.9); export const toneQualityScorer = createScorer({ id: 'tone-quality', type: 'agent', }).generateScore(() => 0.82);固定分数替代 LLM judge,因此无论种子还是实时 Agent 运行,打分都不产生额外模型调用。
本地使用
README 给出的本地命令是从仓库根目录执行(该应用是独立 workspace root,所以用--dir进入):
pnpm --dir packages/playground/vercel-preview install --frozen-lockfile pnpm --dir packages/playground/vercel-preview build本地 Studio 开发则先复制环境变量模板再启动 dev:
cp packages/playground/vercel-preview/.env.example packages/playground/vercel-preview/.env pnpm --dir packages/playground/vercel-preview dev模板 .env.example 的内容:
OPENAI_API_KEY= # ANTHROPIC_API_KEY= # MASTRA_PREVIEW_MODEL=__GATEWAY_OPENAI_MODEL_BASE__对照 package.json 的脚本可以看到dev/build都会先执行build:linked-workspace-deps(即 scripts/build-linked-workspace-deps.mjs),再执行mastra:build/mastra:dev——后者实际调用的是仓库内packages/cli/dist/index.js的build/dev子命令。这意味着本地运行前需要先构建好 monorepo 里的 CLI 产物。
Vercel 项目配置与环境变量
为整个仓库创建一个 Vercel 项目并指向该应用。README 特别提示:如果项目早于本次从examples/迁出,需要把 Root Directory 设置从examples/studio-preview更新为packages/playground/vercel-preview,否则迁移前创建的分支预览会在 rebase 前持续失败。
配置项如下:
- Root Directory:
packages/playground/vercel-preview - Build Command:
pnpm build - Install Command:
pnpm install --frozen-lockfile - Output Directory:留空
- Node.js Version:22.x
- Root Directory 设置:允许使用 root 目录之外的源文件
仓库的 vercel.json 与上述一致,并额外在构建命令前注入了环境变量:
{ "installCommand": "pnpm install --frozen-lockfile", "buildCommand": "MASTRA_AGENT_SIGNALS=false pnpm build" }预览部署策略方面,README 建议在 Vercel 项目中把预览部署限定为“仅 PR 生成”;由于仓库本身不包含分支 allowlist 或生产跳过脚本,生产部署行为应在 Vercel 项目设置中控制。
Preview 部署需要配置以下环境变量:
OPENAI_API_KEY=...也可以配置 Anthropic:
ANTHROPIC_API_KEY=...若两者同时配置,Studio 的模型控件会同时展示这两个已连接 provider。
模型选择逻辑:MASTRA_PREVIEW_MODEL 与回退链
README 说明预览 Agent 默认优先 OpenAI(若已配置),否则回退 Anthropic;也可用MASTRAs_PREVIEW_MODEL(源码中为MASTRA_PREVIEW_MODEL)覆盖默认模型,取值为占位 token(如__GATEWAY_ANTHROPIC_MODEL_SONNET__)或具体provider/modelID。
studio-preview-agent.ts 给出了完整解析链:
const PREVIEW_MODEL_TOKENS: Record<string, string> = { __GATEWAY_OPENAI_MODEL_BASE__: 'openai/gpt-5', __GATEWAY_ANTHROPIC_MODEL_SONNET__: 'anthropic/claude-sonnet-4-6', }; function resolvePreviewModel() { if (process.env.MASTRA_PREVIEW_MODEL) { return PREVIEW_MODEL_TOKENS[process.env.MASTRA_PREVIEW_MODEL] ?? process.env.MASTRA_PREVIEW_MODEL; } if (process.env.OPENAI_API_KEY) return PREVIEW_MODEL_TOKENS.__GATEWAY_OPENAI_MODEL_BASE__; if (process.env.ANTHROPIC_API_KEY) return PREVIEW_MODEL_TOKENS.__GATEWAY_ANTHROPIC_MODEL_SONNET__; return PREVIEW_MODEL_TOKENS.__GATEWAY_OPENAI_MODEL_BASE__; }即:显式设置的MASTRA_PREVIEW_MODEL(占位 token 或provider/model)> 有OPENAI_API_KEY时用openai/gpt-5> 有ANTHROPIC_API_KEY时用anthropic/claude-sonnet-4-6> 兜底仍为 OpenAI 默认模型。注释解释了 token 常量为何本地硬编码而非从 docs 导入:导入 docs 会把其未安装的 tsconfig 拖进 deployer 分析。
链接依赖与构建链:预览永远跑当前分支的代码
README 中最有深度的一段说明了为什么预览不会用到任何“发布版本”的 Mastra 包:package.json 中所有用到的 Mastra 包都是link:依赖——
"dependencies": { "@mastra/core": "link:../../../packages/core", "@mastra/deployer-vercel": "link:../../../deployers/vercel", "@mastra/editor": "link:../../../packages/editor", "@mastra/memory": "link:../../../packages/memory", "hono": "^4.12.34", "zod": "^4.4.3" }, "devDependencies": { "mastra": "link:../../../packages/cli", "turbo": "^2.9.12", ... }因此预览永远运行当前分支的代码,也不存在“发布版本 pin 漂移出 peer 依赖范围”的问题。
build/dev前置的build:linked-workspace-deps步骤由 build-linked-workspace-deps.mjs 实现,它解决“turbo 远端缓存 miss”时的构建问题:
- 读取仓库根
package.json的packageManager字段,取出 pnpm 版本号; - 在仓库根用该 pnpm 版本执行
install --frozen-lockfile,按--filter <name>...安装五个链接包(mastra、@mastra/deployer-vercel、@mastra/core、@mastra/memory、@mastra/editor)的完整依赖图; - 调用应用自己 node_modules 里 pin 死的 turbo(注释说明:脚本必须在脱离
pnpm run、.bin不在 PATH 的场景下也能工作)在仓库根执行build --concurrency=2,只构建这五个链接包——低并发是为把峰值内存控制在 Vercel 预览构建器的限额内。
脚本注释点明了触发场景:远端缓存 miss = turbo 会真正构建链接包,此时必须先把根工具链装好。最终 Vercel 只部署该应用生成的产物,而不是整个仓库。
构建完成后,Vercel 使用生成的.vercel/output文件夹,路由约定为:
- Studio 前端服务在
/; - Mastra API 服务在
/api/*之下(preview-status工具的检查清单也佐证了这一点,如GET /api/agents)。
推荐预览 URL 清单与安全注意
README 给出了一份验收用的推荐预览 URL 清单,评审 PR 时可逐项打开:
| URL | 预览内容 |
|---|---|
/ | Studio 外壳 |
/agents | Agent 列表 |
/agents/studio-preview-agent/chat/new | 可用的 Agent 聊天(侧边栏带种子线程) |
/observability | 种子化的 traces |
/metrics | 种子化的用量、成本、延迟与内存指标 |
/scorers | 种子化的 scorers 与 scores |
/datasets | 种子化的数据集与条目 |
安全方面,README 的最后一条建议:在广泛公开预览之前,用 Vercel Deployment Protection 或 Studio auth 保护该项目——因为 Studio 可以访问 Mastra server 暴露的全部 agents、tools 和 workflows。
小结
Studio Preview 应用展示了 Mastra 一套可借鉴的“框架自举”实践:用pnpm-workspace.yaml把内部工具隔离成独立 workspace root;用InMemoryStore+ 进程内幂等种子换取 serverless 场景下的零外部依赖;用link:依赖 + 前置依赖图安装脚本保证预览代码与当前分支严格一致;用preview-status工具、确定性 scorer 与 24 小时窗口内的种子数据构成一套无需模型调用即可验收的 PR 预览清单。对照 README、vercel.json 与 src/mastra 目录 下的源码,即可完整复现这套预览基础设施。
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考