Vercel AI Chatbot 模板教學|2025 快速建立聊天機器人
想建立一個像 ChatGPT 一樣的聊天介面?
Vercel 官方提供了 AI Chatbot 模板。
開箱即用,功能完整,只要設定 API Key 就能部署。
這篇文章教你如何使用和客製化這個模板。
什麼是 AI Chatbot 模板?
Vercel AI Chatbot 是一個開源的聊天機器人模板。
內建功能
| 功能 | 說明 |
|---|---|
| 多輪對話 | 記住上下文,連續對話 |
| 串流回應 | 即時顯示 AI 回覆 |
| Markdown 渲染 | 支援程式碼、表格等格式 |
| 程式碼高亮 | 自動語法高亮 |
| 對話歷史 | 儲存和載入歷史對話 |
| 使用者認證 | 內建登入系統 |
| 深色模式 | 支援淺色/深色主題 |
| 響應式設計 | 手機和桌面都適用 |
技術架構
- 框架: Next.js 14(App Router)
- 樣式: Tailwind CSS
- 元件: shadcn/ui
- AI: Vercel AI SDK
- 認證: NextAuth.js
- 資料庫: 可選(Vercel KV、PostgreSQL)
GitHub 倉庫
快速開始
方法一:一鍵部署
最快的方式是使用 Vercel 的部署按鈕:
- 前往 github.com/vercel/ai-chatbot
- 點擊「Deploy」按鈕
- 設定環境變數
- 完成部署
方法二:Clone 專案
# Clone 專案
git clone https://github.com/vercel/ai-chatbot.git
cd ai-chatbot
# 安裝依賴
pnpm install
# 複製環境變數範例
cp .env.example .env.local
設定環境變數
編輯 .env.local:
# OpenAI API Key(必要)
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
# NextAuth 設定(必要)
AUTH_SECRET=your-random-secret-key
# 可選:GitHub OAuth
AUTH_GITHUB_ID=your-github-oauth-id
AUTH_GITHUB_SECRET=your-github-oauth-secret
# 可選:Vercel KV(用於儲存對話歷史)
KV_URL=your-kv-url
KV_REST_API_URL=your-kv-rest-url
KV_REST_API_TOKEN=your-kv-token
KV_REST_API_READ_ONLY_TOKEN=your-kv-read-only-token
執行開發伺服器
pnpm dev
打開 http://localhost:3000,就能看到聊天介面了。
模板結構解析
專案結構
ai-chatbot/
├── app/ # Next.js App Router
│ ├── (chat)/ # 聊天相關頁面
│ │ ├── page.tsx # 主聊天頁面
│ │ └── chat/[id]/ # 特定對話頁面
│ ├── api/ # API Routes
│ │ ├── chat/ # 聊天 API
│ │ └── auth/ # 認證 API
│ └── layout.tsx # 根 Layout
├── components/ # UI 元件
│ ├── chat.tsx # 聊天元件
│ ├── message.tsx # 訊息元件
│ └── sidebar.tsx # 側邊欄
├── lib/ # 工具函數
│ ├── ai/ # AI 相關
│ └── auth/ # 認證相關
└── public/ # 靜態資源
核心元件
Chat 元件(主要聊天介面):
// components/chat.tsx
export function Chat({ id, initialMessages }) {
const { messages, input, handleSubmit, handleInputChange } = useChat({
id,
initialMessages,
});
return (
<div className="flex flex-col h-full">
<ChatMessages messages={messages} />
<ChatInput
input={input}
onInputChange={handleInputChange}
onSubmit={handleSubmit}
/>
</div>
);
}
API Route(處理聊天請求):
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
});
return result.toDataStreamResponse();
}
客製化指南
修改 AI 模型
// app/api/chat/route.ts
import { anthropic } from '@ai-sdk/anthropic';
const result = await streamText({
// 改用 Claude
model: anthropic('claude-3-opus-20240229'),
messages,
});
自訂 System Prompt
// app/api/chat/route.ts
const result = await streamText({
model: openai('gpt-4-turbo'),
system: `你是一個專業的技術支援助理。
規則:
1. 使用繁體中文回答
2. 回答要簡潔明瞭
3. 如果是程式問題,提供程式碼範例
4. 不確定的事情不要亂說`,
messages,
});
修改主題顏色
/* app/globals.css */
:root {
--primary: 220 90% 50%;
--primary-foreground: 0 0% 100%;
}
.dark {
--primary: 220 90% 60%;
--primary-foreground: 0 0% 100%;
}
修改 Logo
// components/header.tsx
import Image from 'next/image';
export function Header() {
return (
<header>
<Image
src="/your-logo.png"
alt="Logo"
width={120}
height={40}
/>
</header>
);
}
移除認證(公開使用)
如果不需要登入功能:
// app/(chat)/page.tsx
// 移除 auth 檢查
export default async function Page() {
// const session = await auth();
// if (!session) redirect('/login');
return <Chat />;
}
加入自訂功能
加入歡迎訊息
// components/chat.tsx
const { messages } = useChat({
initialMessages: [
{
id: 'welcome',
role: 'assistant',
content: '您好!我是您的 AI 助理,有什麼我可以幫忙的嗎?',
},
],
});
加入快速問題按鈕
// components/suggested-questions.tsx
const suggestions = [
'如何開始使用?',
'價格方案有哪些?',
'如何聯繫客服?',
];
export function SuggestedQuestions({ onSelect }) {
return (
<div className="flex gap-2 flex-wrap">
{suggestions.map((q) => (
<button
key={q}
onClick={() => onSelect(q)}
className="px-3 py-1 bg-slate-100 rounded-full text-sm"
>
{q}
</button>
))}
</div>
);
}
加入打字指示器
// components/typing-indicator.tsx
export function TypingIndicator() {
return (
<div className="flex items-center gap-1 p-2">
<div className="w-2 h-2 bg-slate-400 rounded-full animate-bounce" />
<div className="w-2 h-2 bg-slate-400 rounded-full animate-bounce delay-100" />
<div className="w-2 h-2 bg-slate-400 rounded-full animate-bounce delay-200" />
</div>
);
}
加入訊息評分
// components/message-feedback.tsx
export function MessageFeedback({ messageId, onFeedback }) {
return (
<div className="flex gap-2 mt-2">
<button
onClick={() => onFeedback(messageId, 'good')}
className="text-slate-400 hover:text-green-500"
>
👍
</button>
<button
onClick={() => onFeedback(messageId, 'bad')}
className="text-slate-400 hover:text-red-500"
>
👎
</button>
</div>
);
}
儲存對話歷史
使用 Vercel KV
模板內建支援 Vercel KV:
- 在 Vercel Dashboard 建立 KV 資料庫
- 連接到專案
- 環境變數會自動設定
// lib/chat.ts
import { kv } from '@vercel/kv';
export async function saveChat(id: string, messages: Message[]) {
await kv.set(`chat:${id}`, messages);
}
export async function getChat(id: string) {
return await kv.get(`chat:${id}`);
}
使用其他資料庫
// lib/chat.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export async function saveChat(userId: string, messages: Message[]) {
await prisma.chat.create({
data: {
userId,
messages: JSON.stringify(messages),
},
});
}
部署到 Vercel
設定環境變數
- 進入 Vercel Dashboard
- 選擇專案 → Settings → Environment Variables
- 加入必要的環境變數:
-OPENAI_API_KEY
-AUTH_SECRET
- 其他選用的變數
部署
# 使用 Git
git push origin main
# Vercel 自動部署
# 或使用 CLI
vercel
驗證部署
- 打開部署的網址
- 測試聊天功能
- 確認串流回應正常
效能優化
減少冷啟動
// 使用 Edge Runtime
export const runtime = 'edge';
限制回應長度
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
maxTokens: 1000, // 限制回應長度
});
使用較快的模型
// GPT-3.5 比 GPT-4 快
model: openai('gpt-3.5-turbo'),
快取常見問題
import { unstable_cache } from 'next/cache';
const getCachedResponse = unstable_cache(
async (question: string) => {
// 查詢預設回答
return await db.faq.findFirst({
where: { question: { contains: question } },
});
},
['faq-cache'],
{ revalidate: 3600 }
);
常見問題 FAQ
Q1:如何支援多語言?
可以在 System Prompt 中指定語言:
system: `請根據用戶使用的語言回覆。
如果用戶用中文提問,請用繁體中文回答。
如果用戶用英文提問,請用英文回答。`,
Q2:如何限制使用次數?
import { Ratelimit } from '@upstash/ratelimit';
import { kv } from '@vercel/kv';
const ratelimit = new Ratelimit({
redis: kv,
limiter: Ratelimit.slidingWindow(10, '1 h'), // 每小時 10 次
});
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for');
const { success } = await ratelimit.limit(ip);
if (!success) {
return Response.json({ error: '請求過於頻繁' }, { status: 429 });
}
// 繼續處理...
}
Q3:如何加入檔案上傳功能?
AI Chatbot 模板目前不內建檔案上傳。
可以整合 Vercel Blob 或其他儲存服務。
Q4:如何追蹤使用量和成本?
- 在 OpenAI Dashboard 查看 API 使用量
- 在程式中加入 logging
- 使用 Vercel Analytics
Q5:可以嵌入到現有網站嗎?
可以使用 iframe:
<iframe
src="https://your-chatbot.vercel.app"
width="400"
height="600"
style="border: none; border-radius: 12px;"
/>
或開發獨立的 Widget 元件。
進階整合
整合知識庫(RAG)
import { embed } from 'ai';
import { openai } from '@ai-sdk/openai';
// 1. 搜尋相關文件
const queryEmbedding = await embed({
model: openai.embedding('text-embedding-3-small'),
value: userQuestion,
});
const relevantDocs = await searchVectorDB(queryEmbedding);
// 2. 加入上下文
const result = await streamText({
model: openai('gpt-4-turbo'),
system: `請根據以下資料回答問題:
${relevantDocs.map(d => d.content).join('\n\n')}`,
messages,
});
整合外部 API
import { tool } from 'ai';
import { z } from 'zod';
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
tools: {
checkOrderStatus: tool({
description: '查詢訂單狀態',
parameters: z.object({
orderId: z.string(),
}),
execute: async ({ orderId }) => {
const order = await fetch(`/api/orders/${orderId}`);
return order.json();
},
}),
},
});
Vercel 部署失敗?
Build Error、環境變數、自訂網域,我們幫你快速排除問題。