使用 OpenUI
OpenUI 是生成式 UI 的开放标准。它将紧凑的流式优先语言(OpenUI Lang)与 React Runtime 和内置组件库相结合,使模型输出能在流式传输过程中渲染为结构化 UI。
OpenUI 通过 AG-UI 协议连接到 Mastra。@ag-ui/mastra 适配器会封装 Mastra Agent 并发出 AG-UI 事件,再由 OpenUI 的 agUIAdapter() 在客户端解析。
完整的可运行示例请参阅 OpenUI 仓库中的 mastra-chat 示例。
集成指南集成指南的直接链接
将 Mastra 嵌入 Next.js API 路由,并通过 AG-UI 协议将 OpenUI <AgentInterface /> 聊天界面连接到该路由。
搭建新的 OpenUI 应用:
- npm
- pnpm
- Yarn
- Bun
npx @openuidev/cli@latest create --name openui-mastra-chatpnpm dlx @openuidev/cli@latest create --name openui-mastra-chatyarn dlx @openuidev/cli@latest create --name openui-mastra-chatbun x @openuidev/cli@latest create --name openui-mastra-chat进入新创建的项目目录:
cd openui-mastra-chat搭建出的应用是一个具有如下结构的 Next.js 项目:
openui-mastra-chat└── src├── app│ ├── api│ │ └── chat│ │ └── route.ts│ ├── globals.css│ ├── layout.tsx│ └── page.tsx├── generated│ └── system-prompt.txt└── library.ts聊天路由位于
src/app/api/chat/route.ts,聊天界面位于src/app/page.tsx,组件库位于src/library.ts。OpenUI CLI 会根据组件库写入src/generated/system-prompt.txt;每当组件库发生变化时,都要重新生成该文件。将 OpenAI Key 添加到
.env.local:.env.localOPENAI_API_KEY=sk-...备注OpenUI 需要模型 Provider Key。你可以使用 Mastra 支持的任意 Provider,并在下一步中相应调整 Agent 配置。
安装 Mastra 包和适用于 Mastra 的 AG-UI 适配器:
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/core @ag-ui/mastra @ag-ui/core zodpnpm add @mastra/core @ag-ui/mastra @ag-ui/core zodyarn add @mastra/core @ag-ui/mastra @ag-ui/core zodbun add @mastra/core @ag-ui/mastra @ag-ui/core zod@ag-ui/mastra将 MastraAgent封装在MastraAgent中,由后者发出 AG-UI 协议事件。OpenUI 的agUIAdapter()在客户端使用这些事件。打开
src/app/api/chat/route.ts。使用@mastra/core/tools中的createTool定义 Agent 所需的 Tool:src/app/api/chat/route.tsimport { createTool } from '@mastra/core/tools'import { z } from 'zod'const getWeather = createTool({id: 'get_weather',description: 'Get current weather for a city.',inputSchema: z.object({ location: z.string().describe('City name') }),execute: async ({ location }) => {return { location, temperature_celsius: 22, condition: 'Clear' }},})使用
MastraAgent封装 MastraAgent。注入生成的系统提示词,使 Agent 知道如何使用 OpenUI 组件库:src/app/api/chat/route.tsimport { MastraAgent } from '@ag-ui/mastra'import { Agent } from '@mastra/core/agent'import { readFileSync } from 'fs'import { join } from 'path'const systemPrompt = readFileSync(join(process.cwd(), 'src/generated/system-prompt.txt'), 'utf-8')const agent = new MastraAgent({agent: new Agent({id: 'openui-agent',name: 'OpenUI Agent',instructions: `You are a helpful assistant. Use tools when relevant.\n\n${systemPrompt}`,model: {id: 'openai/gpt-5.6-sol',apiKey: process.env.OPENAI_API_KEY,},tools: { getWeather },}),resourceId: 'chat-user',})导出一个
POSThandler,将 Agent 的 AG-UI 事件作为 Server-Sent Events(SSE)进行流式传输:src/app/api/chat/route.tsimport type { Message } from '@ag-ui/core'import { NextRequest } from 'next/server'export async function POST(req: NextRequest) {const { messages, threadId }: { messages: Message[]; threadId: string } = await req.json()const encoder = new TextEncoder()const stream = new ReadableStream({start(controller) {const subscription = agent.run({ messages, threadId, runId: crypto.randomUUID(), tools: [], context: [] }).subscribe({next: event => {controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`))},complete: () => {controller.enqueue(encoder.encode('data: [DONE]\n\n'))controller.close()},error: error => {controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: error.message })}\n\n`),)controller.close()},})req.signal.addEventListener('abort', () => subscription.unsubscribe())},})return new Response(stream, {headers: {'Content-Type': 'text/event-stream','Cache-Control': 'no-cache, no-transform',Connection: 'keep-alive',},})}将 OpenUI
<AgentInterface />聊天界面连接到该路由。使用fetchLLM()构建llm适配器,并将streamAdapter设置为agUIAdapter(),以便 OpenUI 解析 AG-UI 事件。src/app/page.tsx'use client'import '@openuidev/react-ui/components.css'import { AgentInterface, agUIAdapter, fetchLLM } from '@openuidev/react-ui'import { openuiChatLibrary } from '@openuidev/react-ui/genui-lib'const llm = fetchLLM({url: '/api/chat',streamAdapter: agUIAdapter(),})export default function Page() {return (<div className="relative h-screen w-screen overflow-hidden"><AgentInterface llm={llm} componentLibrary={openuiChatLibrary} /></div>)}componentLibraryprop 控制模型可以生成哪些组件。将openuiChatLibrary替换为你自己的库,以限制或扩展输出。启动开发 Server:
- npm
- pnpm
- Yarn
- Bun
npm run devpnpm run devyarn devbun run dev打开 http://localhost:3000。现在,你可以通过 OpenUI 聊天界面与 Mastra Agent 聊天;随着模型进行流式传输,结构化 UI 会逐步渲染。
使用 AG-UI 进行流式传输使用 AG-UI 进行流式传输的直接链接
OpenUI 使用 AG-UI 协议,这是一种与传输方式无关的 AI Agent 类型化事件流。@ag-ui/mastra 将 Mastra Agent 转换为该协议:
- Server 调用
agent.run({ messages, threadId, runId, ... }),并将每个发出的事件序列化为 SSE 消息。 - 客户端将
fetchLLM({ streamAdapter: agUIAdapter() })传给<AgentInterface />,后者把 SSE 流解析为驱动 OpenUI Lang 渲染的内部事件。
threadId 将跨请求的对话关联起来,runId 则标识单次执行。请为每个请求生成新的 runId,并在客户端持久化 threadId。
组件库组件库的直接链接
OpenUI 根据组件库生成 UI。组件库定义可用组件、组件的 props,以及如何指示模型使用这些组件。
内置库内置库的直接链接
@openuidev/react-ui 提供两个可以直接使用的库:
openuiChatLibrary:用于聊天界面的组件(卡片、表单、表格、图表)。openuiDashboardLibrary:用于仪表盘和数据密集型界面的组件。
将库传给 <AgentInterface componentLibrary={...} />,使其中的组件可供模型使用。
自定义组件库自定义组件库的直接链接
如需限制或扩展输出,请在 src/library.ts 中定义自己的库,并导出一部分组件。将该库传给 <AgentInterface />,并在组件库发生变化时重新生成系统提示词:
- npm
- pnpm
- Yarn
- Bun
npx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
pnpm dlx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
yarn dlx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
bun x @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
API 路由会读取生成的提示词,并将其合并到 Agent 的 instructions 中,使 Agent 准确了解可以输出哪些组件。