在你的 Astro 项目中集成 Mastra
🌐 Integrate Mastra in your Astro project
在本指南中,你将使用 Mastra 构建一个调用工具的 AI 代理,然后通过从你的路由中直接导入和调用该代理,将其连接到 Astro。
🌐 In this guide, you'll build a tool-calling AI agent using Mastra, then connect it to Astro by importing and calling the agent directly from your routes.
你将使用 AI SDK UI 和 AI Elements 来创建一个美观且互动的聊天体验。
🌐 You'll use AI SDK UI and AI Elements to create a beautiful, interactive chat experience.
虽然本指南向你展示了如何将 Astro 与 React 以及完整的服务器端渲染 (SSR) 一起使用,但还有许多方法可以将 Astro 与 Mastra 一起使用。你可以在每个文件的基础上选择启用 SSR,并使用其他框架,如 Svelte、Vue、Solid 或 Preact。你可以使用 Astro 构建聊天界面,并在 Astro 中原生调用端点。
🌐 While this guide shows you how to use Astro with React and full server-side rendering (SSR), there are many ways to use Astro with Mastra. You can opt-in to SSR on a per-file basis and use other frameworks like Svelte, Vue, Solid, or Preact. You can use Astro to build out a chat interface and call endpoints natively in Astro.
在你开始之前Direct link to 在你开始之前
🌐 Before you begin
创建一个新的 Astro 应用(可选)Direct link to 创建一个新的 Astro 应用(可选)
🌐 Create a new Astro app (optional)
如果你已经有一个 Astro 应用,请跳到下一步。你的 Astro 应用应如下设置:
🌐 If you already have an Astro app, skip to the next step. Your Astro app should be setup like this:
- 使用 SSR(在
astro.config.mjs中的output: "server") - 使用 React 集成
- Tailwind 已安装
为了支持按需渲染,本指南将使用Node.js 适配器,但任何受支持的服务器适配器都可以使用。
🌐 To support on-demand rendering this guide will use the Node.js adapter but any of the supported server adapters will work.
- npm
- pnpm
- Yarn
- Bun
npm create astro@latest mastra-astro -- --add node --add react --add tailwind --install --skip-houston --template minimal --git
pnpm create astro mastra-astro --add node --add react --add tailwind --install --skip-houston --template minimal --git
yarn create astro mastra-astro --add node --add react --add tailwind --install --skip-houston --template minimal --git
bunx create-astro mastra-astro --add node --add react --add tailwind --install --skip-houston --template minimal --git
这会创建一个名为 mastra-astro 的项目,但你可以用你想要的任何名字替代它。
🌐 This creates a project called mastra-astro, but you can replace it with any name you want.
将 cd 添加到你的项目中,并编辑 astro.config.mjs 文件,将 output 设置 设置为 "server":
// @ts-check
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
import react from '@astrojs/react';
import tailwindcss from '@tailwindcss/vite';
// https://astro.build/config
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone'
}),
integrations: [react()],
vite: {
plugins: [tailwindcss()]
}
});
最后,编辑 tsconfig.json 来解决路径:
🌐 Lastly, edit the tsconfig.json to resolve paths:
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
// ...
}
}
初始化 MastraDirect link to 初始化 Mastra
🌐 Initialize Mastra
运行 mastra init。出现提示时,选择一个提供商(例如 OpenAI)并输入你的密钥:
🌐 Run mastra init. When prompted, choose a provider (e.g. OpenAI) and enter your key:
- 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 文件夹:
🌐 This creates a src/mastra folder with an example weather agent and the following files:
index.ts- Mastra 配置,包括内存tools/weather-tool.ts- 一个用于获取给定位置天气的工具agents/weather-agent.ts——一个使用该工具的天气代理和提示
在接下来的步骤中,你将从你的 Astro 路由中调用 weather-agent.ts。
🌐 You'll call weather-agent.ts from your Astro routes in the next steps.
安装 AI SDK UI 和 AI 元素Direct link to 安装 AI SDK UI 和 AI 元素
🌐 Install AI SDK UI & AI Elements
安装 AI SDK 界面以及 Mastra 适配器:
🌐 Install AI SDK UI along with the Mastra adapter:
- 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 元素。出现提示时,选择默认选项:
🌐 Next, initialize AI Elements. When prompted, choose the default options:
- 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 用户界面组件库下载到一个 @/components/ai-elements 文件夹中。
🌐 This downloads the entire AI Elements UI component library into a @/components/ai-elements folder.
创建聊天路线Direct link to 创建聊天路线
🌐 Create a chat route
创建 src/pages/api/chat.ts:
🌐 Create src/pages/api/chat.ts:
import type { APIRoute } from "astro";
import { handleChatStream } from '@mastra/ai-sdk';
import { toAISdkV5Messages } from '@mastra/ai-sdk/ui'
import { createUIMessageStreamResponse } from 'ai';
import { mastra } from '@/mastra';
const THREAD_ID = 'example-user-id';
const RESOURCE_ID = 'weather-chat';
export const POST: APIRoute = async ({ request }) => {
const params = await request.json();
const stream = await handleChatStream({
mastra,
agentId: 'weather-agent',
params: {
...params,
memory: {
...params.memory,
thread: THREAD_ID,
resource: RESOURCE_ID,
}
}
})
return createUIMessageStreamResponse({ stream })
}
export const GET: APIRoute = async () => {
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 Response.json(uiMessages)
}
POST 路由接受一个提示并以 AI SDK 格式流式返回代理的响应,而 GET 路由则从内存中获取消息历史,以便在客户端重新加载时能够恢复 UI。
🌐 The POST route accepts a prompt and streams the agent's response back in AI SDK format, while the GET route fetches message history from memory so the UI can be hydrated when the client reloads.
创建聊天组件Direct link to 创建聊天组件
🌐 Create a chat component
创建 src/components/chat.tsx:
🌐 Create src/components/chat.tsx:
import '@/styles/global.css';
import { useEffect, useState } from 'react';
import { DefaultChatTransport, type 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="w-full p-6 relative size-full h-screen">
<div className="flex flex-col h-full">
<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 端点,将提示发送到那里,并将响应分块回传。
🌐 This component connects useChat() to the api/chat endpoint, sending prompts there and streaming the response back in chunks.
它使用 <MessageResponse> 组件呈现响应文本,并使用 <Tool> 组件显示任何工具调用。
🌐 It renders the response text using the <MessageResponse> component, and shows any tool invocations with the <Tool> component.
渲染聊天组件Direct link to 渲染聊天组件
🌐 Render the chat component
最后一步是在你的索引页面上渲染聊天组件。编辑 src/pages/index.astro:
🌐 The last step is to render the chat component on your index page. Edit src/pages/index.astro:
---
import Chat from '@/components/chat';
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<Chat client:load />
</body>
</html>
导入 Chat 组件,并使用 client:load 指令 将其添加到主体中,以便在客户端运行。
🌐 Import the Chat component and add it to the body with the client:load directive so it runs on the client side.
测试你的代理Direct link to 测试你的代理
🌐 Test your agent
- 使用
npm run dev运行你的 Astro 应用 - 在 http://localhost:4321 打开聊天
- 试着询问天气。如果你的 API 密钥设置正确,你将会收到回复
下一步Direct link to 下一步
🌐 Next steps
祝贺你使用 Astro 构建你的 Mastra 代理!🎉
🌐 Congratulations on building your Mastra agent with Astro! 🎉
从这里,你可以使用你自己的工具和逻辑来扩展项目:
🌐 From here, you can extend the project with your own tools and logic:
准备好后,阅读更多关于 Mastra 如何与 AI SDK 用户界面集成以及如何将你的代理部署到任何地方的信息:
🌐 When you're ready, read more about how Mastra integrates with AI SDK UI and how to deploy your agent anywhere: