前 10 篇的 Agent 都活在 mastra dev 里:改代码热重载,Studio 里点一点就能验证。可 Agent 迟早要见真实用户——挂到公网、接上前端、扛住流量,这一步在框架教程里往往是空白。Python 版 Agent 系列第 29 篇讲过那边的部署运维,换到 TypeScript 阵营,问题换了一副面孔:Node 进程怎么守护、Docker 镜像怎么打、Serverless 能不能直接上,答案都带着 TS 生态自己的印记。
先给结论:Mastra 的生产形态是 mastra build 打出的一个自包含 Hono 服务器——一个目录、一份 node_modules,拷到任何装着 Node 的机器上 node index.mjs 就能跑。本文按"服务形态 → 构建产物 → 进程守护 → Docker 化 → 前端 API → Serverless 取舍 → 密钥管理 → 总结"组织,版本事实基于 2026 年 10 月官方文档逐一核实。
1、服务形态总览
第 1 篇核实过:Mastra 的服务端底座是 Hono。落到部署上,mastra build 会为你的 Mastra 实例生成一整套 REST 端点——每个 Agent 自动获得生成回复、流式输出、读写会话一组接口,Studio 的 playground 也由同一个服务器托管。这套自动生成的 API 面向通用客户端,联调够用,但直接暴露到公网有两个硬伤:默认没有鉴权,路径与业务语义也对不上。
所以生产形态有两条路。路线 A:直接部署生成的服务器,鉴权与限流交给网关层(Nginx、API 网关)做;路线 B:自己包一层 Hono,把 Mastra 实例嵌进去,鉴权、流式格式、路由语义全部自己定义——官方参考里为这种场景留了 MastraServer 适配器抽象,Hono 与 Express 之外还能扩展其他框架。整体形态如下:
图里最关键的分界线是中间那层 Node 常驻进程:Serverless 平台打不破这层(第 6 节展开),而存储落在哪里决定了能不能水平扩容(第 4 节展开)。官方对运行时要求宽松,Node.js、Bun、Deno 都支持,Node 建议 22.13 及以上;产物可以落到任意 VM、容器或 PaaS 平台,不绑定特定云厂商,细节见部署总览。
注意:自动生成的端点默认无鉴权。哪怕只是测试环境,也别把 4111 端口直接暴露到公网。
2、构建与运行
开发态用 mastra dev(热重载、贴着 Studio),生产换成 mastra build:把 src/mastra 下的 agents、workflows、tools 连同依赖一起打成 Hono 服务器。产物结构节选如下:
.mastra/output/
├── index.mjs # Hono 服务器入口,node 直接运行它
├── mastra.mjs # 你的 Mastra 实例(agents / workflows)
├── tools.mjs # 工具注册表
├── package.json # 依赖清单
├── node_modules/ # 自带依赖
├── public/
└── playground/ # Studio 界面(可选打包)
两个要点。其一,产物自包含:output 目录带了自己的 node_modules,整个目录拷到目标机即可运行,不需要重新 npm install。其二,index.mjs 本身就是可独立运行的 Hono 服务器,启动只要一条命令:
npx mastra build # 打包,产物在 .mastra/output/
npx mastra start # 官方启动器,自动读 .env.production / .env
node .mastra/output/index.mjs # 或不依赖 CLI,直接用 node 启动
mastra start 与裸 node 的差别在细节:前者会优先加载 .env.production 再兜底 .env,并统一处理进程信号;后者胜在零依赖,适合塞进极简容器。端口用 PORT 环境变量控制(默认 4111),也可以在 Mastra 配置的 server: { port } 里构建期写死,见服务器部署文档。
优雅退出是内置的:收到 SIGINT 或 SIGTERM,进程先排空在途请求再退出,宽限期 drainTimeout 默认只有 5 秒——Agent 请求动辄几十秒,建议像 server: { drainTimeout: 240_000 } 这样调大。等不及的话再发一次信号会立即强杀,部署脚本里"停不住就补一刀"是安全的。想让 Studio 跟服务一起上线,构建时加 --studio 即可,命令细节可查 CLI 参考。
3、进程守护
裸起的 node 进程挂了就没了,生产必须配守护。TS 生态两条主流路:pm2 与 systemd。
3.1、pm2 守护
pm2 是 Node 圈的事实标准:进程崩溃自动拉起、内存超限自动重启、日志管理、多实例 cluster 一把梭。推荐用配置文件而非命令行参数,跟着代码进仓库:
module.exports = {
apps: [
{
name: 'mastra-api',
script: '.mastra/output/index.mjs', // 直接跑构建产物
env: { NODE_ENV: 'production', PORT: 4111 },
max_memory_restart: '512M', // 内存超限自动重启
instances: 1, // LibSQL 文件存储别开多实例
},
],
}
pm2 start ecosystem.config.js 起服务,pm2 logs mastra-api 看日志,pm2 save && pm2 startup 做开机自启。注释里那句提醒是存储耦合问题:LibSQL 是嵌入式文件库(第 5 篇),多个进程写同一个文件会锁冲突——要么单实例,要么把 storage 换成 Postgres 再谈扩容。这也是为什么配置里 instances 明确写 1 而不是 "max":cluster 模式开出来的每个副本都会抢同一个 mastra.db 文件,症状是随机报错与记忆丢失,非常难排查。
3.2、systemd 守护
只有一台服务器、不想多装任何东西,systemd 是零依赖方案——Linux 发行版自带,一个 unit 文件解决:
[Unit]
Description=Mastra API Server
After=network.target
[Service]
User=mastra
WorkingDirectory=/srv/mastra
ExecStart=/usr/bin/node .mastra/output/index.mjs
Environment=PORT=4111
EnvironmentFile=/etc/mastra/env # 密钥集中放这里,权限 600
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
systemctl enable --now mastra 启用,日志走 journalctl -u mastra -f,不需要额外配置日志轮转。怎么选:多语言项目混布、要用 cluster 吃满多核,选 pm2;追求最少依赖、运维只认系统标准工具,选 systemd。两者效果等价——挂了拉起、开机自启、日志可查。
4、Docker 化
容器化的价值在可复制:镜像锁死 Node 版本与依赖,从测试机到云主机行为一致。产物自包含让 Dockerfile 可以写得很薄——多阶段构建,构建阶段跑 mastra build,运行阶段只带走 output:
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx mastra build # 产物在 .mastra/output/
FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production PORT=4111
COPY --from=build /app/.mastra/output ./
VOLUME /app/data # LibSQL 数据文件落这里
EXPOSE 4111
CMD ["node", "index.mjs"]
镜像里刻意不放任何密钥文件,.dockerignore 至少排除三样:.env、node_modules、.mastra——前一个是密钥泄漏,后两个是让构建阶段自己生成,避免把本机旧产物带进镜像。启动时挂卷、注入密钥:docker run -d -p 4111:4111 -v mastra-data:/app/data -e ANTHROPIC_API_KEY=... mastra-api。
LibSQL 场景务必把数据库文件指到 /app/data——在 mastra/index.ts 里让 LibSQLStore 的 url 读 DATABASE_URL 环境变量,容器里传 file:/app/data/mastra.db。落在容器可写层的话,容器一删、记忆清零。用 Postgres 反而更省心:不挂卷,DATABASE_URL 换成连接串即可,存储与容器生命周期天然解耦,也是后面扩多实例的前提。
5、前端 API 设计
自动生成的端点是"框架视角":路径带 agentId、入参是标准消息体,适合通用客户端联调。给真实前端用,建议按"业务视角"自己包一层(第 1 节路线 B):鉴权中间件挡在最外层,路由里绑定会话线程,流式响应用 SSE。核心实现:
import { Hono } from 'hono'
import { mastra } from './mastra/index'
export const app = new Hono()
// Bearer 鉴权:没带 key 或 key 不对,一律 401
app.use('/api/*', async (c, next) => {
const token = c.req.header('Authorization')
if (token !== `Bearer ${process.env.API_KEY}`) {
return c.json({ error: 'unauthorized' }, 401)
}
await next()
})
// 流式对话:threadId 由前端生成并在每次请求带上
app.post('/api/chat', async (c) => {
const { threadId, message } = await c.req.json()
const agent = mastra.getAgent('ragAgent')
const result = agent.stream(message, {
threadId, // 同一 threadId = 同一段多轮记忆
resourceId: 'app-user', // 用户 / 租户级隔离
})
return result.toTextStreamResponse() // SSE 流,前端边收边渲染
})
三个设计点。其一,threadId 就是会话管理的全部:第 5 篇讲过,Mastra 的 memory 挂在线程上,前端首条消息生成一个 UUID 存本地,之后每轮带上,服务端保持零状态、多轮记忆自动续接。其二,toTextStreamResponse() 把 Agent 输出直接转成 SSE 响应;要更细的事件粒度(工具调用开始与结束),改用 UIMessage 流,或自己遍历 fullStream 组装事件。其三,示例里的 Bearer 是演示级,生产应换成 JWT 或网关层鉴权——官方 2026 年发布了 @mastra/core/auth 插拔式鉴权组件,要把鉴权做进生成的服务器时可以直接复用。
还有个部署侧的坑要提前踩:SSE 经过 Nginx 反代时默认会被缓冲,表现是前端收不到逐字流、憋到最后一次性吐完。给这层路由加 proxy_buffering off;(或让响应头带 X-Accel-Buffering: no),流式才真正逐块到达。函数平台同理,不少网关对流式响应有自己的缓冲策略,上线前用 curl 实测一遍首字延迟。
6、Serverless 取舍
Serverless 对 Agent 服务诱惑不小:免运维、按量付费、自动缩容。但长任务 Agent 与函数模型天生不合,三个硬约束先看清,时长上限是第一个:
| 平台 | 时长限制 | 对 Agent 的含义 |
|---|---|---|
| AWS Lambda | 单次调用最长 15 分钟 | 多步工具循环容易被掐断 |
| Vercel Functions | maxDuration 最高 800 秒 |
比 Lambda 更紧,长回复有风险 |
| Cloudflare Workers | 墙上时钟不限,CPU 时间默认 30 秒、可调高 | 等 LLM 响应不算 CPU,但重计算会撞墙 |
冷启动是第二重税:Node 依赖树加载,加上你的工具代码与知识库索引,冷启动从几百毫秒到数秒不等,交互式 Agent 的首字延迟直接翻倍。第三重是无状态:函数的文件系统是临时的,本地 LibSQL 文件根本不成立,storage 必须整体换成 Postgres 这类外部服务。Workers 的具体限额以官方限制文档为准。
Python 系列第 29 篇的结论在 TS 侧原样成立:短任务可以上,长 Agent 别硬塞。单轮问答、一次检索增强回答、批量 embedding 这类秒级任务,Vercel 与 Cloudflare 都合适,Mastra 也内置了这两家的 deployer 支持一键发布。反过来,几十步的 workflow、human-in-the-loop、长时间 SSE 连接,请回到第 3、4 节的常驻进程加容器路线;要弹性伸缩,Kubernetes 上还有官方 Helm Chart。真有长任务又想享受弹性,正路是改架构——队列加常驻 worker,或用工作流引擎做步进恢复——而不是指望函数平台放宽时限。
经验法则:一次调用撑不过 1 分钟的才考虑 Serverless;要挂长连接、要长记忆、要跑几十步的,直接常驻。
7、密钥与环境管理
开发期一切密钥在 .env:模型 API key、存储连接串、自设的 API_KEY。生产的第一条纪律是密钥只经环境变量注入,具体三条规矩:
.env进.gitignore与.dockerignore,仓库与镜像里都不出现- 服务器上密钥文件权限收到 600,用
mastra start时靠.env.production加载 - 容器与云平台用各自的 secret 机制:
docker run -e、systemd 的EnvironmentFile、云厂商 secret 管理服务
按环境拆 key 是低成本高收益的动作:开发、预发、生产各一套模型 key,泄漏时影响面小,轮换也不用全量停机。镜像不含密钥还有个连带好处:制品仓库可以放心共享,密钥只在编排层注入——compose 的 env_file、Kubernetes 的 Secret、云平台的 secret 管理各归其位。最后一条日志纪律:别指望平台兜底——你代码里 console.log 出去的明文 key,日志采集会原样带走。
8、总结
回顾全文路线:形态上,Mastra 生产端是 mastra build 打出的自包含 Hono 服务器,默认 4111 端口,直接部署或自己包一层 Hono 皆可;运行上,pm2 与 systemd 二选一守护,Docker 多阶段构建十几行搞定,存储用 LibSQL 要挂卷、用 Postgres 只需连接串;接口上,鉴权中间件加 threadId 会话加 SSE 流式,是给前端的最小完备组合;Serverless 只留给短任务,长 Agent 老实常驻;密钥只经环境变量注入,按环境隔离与轮换。
练习(承接第 10 篇的 RAG Agent):
- 本地跑
npx mastra build,用node .mastra/output/index.mjs起服务,curl 打通一个端点 - 写出第 4 节的 Dockerfile,挂数据卷启动,验证重启容器后 thread 记忆仍在
- 加分项:把 storage 换成 Postgres 连接串重跑,体会存储外置后多实例才可行
对于已经用 Mastra 写完 Agent 的团队,建议本周就把 build → Docker → 守护这条链路走通——它不改任何业务代码,却是从 demo 到产品的最后一块板子。

