使用 OpenUI
OpenUI 是生成式 UI 的開放標準。它結合精簡、以串流為先的語言(OpenUI Lang)、React 執行環境和內置元件庫,讓模型輸出可在串流期間呈現為結構化 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 API 金鑰加入
.env.local:.env.localOPENAI_API_KEY=sk-...備註OpenUI 需要模型 Provider 的 API 金鑰。你可以使用 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封裝在會發出 AG-UI 協定事件的MastraAgent中。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' }},})將 Mastra
Agent封裝在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',})匯出
POST處理常式,以 Server-Sent Events (SSE) 串流傳送 Agent 的 AG-UI 事件: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>)}componentLibrary屬性控制模型可產生哪些元件。你可以把openuiChatLibrary換成自己的元件庫,以限制或擴充輸出。啟動開發伺服器:
- 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 轉換成此協定:
- 伺服器會呼叫
agent.run({ messages, threadId, runId, ... }),並將每個發出的事件序列化為 SSE 訊息。 - 用戶端會將
fetchLLM({ streamAdapter: agUIAdapter() })傳遞至<AgentInterface />,由後者把 SSE 串流解析成驅動 OpenUI Lang 呈現的內部事件。
threadId 會把跨請求的對話連繫起來,而 runId 則識別單次執行。請為每個請求產生新的 runId,並在用戶端保存 threadId。
元件庫元件庫 的直接連結
OpenUI 會根據元件庫產生 UI。元件庫定義可使用的元件、其屬性,以及如何指示模型使用這些元件。
內置元件庫內置元件庫 的直接連結
@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 確切知道可以發出哪些元件。