开发指南AI 功能集成
AI 功能集成
🚀 Cheatsheet (快速执行)
目标: 10分钟内为你的应用添加 AI 聊天功能,让用户可以与 AI 对话
最快上手方式:
# 1. 获取 OpenAI API Key
# 访问 https://platform.openai.com/account/api-keys
# 创建新的 API Key
# 2. 配置环境变量
echo 'OPENAI_API_KEY=sk-你的密钥' >> .env.local
# 3. 已预装 Vercel AI SDK
# bun add ai @ai-sdk/openai
# 4. 创建聊天页面
# 访问 /app/ai/chatbot 测试 AI 对话功能
立即生效: 用户可以在聊天界面与 AI 进行对话,支持流式响应
❓ 为什么要集成 AI 功能
对 MVP 的核心价值:
- 产品差异化: AI 是现在最火的功能,用户看到就觉得很先进
- 用户粘性: AI 助手能让用户每天都来使用你的产品
- 收费理由: AI 功能消耗成本,天然的付费功能点
- 数据收集: 通过对话了解用户需求,优化产品方向
真实场景举例: 你做了一个创业工具,加入 AI 商业计划书生成功能,用户输入"我想做一个外卖app",AI 自动生成市场分析、竞品分析、盈利模式,用户觉得太牛了,立马付费升级。
🤔 为什么选择 Vercel AI SDK
我们的实战经验:
- 开发体验最好: 专为 React 设计,几行代码就能实现流式聊天
- 多提供商支持: 一套代码支持 OpenAI、Claude、Gemini,随时切换
- 流式响应: 像 ChatGPT 一样的打字效果,用户体验好
- 类型安全: 完整的 TypeScript 支持,减少bug
对比其他方案:
直接调用 OpenAI API: 需要自己处理流式响应,复杂
LangChain: 功能太重,学习成本高,适合复杂场景
原生 fetch: 没有 React 集成,体验差
Vercel AI SDK: ✅ 专为 Next.js 优化,开箱即用
🧠 简要原理 & 最简案例
AI 对话流程: 用户输入消息 → 发送到 API 路由 → 调用 AI 服务 → 流式返回回答 → 实时显示
最简聊天示例:
// 1. API 路由 (app/api/ai/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-3.5-turbo'),
messages,
})
return result.toDataStreamResponse()
}
// 2. 聊天组件 (components/ChatBox.tsx)
'use client'
import { useChat } from 'ai/react'
export function ChatBox() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/ai/chat',
})
return (
<div>
{/* 消息列表 */}
{messages.map(message => (
<div key={message.id}>
<strong>{message.role}:</strong> {message.content}
</div>
))}
{/* 输入框 */}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} placeholder="问我任何问题..." />
<button type="submit">发送</button>
</form>
</div>
)
}
🛠️ 实际操作步骤
1. 配置 AI 提供商 (5分钟)
获取 OpenAI API Key:
1. 访问 https://platform.openai.com
2. 注册并登录账号
3. Billing > 添加支付方式 (必须,否则无法使用)
4. API keys > Create new secret key
5. 复制密钥:sk-proj-...
环境变量配置:
# .env.local
OPENAI_API_KEY=sk-proj-你的完整密钥
# 可选:其他 AI 提供商
ANTHROPIC_API_KEY=sk-ant-你的Claude密钥
GOOGLE_GENERATIVE_AI_API_KEY=你的Gemini密钥
2. 创建基础聊天功能 (10分钟)
聊天页面组件:
// app/ai/chatbot/page.tsx
import { ChatInterface } from '@/modules/ai/ChatInterface'
export default function ChatbotPage() {
return (
<div className="container mx-auto max-w-4xl p-4">
<h1 className="text-2xl font-bold mb-6">AI 聊天助手</h1>
<ChatInterface />
</div>
)
}
完整聊天界面:
// components/ai/ChatInterface.tsx
'use client'
import { useChat } from 'ai/react'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
export function ChatInterface() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: '/api/ai/chat',
})
return (
<div className="flex flex-col h-[600px] border rounded-lg">
{/* 消息区域 */}
<ScrollArea className="flex-1 p-4">
{messages.length === 0 && (
<div className="text-center text-gray-500 mt-20">
<p>👋 你好!我是 AI 助手,有什么可以帮助你的吗?</p>
</div>
)}
{messages.map(message => (
<div key={message.id} className={`mb-4 ${
message.role === 'user' ? 'text-right' : 'text-left'
}`}>
<div className={`inline-block p-3 rounded-lg max-w-[80%] ${
message.role === 'user'
? 'bg-blue-500 text-white'
: 'bg-gray-100 text-gray-900'
}`}>
{message.content}
</div>
</div>
))}
{isLoading && (
<div className="text-left mb-4">
<div className="inline-block p-3 rounded-lg bg-gray-100">
<div className="flex space-x-1">
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{animationDelay: '0.1s'}}></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{animationDelay: '0.2s'}}></div>
</div>
</div>
</div>
)}
</ScrollArea>
{/* 输入区域 */}
<form onSubmit={handleSubmit} className="p-4 border-t flex gap-2">
<Input
value={input}
onChange={handleInputChange}
placeholder="输入你的问题..."
disabled={isLoading}
className="flex-1"
/>
<Button type="submit" disabled={isLoading}>
发送
</Button>
</form>
</div>
)
}
3. 增强 API 路由功能 (10分钟)
智能路由选择:
// app/api/ai/chat/route.ts
import { openai } from '@ai-sdk/openai'
import { anthropic } from '@ai-sdk/anthropic'
import { streamText } from 'ai'
import { auth } from '@/lib/auth'
export async function POST(req: Request) {
try {
const session = await auth()
if (!session?.user) {
return Response.json({ error: '请先登录' }, { status: 401 })
}
const { messages } = await req.json()
// 根据用户套餐选择模型
const user = session.user
const model = user.planType === 'pro'
? openai('gpt-4')
: openai('gpt-3.5-turbo')
const result = await streamText({
model,
messages,
system: `你是一个有用的AI助手。请用中文回答用户的问题。
如果用户提到创业、商业计划等话题,请提供实用的建议。`,
// 安全过滤
maxTokens: 1000,
temperature: 0.7,
})
return result.toDataStreamResponse()
} catch (error) {
console.error('AI API 错误:', error)
return Response.json({ error: 'AI 服务暂时不可用' }, { status: 500 })
}
}
4. 添加专用 AI 功能 (15分钟)
文案生成功能:
// app/api/ai/generate-content/route.ts
import { openai } from '@ai-sdk/openai'
import { generateText } from 'ai'
export async function POST(req: Request) {
const { prompt, type } = await req.json()
const prompts = {
blog: `请写一篇关于"${prompt}"的博客文章,包括标题、引言、正文和结论。`,
social: `为"${prompt}"写 5 条不同风格的社交媒体文案。`,
email: `写一封关于"${prompt}"的营销邮件,包括主题行和正文。`,
slogan: `为"${prompt}"想 10 个创意广告标语。`
}
const result = await generateText({
model: openai('gpt-3.5-turbo'),
prompt: prompts[type] || prompt,
})
return Response.json({ content: result.text })
}
内容生成组件:
// components/ai/ContentGenerator.tsx
'use client'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Textarea } from '@/components/ui/textarea'
import { Select } from '@/components/ui/select'
export function ContentGenerator() {
const [prompt, setPrompt] = useState('')
const [type, setType] = useState('blog')
const [result, setResult] = useState('')
const [loading, setLoading] = useState(false)
const handleGenerate = async () => {
setLoading(true)
try {
const response = await fetch('/api/ai/generate-content', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt, type })
})
const data = await response.json()
setResult(data.content)
} catch (error) {
alert('生成失败,请重试')
} finally {
setLoading(false)
}
}
return (
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">内容主题</label>
<Textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="例如:如何提高工作效率"
rows={3}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">内容类型</label>
<Select value={type} onValueChange={setType}>
<option value="blog">博客文章</option>
<option value="social">社交媒体</option>
<option value="email">营销邮件</option>
<option value="slogan">广告标语</option>
</Select>
</div>
<Button onClick={handleGenerate} disabled={loading || !prompt}>
{loading ? '生成中...' : '开始生成'}
</Button>
{result && (
<div className="border rounded p-4 bg-gray-50">
<h3 className="font-medium mb-2">生成结果:</h3>
<div className="whitespace-pre-wrap">{result}</div>
</div>
)}
</div>
)
}
💡 高级 AI 功能
文件上传分析
// app/api/ai/analyze-file/route.ts
import { openai } from '@ai-sdk/openai'
import { generateText } from 'ai'
export async function POST(req: Request) {
const formData = await req.formData()
const file = formData.get('file') as File
// 读取文件内容
const content = await file.text()
const result = await generateText({
model: openai('gpt-3.5-turbo'),
prompt: `请分析以下文档内容,并提供:
1. 内容摘要
2. 关键要点
3. 改进建议
文档内容:
${content}`,
})
return Response.json({ analysis: result.text })
}
AI 角色设定
// lib/ai/personas.ts
export const aiPersonas = {
assistant: {
name: '通用助手',
system: '你是一个友善、专业的AI助手,能够帮助用户解决各种问题。',
},
business: {
name: '商业顾问',
system: '你是一位经验丰富的商业顾问,专注于帮助创业者和企业家解决商业问题。',
},
writer: {
name: '写作助手',
system: '你是一位专业的写作助手,擅长各种类型的文案创作和内容优化。',
},
teacher: {
name: '学习导师',
system: '你是一位耐心的老师,善于用简单易懂的方式解释复杂概念。',
}
}
// 使用示例
export function getPersonaPrompt(personaId: string, userMessage: string) {
const persona = aiPersonas[personaId] || aiPersonas.assistant
return `${persona.system}\n\n用户问题:${userMessage}`
}
成本控制和限流
// lib/ai/usage.ts
export async function checkAIUsage(userId: string) {
const user = await db.user.findUnique({
where: { id: userId },
include: { usage: true }
})
const today = new Date().toISOString().split('T')[0]
const dailyUsage = user.usage?.find(u => u.date === today)
const limits = {
free: 10, // 免费用户每天 10 次
pro: 100, // Pro 用户每天 100 次
enterprise: -1 // 企业版无限制
}
const limit = limits[user.planType] || limits.free
const used = dailyUsage?.count || 0
return {
allowed: limit === -1 || used < limit,
remaining: limit === -1 ? -1 : Math.max(0, limit - used),
resetTime: new Date(Date.now() + 24 * 60 * 60 * 1000) // 明天同一时间
}
}
🎯 用户体验优化
错误处理和重试
// hooks/useAIChat.ts
import { useChat } from 'ai/react'
import { useState } from 'react'
export function useAIChat() {
const [retryCount, setRetryCount] = useState(0)
const maxRetries = 3
const chat = useChat({
api: '/api/ai/chat',
onError: (error) => {
console.error('AI 聊天错误:', error)
if (retryCount < maxRetries) {
setTimeout(() => {
setRetryCount(prev => prev + 1)
// 重试逻辑
}, 1000 * (retryCount + 1)) // 递增延迟
}
},
onFinish: () => {
setRetryCount(0) // 成功后重置重试计数
}
})
return {
...chat,
canRetry: retryCount < maxRetries,
isRetrying: retryCount > 0
}
}
消息持久化
// lib/ai/history.ts
export async function saveChatMessage(userId: string, role: string, content: string) {
return await db.chatMessage.create({
data: {
userId,
role,
content,
timestamp: new Date()
}
})
}
export async function getChatHistory(userId: string, limit = 50) {
return await db.chatMessage.findMany({
where: { userId },
orderBy: { timestamp: 'desc' },
take: limit
})
}
🆘 常见问题解决
问题1: API 调用失败
// 检查 API Key 配置
console.log('OpenAI Key:', process.env.OPENAI_API_KEY?.slice(0, 10) + '...')
// 添加错误处理
try {
const result = await streamText({ model, messages })
return result.toDataStreamResponse()
} catch (error) {
if (error.message?.includes('API key')) {
return Response.json({ error: 'API 密钥配置错误' }, { status: 401 })
}
if (error.message?.includes('quota')) {
return Response.json({ error: 'API 额度不足,请充值' }, { status: 429 })
}
throw error
}
问题2: 流式响应中断
// 客户端重连机制
const { messages, input, handleInputChange, handleSubmit, isLoading, error } = useChat({
api: '/api/ai/chat',
onError: (error) => {
console.error('聊天错误:', error)
// 可以显示重试按钮
},
// 自动重试配置
initialMessages: [],
keepLastMessageOnError: true
})
问题3: 响应时间过长
// 设置超时时间
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 30000) // 30秒超时
const result = await streamText({
model,
messages,
abortSignal: controller.signal
})
clearTimeout(timeoutId)
📊 AI 使用统计
使用情况面板
// components/ai/UsageStats.tsx
export function AIUsageStats() {
const { data: stats } = useAIUsage()
return (
<div className="grid grid-cols-3 gap-4">
<div className="bg-white p-4 rounded shadow">
<h3 className="text-sm text-gray-600">今日使用</h3>
<p className="text-2xl font-bold">{stats?.todayCount}</p>
<p className="text-xs text-gray-500">剩余 {stats?.remaining} 次</p>
</div>
<div className="bg-white p-4 rounded shadow">
<h3 className="text-sm text-gray-600">本月费用</h3>
<p className="text-2xl font-bold">${stats?.monthlyCost}</p>
</div>
<div className="bg-white p-4 rounded shadow">
<h3 className="text-sm text-gray-600">最常用功能</h3>
<p className="text-lg font-medium">{stats?.topFeature}</p>
</div>
</div>
)
}
📎 延伸阅读
官方文档:
- Vercel AI SDK - 完整的 SDK 文档和示例
- OpenAI API - OpenAI 官方 API 文档
最佳实践:
- AI 应用设计指南 - OpenAI 官方最佳实践
- Prompt 工程技巧 - 提示词优化指南
工具推荐:
- AI Playground - 在线测试和调试
- Prompt 模板库 - 优质提示词模板
下一步: AI 功能配置完成后,查看 [文件存储]./storage) 了解如何实现文件上传和AI文档分析功能。