Mastra @mastra/ai-sdk 实战:把 Agent、Workflow 与 Agent 网络输出为 AI SDK 兼容的 UI 流
2026/9/14 20:23:20 网站建设 项目流程

Mastra @mastra/ai-sdk 实战:把 Agent、Workflow 与 Agent 网络输出为 AI SDK 兼容的 UI 流

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

@mastra/ai-sdk是 Mastra 官方推荐的与 Vercel AI SDK 集成的方式:它通过注册自定义 API 路由,把 Mastra 的 Agent、Workflow 和 Agent 网络执行结果,以 AI SDK UI 兼容的 SSE 流格式返回给前端。读完本文,你将掌握三条路由处理器(chatRouteworkflowRoutenetworkRoute)的完整参数与默认值、脱离 Mastra 内置服务器使用框架无关处理器(handleChatStream等)的方法,以及 SSE 心跳保活、流平滑、withMastra记忆中间件和./ui浏览器端消息转换等配套能力,并能在源码层面理解这些功能背后的实现。

包定位与环境要求

Mastra 仓库中该包的 README(client-sdks/ai-sdk/README.md)明确写道:将 Mastra 与 AI SDK 一起使用的推荐方式就是安装@mastra/ai-sdk包,它提供自定义 API 路由与工具,用于以 AI SDK 兼容格式流式传输 Mastra 的 Agent,包括聊天、Workflow 与网络路由处理器,以及面向 UI 集成的工具与导出类型。

从 client-sdks/ai-sdk/package.json 可以确认运行环境约束:

  • 安装:npm install @mastra/ai-sdk
  • 要求 Node.js>= 22.13.0
  • peerDependencies@mastra/core >=1.5.0-0 <2.0.0-0zod ^3.25.0 || ^4.0.0,也就是说项目必须已安装 Mastra 核心且 zod 版本受兼容区间约束;
  • 包导出两个入口:主入口@mastra/ai-sdk(路由与流工具)和子路径@mastra/ai-sdk/ui(浏览器安全的消息转换,不含任何 Node 流工具,见 src/ui.ts);
  • 当前仓库中的包版本为1.10.3-alpha.1,版本历史见 client-sdks/ai-sdk/CHANGELOG.md。

路由注册总览:三种 apiRoutes

README 给出的最简用法是在Mastra实例的server.apiRoutes中注册chatRoute,并通过:agentId路径参数实现动态 Agent 路由:

import { chatRoute } from '@mastra/ai-sdk'; export const mastra = new Mastra({ server: { apiRoutes: [ chatRoute({ path: '/chat/:agentId', }), ], }, });

chatRoute外,主入口 src/index.ts 还导出workflowRoutenetworkRoute,三者共同覆盖 Mastra 的三类可执行对象:

路由默认路径固定 ID 参数底层调用适用场景
chatRoute/chat/:agentIdagentagent.stream()/agent.resumeStream()单 Agent 多轮对话
workflowRoute/api/workflows/:workflowId/streamworkflowworkflow.createRun()+run.stream()/run.resumeStream()流式执行并可视化 Workflow 步骤
networkRoute/network/:agentIdagentagent.network()路由 Agent 将任务委派给其他 Agent 的多 Agent 网络

三者共享同一套约定:路径中必须包含:agentId/:workflowId参数,或者显式传入固定的agent/workflowID;若同时提供路径参数与固定 ID,处理器会记录警告且固定 ID 优先(见 src/chat-route.ts#L682-L688)。路由通过@mastra/coreregisterApiRoute注册为 HTTP POST 端点,并自带 OpenAPI 描述,因此会出现在 Mastra 服务器的 API 文档中。

chatRoute:完整参数、请求体与版本选择

chatRoute是最常用的路由。以下参数说明整理自 src/chat-route.ts 中chatRouteOptions类型定义与 JSDoc(约 L456-L529):

参数默认值说明
path/chat/:agentId路由路径;包含:agentId时动态路由
agent-不使用动态路由时固定的 Agent ID
defaultOptions-传给 Agent 执行的默认选项(AgentExecutionOptions,如maxStepsrequestContextproviderOptionsstructuredOutput
experimentalTransform-转换为 AI SDK UI 块前应用到 Mastra 流上的实验性 transform(见“流平滑”一节)
versionv5AI SDK UI 消息流版本:v5|v6|v7
agentVersion-Agent 版本选项,类型直接派生自Mastra.getAgentById的第二参数,保证与核心自动同步
sendStarttrue是否发送start事件
sendFinishtrue是否发送finish事件
sendReasoningfalse是否包含推理步骤
sendSourcesfalse是否包含引用来源
heartbeatMs-SSE 心跳目标间隔;<= 0关闭;NaN、正无穷或超过 2,147,483,647 抛RangeError
onError默认序列化器自定义错误序列化函数;缺省时默认序列化器会剥离敏感字段(如APICallError.requestBodyValues,其中包含系统提示词)
messageMetadata-附加到 AI SDK 流start/finish消息块的元数据映射函数

一个结合固定 Agent 与默认选项的完整示例:

chatRoute({ path: '/api/support-chat', agent: 'support-agent', defaultOptions: { maxSteps: 5, }, version: 'v7', sendReasoning: true, heartbeatMs: 15000, });

请求体与查询参数

根据源码中内嵌的 OpenAPI 定义,请求体为 JSON,messages为必填:

{ "messages": [ { "role": "user", "content": "你好" } ], "resumeData": { }, "runId": "xxx" }
  • messages数组中的消息遵循{ role: 'user' | 'assistant' | 'system', content: string }形态(AI SDKUIMessage结构由前端useChat等钩子产生);
  • resumeData用于恢复挂起的 Agent 执行(例如工具审批后的恢复),提供resumeData时必须同时提供runId,否则handleChatStream直接抛错(src/chat-route.ts#L297-L299);
  • 查询参数支持versionId(指定 Agent 版本 ID)与statusdraftpublished),二者互斥,status取值非法或两者同传都会抛错(src/chat-route.ts#L708-L724)。

内部执行链路

从源码结构看,chatRoute的 handler 依次做以下几件事(src/chat-route.ts#L671-L768):

  1. 解析请求体,确定 Agent ID(固定agent优先于路径参数);
  2. 合并requestContext,优先级为中间件上下文 > 路由defaultOptions> 请求体,多处同时提供时记录警告;
  3. c.req.raw.signal作为abortSignal注入参数,使客户端断开能中止 Agent 执行;
  4. 调用handleChatStream生成 UI 消息流,再用对应版本的createUIMessageStreamResponse包装为 HTTP 响应;
  5. 最后经withSseHeartbeat包装(见“SSE 心跳保活”一节)后返回。

handleChatStream内部还有两个值得了解的细节:

  • 重新生成(regenerate):当trigger === 'regenerate-message'且最后一条消息是 assistant 消息时,该消息会被剔除后再交给模型,从而生成全新回复;最后一条 assistant 消息的 ID 会被记录为lastMessageId,随start块下发,帮助前端识别响应归属(src/chat-route.ts#L330-L345)。
  • v6/v7 原生工具审批恢复:AI SDK v6/v7 会把用户对工具调用的审批回应重新提交在 assistant 消息的工具块上。extractV6NativeApprovals会扫描所有 assistant 消息中state === 'approval-responded'的工具块,按runId:toolCallId复合键去重,然后streamV6ApprovalResumes按请求顺序逐个调用agent.resumeStream恢复执行;对AGENT_RESUME_TOOL_CALL_NOT_SUSPENDEDAGENT_RESUME_NO_SNAPSHOT_FOUND两类“目标已解析”错误容错跳过,只有当所有目标都无法恢复时才抛出类型化错误(src/chat-route.ts#L35-L179)。该行为由端到端测试tool-call-approval.e2e.test.ts与录制文件验证。
  • 编辑器存储覆盖:当 Mastra 配置了 editor 时,Agent 的运行时配置(指令、工具、模型等)可能存放在存储配置而非代码定义中,handleChatStream会调用editorAgent.applyStoredOverrides解析,显式agentVersion优先,否则默认取published版本,与内置 Agent 处理器行为对齐(src/chat-route.ts#L306-L324)。

workflowRoute:步骤级流式可视化

workflowRoute的选项类型见 src/workflow-route.ts#L171-L178:path(默认/api/workflows/:workflowId/stream)、固定workflowversionv5|v6|v7,默认v5)、includeTextStreamParts(默认true,是否包含文本流块)、sendReasoningsendSources(后两者默认false)。

其请求体字段比聊天路由更丰富(WorkflowStreamHandlerParams):

  • runId/resourceId:运行标识;resourceId优先取requestContext中的MASTRA_RESOURCE_ID_KEY,其次取请求体;
  • inputData/initialState:Workflow 输入与初始状态;
  • resumeData:从挂起点恢复运行;
  • requestContexttracingOptionsstep

执行链路是:mastra.getWorkflowById(workflowId)找到 Workflow 后,createRun({ runId, resourceId })建立运行,然后二选一——有resumeData时走run.resumeStream({ resumeData }),否则run.stream({ inputData, initialState })(src/workflow-route.ts#L114-L123)。由于每一步的输入/输出/挂起状态都会实时下发,前端可以做出步骤级的进度 UI。

networkRoute:多 Agent 网络的流式入口

networkRoute的选项为path(默认/network/:agentId)、固定agentdefaultOptionsNetworkOptions)、versionagentVersion(src/network-route.ts#L173-L187)。处理器调用agentObj.network(messages, { ...defaultOptions, ...rest })执行网络(src/network-route.ts#L104-L124)。其 OpenAPI 请求体在messages之外还接受requestContextrunIdmaxStepsthreadIdresourceIdmodelSettingstools等字段,即标准的 Agent 执行选项。

框架无关处理器:handleChatStream / handleWorkflowStream / handleNetworkStream

三条路由之外,包还导出对应的handleChatStreamhandleWorkflowStreamhandleNetworkStream。这三个函数不依赖 Hono 或 Mastra 的apiRoutes,适合在非内置服务器(例如 Next.js App Router 的 Route Handler)中直接调用。JSDoc 中给出的 Next.js 示例:

// Next.js App Router import { handleChatStream } from '@mastra/ai-sdk'; import { createUIMessageStreamResponse } from 'ai'; import { mastra } from '@/src/mastra'; export async function POST(req: Request) { const params = await req.json(); const stream = await handleChatStream({ mastra, agentId: 'weatherAgent', params, }); return createUIMessageStreamResponse({ stream }); }

handleWorkflowStreamhandleNetworkStream的用法同构,只需替换workflowIdparams。三者均提供按version重载的类型签名(v5为可选、v6/v7必须显式传),返回的流可以直接交给对应 AI SDK 版本的createUIMessageStreamResponse

流转换机制:toAISdkStream 与 data part 类型

@mastra/ai-sdk的核心工作在“Mastra 流 → AI SDK UI 流”的转换上,主入口导出toAISdkStream(三版本统一入口)与toAISdkV5Stream(v5 专用别名),实现在 src/convert-streams.ts。除 AI SDK 标准文本/工具/推理块外,Mastra 还通过data part把执行结构下发给前端,对应导出类型定义在 src/transformers.ts:

  • AgentAgentDataParttype: 'data-tool-agent')携带整个运行的快照AgentRunSnapshot(含stepsusagefinishReason,并扩展了toolErrors);AgentStepDataPart'data-tool-agent-step')携带单步详情。transformer 按runId缓冲增量(text-deltatool-call-deltareasoning-deltasourcefile等),把流式增量累积为全量快照再下发,因此前端任意时刻拿到的都是自洽的完整状态;
  • WorkflowWorkflowDataPart'data-workflow',嵌套场景为'data-tool-workflow')包含运行状态与steps: Record<string, StepResult>WorkflowStepDataPart'data-workflow-step')以${runId}:${stepId}为 ID 下发单步的完整StepResult(含inputoutputsuspendPayloadresumePayload);
  • NetworkNetworkDataPart'data-network'/'data-tool-network')包含status: 'running' | 'finished'、各步骤数组、usageoutput
  • 此外object-result块会转换为data-structured-output,用于结构化输出场景。

从源码结构看,Agent transformer 还处理了两个易错点:其一是 processors 可能在首个模型步骤之前轮换响应消息 ID,transformer 会“扣留”start块直到首个step-start,确保广播的 ID 与实际持久化 ID 一致;其二是 tripwire(处理器主动中止),若发生 tripwire 且未收到finish事件,transformer 会在流结束时补发finishReason: 'other'finish块,保证前端流状态机闭合(src/transformers.ts#L496-L548)。

SSE 心跳保活:heartbeatMs 与 withSseHeartbeat

长时挂起或慢推理场景下,中间代理常常关闭空闲连接。chatRouteheartbeatMs参数配合 src/sse-heartbeat.ts 中的withSseHeartbeat解决这一问题:它在源流空闲期间周期性插入: heartbeat\n\n这种 SSE 注释帧,既不改变数据语义又能维持连接。

实现上有几个关键约束,值得在调参时了解:

  • 心跳只插入在完整 SSE 帧边界(LF-LF 换行对)之间,拆帧期间心跳暂停等待剩余字节(src/sse-heartbeat.ts#L61-L69);
  • 已缓冲的源数据、完成信号与错误永远优先于心跳,数据不会因心跳被延迟;
  • heartbeatMs省略、<= 0或响应无 body 时原样返回;NaN、正无穷或超过2_147_483_647assertValidHeartbeatMsRangeError(src/sse-heartbeat.ts#L9-L17)。chat-route-heartbeat.test.ts对这套行为有专门测试。

流平滑:smoothStream 与 experimentalTransform

smoothStream是一个标记为实验性的 API,它把 Mastra 的文本与推理块整理为“一致、有延迟”的输出块,改善打字机式渲染的观感(src/smooth-stream.ts)。它实际上是@mastra/core/streamcreateSmoothStream的工厂封装:

import { smoothStream } from '@mastra/ai-sdk'; chatRoute({ path: '/chat/:agentId', experimentalTransform: smoothStream(), });

从实现看,MastraStreamTransformOptions可以是单个 transform 工厂或工厂数组;applyMastraStreamTransformspipeThrough把每个工厂产生的TransformStream依次串联在原始流与 AI SDK 转换之间(src/smooth-stream.ts#L27-L37)。注释特别提示:工厂可跨请求复用,而TransformStream实例只能消费一次——所以导出的是工厂而非实例。该参数同时出现在chatRoutedefaultOptions与顶层选项中,experimentalTransform名称本身也表明 API 可能变化,生产使用前建议跟进 CHANGELOG。

withMastra:给任意 AI SDK 模型接入 Mastra 记忆与处理器

除了路由,主入口还导出withMastracreateProcessorMiddleware(实现见 src/middleware.ts)。它们把 Mastra 的处理器(processors)与记忆能力包装到任意 AI SDK 语言模型上,使你在不经过 Mastra Agent 的情况下(例如直接generateText)也能拥有会话记忆:

import { openai } from '@ai-sdk/openai'; import { withMastra } from '@mastra/ai-sdk'; import { LibSQLStore } from '@mastra/libsql'; const storage = new LibSQLStore({ url: 'file:memory.db' }); await storage.init(); const model = withMastra(openai('gpt-4o'), { memory: { storage, threadId: 'thread-123', resourceId: 'user-456', lastMessages: 10, semanticRecall: { vector: pinecone, embedder: openai.embedding('text-embedding-3-small'), topK: 5, messageRange: 2, }, workingMemory: { enabled: true, template: '# User Profile\n- **Name**:\n- **Preferences**:', }, }, inputProcessors: [myInputProcessor], outputProcessors: [myOutputProcessor], });

WithMastraMemoryOptions的关键字段(src/middleware.ts#L68-L83):storageMemoryStorage适配器,必填)、threadId(必填)、resourceIdlastMessages(取最近 N 条,false禁用)、semanticRecall(需额外提供vector向量库与embedder,索引名默认memory_messages)、workingMemory(启用后字符串template会被包装为 markdown 模板)。

从源码结构看,withMastra按配置自动装配处理器:workingMemory启用时创建WorkingMemory输入处理器;lastMessages不为false时创建MessageHistory(同时作为输入与输出处理器);配置semanticRecall时创建SemanticRecall(RAG 式召回)。所有处理器最终经由createProcessorMiddleware注入 AI SDK 的wrapLanguageModel中间件,函数同时支持 v2(LanguageModelV2)与 v3(LanguageModelV3)规格的模型。

另一值得注意的机制是tripwire:处理器在processInput/processOutputStream中调用abort(reason)会抛出内部TripWire,中间件把该状态经providerOptions.mastraProcessors传递(保证并发请求间状态隔离),wrapGenerate/wrapStream检测到后返回一条包含阻断理由的“阻塞流”而非真正调用模型——这为内容过滤、策略拦截等场景提供了标准做法。createProcessorMiddleware则是面向需要精细控制的低层 API,JSDoc 明确建议一般场景直接使用withMastra

./ui 子路径:浏览器端消息转换

@mastra/ai-sdk/ui子路径(src/ui.ts)只导出消息转换函数,刻意保持浏览器安全(不含 Node 流工具):

  • toAISdkMessages:将 Mastra 存储的消息转换为当前 AI SDK 版本的UIMessage
  • toAISdkV5Messages/toAISdkV4Messages:面向特定 AI SDK 大版本的显式转换。

典型用途是前端加载历史会话:从 Mastra 存储读出的数据库消息经toAISdkMessages转换后,可以直接喂给 AI SDK 的useChat等组件,与流式响应的消息结构保持一致。

测试覆盖与相关路径

这个包的测试目录能反映其能力边界,均位于 client-sdks/ai-sdk/src/testschat-route-v7.test.ts(v7 流行为)、chat-route-heartbeat.test.ts(心跳)、resume-stream.test.ts(挂起恢复)、smooth-stream.test.tstransformers.test.tstransform-agent-cumulative-growth.test.ts(累积快照)、tool-call-approval.e2e.test.ts(带录制的端到端审批恢复,录制文件见recordings)等。本地验证可运行pnpm --filter @mastra/ai-sdk test(包的scripts.testvitest run)。

版本与使用边界

结合当前仓库内容,使用时需注意:

  • version参数支持v5/v6/v7三档 AI SDK UI 消息流,默认v5v6/v7在运行时会共享 v6 的转换器并在边界处重新定型(源码注释说明 v7 UI 块在运行时与 v6 结构一致);
  • 主入口保留了弃用导出toAISdkFormat(src/index.ts#L27-L28),新代码应使用toAISdkStream
  • smoothStreamexperimentalTransform属实验性 API,可能在未来版本变化;
  • 路由的 OpenAPI 描述、错误约定(400 校验失败 / 404 Agent 未找到)均来自源码内嵌定义,可直接用于对接前端错误处理;
  • 所有行为以上述当前仓库源码为准:包版本1.10.3-alpha.1,peer 依赖锁定@mastra/core >=1.5.0-0 <2.0.0-0,Node 引擎要求>=22.13.0

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询