第 17 章 · 集成 React 与 Next.js
本章目标:把 Mastra Agent 接入 React/Next.js 应用:API 路由暴露流式接口,前端实现打字机效果对话 UI。
17.1 架构总览
text
React 组件 ──fetch──▶ Next.js API Route ──▶ Mastra Agent
▲ │ │
└────── SSE 流式渲染 ◀───┴──────────────────┘Mastra 不绑定特定前端库——你可以用 Vercel AI SDK 的 useChat、CopilotKit,或直接消费 Mastra Client SDK。
17.2 Next.js API 路由
typescript
// app/api/chat/route.ts(App Router)
import { mastra } from '@/mastra'
import { createUIMessageStreamResponse } from 'ai'
export async function POST(req: Request) {
const { messages, threadId, resourceId } = await req.json()
const agent = mastra.getAgent('support')
// streamVNext 输出与 AI SDK 兼容的 UI 消息流
const stream = await agent.streamVNext(messages, {
format: 'aisdk',
memory: {
resource: resourceId, // 用户标识
thread: threadId, // 会话标识
},
})
return createUIMessageStreamResponse({ stream: stream.toUIMessageStream() })
}17.3 前端 useChat 对接
tsx
// app/page.tsx
'use client'
import { useChat } from '@ai-sdk/react'
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, status } = useChat({
api: '/api/chat',
// 携带会话信息以便服务端记忆
body: { resourceId: 'user-123', threadId: 'thread-a' },
})
return (
<div className="chat">
{messages.map((m) => (
<div key={m.id} className={m.role}>
{/* 流式时 content 增量到达,天然打字机效果 */}
{m.parts.map((p, i) =>
p.type === 'text' ? <span key={i}>{p.text}</span> : null,
)}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={status !== 'ready'} />
<button type="submit" disabled={status !== 'ready'}>发送</button>
</form>
</div>
)
}17.4 工具调用可视化
AI SDK 消息的 parts 里包含工具事件,可渲染"正在查询订单…"这类中间状态:
tsx
{m.parts.map((p, i) => {
if (p.type === 'tool-queryOrder') {
return p.state === 'output-available'
? <Tag key={i}>✅ 已查到订单</Tag>
: <Tag key={i}>⏳ 正在查询订单…</Tag>
}
if (p.type === 'text') return <span key={i}>{p.text}</span>
return null
})}17.5 其他集成路径
- Mastra Client SDK——
@mastra/client-js直接从浏览器调用部署好的 Mastra server,无需自建路由; - CopilotKit——把 Mastra agent 注册为 Copilot 后端,获得现成聊天侧边栏与人工接管能力;
- 任意框架——只要能发 fetch 并读 SSE,Vue/Svelte 同样适用。
CopilotKit 快速接入
若想要现成的聊天侧边栏与人工接管能力:
tsx
// app/layout.tsx —— 包一层 Provider 即可
'use client'
import { CopilotKit } from '@copilotkit/react-core'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<CopilotKit runtimeUrl="/api/copilotkit">
{/* runtimeUrl 指向桥接 Mastra agent 的服务端路由 */}
{children}
</CopilotKit>
)
}本章小结
本章小结
- 服务端用
streamVNext({ format: 'aisdk' })输出 AI SDK 兼容流; - 前端
useChat+body透传 resource/thread 即可获得带记忆的多轮对话; - 工具调用以消息 parts 形式下发,可用于展示执行状态;
- 浏览器直连可选 Mastra Client SDK 或 CopilotKit。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. streamVNext 的 format: "aisdk" 选项的作用是?
2. useChat 中 body 参数的作用是?
3. 前端如何得知工具已执行完毕?
4. 不想自建 Next.js API 路由时,浏览器直连 Mastra 的推荐方式是?
🛠️ 动手实践
- 完成 Next.js 示例并接入第 10 章的工具,让页面显示"正在查询订单…"中间态。
- 用两个浏览器标签模拟两个用户,验证 resource 隔离后互不串话。
- 把 API 路由换成 Mastra Client SDK 直连方案,对比两种方式的代码量。