將 Mastra 整合至你的 Next.js 項目
本指南會帶你使用 Mastra 建立一個可呼叫 Tool 的 AI Agent,然後在路由中直接匯入並呼叫該 Agent,將它連接至 Next.js。
你會使用 AI SDK UI 和 AI Elements,建立美觀且具互動性的聊天體驗。
建立一個 Mastra + Next.js 項目。請完全依照本指南操作: https://mastra.ai/guides/getting-started/next-js.md
開始前,逐一提出以下問題。除非已經取得答案,否則請等候回覆:
- 項目名稱?(預設:"my-nextjs-agent")
- Provider?(預設:"openai",選項:"openai"、"anthropic"、"groq"、"google"、"cerebras"、"mistral")
- 已經有 Next.js 應用程式?(預設:"no")
Provider 規則:
- 獲允許的 Provider -> 使用該 Provider。
- 任何其他值 -> 使用 "openai"。
如果是新應用程式:執行 npx create-next-app@latest <project-name> --yes --ts --eslint --tailwind --src-dir --app --turbopack --no-react-compiler --no-import-alias
在「初始化 Mastra」步驟中,不要執行指南內的互動式命令。請改為執行:cd <project-name> && npx mastra@latest init --default --llm <provider>
然後完成指南中的每個步驟。完全照抄指南內的程式碼,不要自行修改。
開始之前開始之前 的直接連結
- 你需要取得受支援模型 Provider 的 API 金鑰。如果沒有偏好,請使用 OpenAI。
- 安裝 Node.js
v22.13.0或以上版本
建立新的 Next.js 應用程式(可選)建立新的 Next.js 應用程式(可選) 的直接連結
如果你已經有 Next.js 應用程式,請跳至下一步。
執行以下命令以建立新的 Next.js 應用程式:
- npm
- pnpm
- Yarn
- Bun
npx create-next-app@latest my-nextjs-agent --yes --ts --eslint --tailwind --src-dir --app --turbopack --no-react-compiler --no-import-alias
pnpm dlx create-next-app@latest my-nextjs-agent --yes --ts --eslint --tailwind --src-dir --app --turbopack --no-react-compiler --no-import-alias
yarn dlx create-next-app@latest my-nextjs-agent --yes --ts --eslint --tailwind --src-dir --app --turbopack --no-react-compiler --no-import-alias
bun x create-next-app@latest my-nextjs-agent --yes --ts --eslint --tailwind --src-dir --app --turbopack --no-react-compiler --no-import-alias
這會建立名為 my-nextjs-agent 的項目,你亦可以換成任何想要的名稱。
初始化 Mastra初始化 Mastra 的直接連結
前往你的 Next.js 項目:
cd my-nextjs-agent
執行 mastra init。系統提示時,選擇 Provider(例如 OpenAI)並輸入你的金鑰:
- npm
- pnpm
- Yarn
- Bun
npx mastra@latest init
pnpm dlx mastra@latest init
yarn dlx mastra@latest init
bun x mastra@latest init
這會建立 src/mastra 資料夾,當中包含一個天氣 Agent 範例和以下檔案:
index.ts- Mastra 設定,包括記憶體tools/weather-tool.ts- 擷取指定地點天氣的 Toolagents/weather-agent.ts- 使用該 Tool 的天氣 Agent,內含提示詞
接下來的步驟會從 Next.js 路由呼叫 weather-agent.ts。
如果你想在 Next.js 應用程式旁同時執行 Studio,並讓兩者共用同一個資料庫,請更新 src/mastra/index.ts 內的儲存空間 URL,改用絕對路徑:
url: 'file:/absolute/path/to/your/project/mastra.db'
相對路徑會按各程序的工作目錄解析,而 next dev 與 mastra dev 的工作目錄並不相同。
安裝 AI SDK UI 和 AI Elements安裝 AI SDK UI 和 AI Elements 的直接連結
安裝 AI SDK UI 和 Mastra 配接器:
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/ai-sdk@latest @ai-sdk/react ai
pnpm add @mastra/ai-sdk@latest @ai-sdk/react ai
yarn add @mastra/ai-sdk@latest @ai-sdk/react ai
bun add @mastra/ai-sdk@latest @ai-sdk/react ai
接着初始化 AI Elements。系統提示時,選擇預設選項:
- npm
- pnpm
- Yarn
- Bun
npx ai-elements@latest
pnpm dlx ai-elements@latest
yarn dlx ai-elements@latest
bun x ai-elements@latest
這會將整個 AI Elements UI 元件庫下載至 @/components/ai-elements 資料夾。
建立聊天路由建立聊天路由 的直接連結
建立 src/app/api/chat/route.ts:
import { handleChatStream } from '@mastra/ai-sdk'
import { toAISdkV5Messages } from '@mastra/ai-sdk/ui'
import { createUIMessageStreamResponse } from 'ai'
import { mastra } from '@/mastra'
import { NextResponse } from 'next/server'
const THREAD_ID = 'example-user-id'
const RESOURCE_ID = 'weather-chat'
export async function POST(req: Request) {
const params = await req.json()
const stream = await handleChatStream({
mastra,
agentId: 'weather-agent',
params: {
...params,
memory: {
...params.memory,
thread: THREAD_ID,
resource: RESOURCE_ID,
},
},
})
return createUIMessageStreamResponse({ stream })
}
export async function GET() {
const memory = await mastra.getAgentById('weather-agent').getMemory()
let response = null
try {
response = await memory?.recall({
threadId: THREAD_ID,
resourceId: RESOURCE_ID,
})
} catch {
console.log('No previous messages found.')
}
const uiMessages = toAISdkV5Messages(response?.messages || [])
return NextResponse.json(uiMessages)
}
POST 路由會接收提示詞,並以 AI SDK 格式串流傳回 Agent 的回應;GET 路由則會從記憶體擷取訊息記錄,讓用戶端重新載入時可以還原 UI 狀態。
建立聊天頁面建立聊天頁面 的直接連結
建立 src/app/chat/page.tsx:
'use client'
import '@/app/globals.css'
import { useEffect, useState } from 'react'
import { DefaultChatTransport, ToolUIPart } from 'ai'
import { useChat } from '@ai-sdk/react'
import {
PromptInput,
PromptInputBody,
PromptInputTextarea,
} from '@/components/ai-elements/prompt-input'
import {
Conversation,
ConversationContent,
ConversationScrollButton,
} from '@/components/ai-elements/conversation'
import { Message, MessageContent, MessageResponse } from '@/components/ai-elements/message'
import { Tool, ToolHeader, ToolContent, ToolInput, ToolOutput } from '@/components/ai-elements/tool'
function Chat() {
const [input, setInput] = useState<string>('')
const { messages, setMessages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat',
}),
})
useEffect(() => {
const fetchMessages = async () => {
const res = await fetch('/api/chat')
const data = await res.json()
setMessages([...data])
}
fetchMessages()
}, [setMessages])
const handleSubmit = async () => {
if (!input.trim()) return
sendMessage({ text: input })
setInput('')
}
return (
<div className="relative size-full h-screen w-full p-6">
<div className="flex h-full flex-col">
<Conversation className="h-full">
<ConversationContent>
{messages.map(message => (
<div key={message.id}>
{message.parts?.map((part, i) => {
if (part.type === 'text') {
return (
<Message key={`${message.id}-${i}`} from={message.role}>
<MessageContent>
<MessageResponse>{part.text}</MessageResponse>
</MessageContent>
</Message>
)
}
if (part.type?.startsWith('tool-')) {
return (
<Tool key={`${message.id}-${i}`}>
<ToolHeader
type={(part as ToolUIPart).type}
state={(part as ToolUIPart).state || 'output-available'}
className="cursor-pointer"
/>
<ToolContent>
<ToolInput input={(part as ToolUIPart).input || {}} />
<ToolOutput
output={(part as ToolUIPart).output}
errorText={(part as ToolUIPart).errorText}
/>
</ToolContent>
</Tool>
)
}
return null
})}
</div>
))}
<ConversationScrollButton />
</ConversationContent>
</Conversation>
<PromptInput onSubmit={handleSubmit} className="mt-20">
<PromptInputBody>
<PromptInputTextarea
onChange={e => setInput(e.target.value)}
className="md:leading-10"
value={input}
placeholder="Type your message..."
disabled={status !== 'ready'}
/>
</PromptInputBody>
</PromptInput>
</div>
</div>
)
}
export default Chat
此元件會將 useChat() 連接至 api/chat 端點,把提示詞傳送至該端點,並以分段串流方式傳回回應。
它會使用 <MessageResponse> 元件顯示回應文字,並以 <Tool> 元件顯示任何 Tool 呼叫。
測試你的 Agent測試你的 Agent 的直接連結
- 使用
npm run dev執行 Next.js 應用程式 - 在 http://localhost:3000/chat 開啟聊天頁面
- 嘗試查問天氣。如果 API 金鑰設定正確,你便會收到回應
下一步下一步 的直接連結
恭喜你使用 Next.js 建立了 Mastra Agent!🎉
接下來,你可以使用自己的 Tool 和邏輯擴充項目:
準備好後,可進一步了解 Mastra 如何與 AI SDK UI 和 Next.js 整合,以及如何將 Agent 部署至包括 Vercel 在內的任何地方: