AI 全栈应用开发
问题
如何构建一个完整的 AI 全栈应用?从数据库到部署的完整架构是怎样的?
答案
一、典型技术栈
二、数据库设计
-- 用户表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
-- 会话表
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
title VARCHAR(200),
model VARCHAR(50) DEFAULT 'gpt-4o',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 消息表
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES conversations(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL, -- 'user' | 'assistant' | 'system'
content TEXT NOT NULL,
tokens_used INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
-- 向量索引(pgvector)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
embedding vector(1536),
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
三、核心 API 实现
app/api/chat/route.ts
import { openai } from "@ai-sdk/openai";
import { streamText } from "ai";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
export async function POST(req: Request) {
// 1. 认证
const session = await auth();
if (!session?.user) {
return new Response("Unauthorized", { status: 401 });
}
const { messages, conversationId } = await req.json();
// 2. 保存用户消息
const userMessage = messages[messages.length - 1];
await db.message.create({
data: {
conversationId,
role: "user",
content: userMessage.content,
},
});
// 3. 流式调用 LLM
const result = streamText({
model: openai("gpt-4o"),
messages,
onFinish: async ({ text, usage }) => {
// 4. 保存 AI 回复
await db.message.create({
data: {
conversationId,
role: "assistant",
content: text,
tokensUsed: usage.totalTokens,
},
});
},
});
return result.toDataStreamResponse();
}
四、认证方案
lib/auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
export const { auth, handlers, signIn, signOut } = NextAuth({
providers: [GitHub],
callbacks: {
async session({ session, token }) {
session.user.id = token.sub!;
return session;
},
},
});
五、部署方案
| 平台 | 优势 | 适用 |
|---|---|---|
| Vercel | Next.js 最佳体验,Edge Runtime | 标准 AI 应用 |
| Railway | 全栈部署,Docker 支持 | 后端复杂的应用 |
| Fly.io | 全球边缘部署 | 低延迟要求 |
| 自建 Docker | 完全控制 | 企业私有部署 |
docker-compose.yml
services:
app:
build: .
ports: ["3000:3000"]
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY}
DATABASE_URL: postgres://user:pass@db:5432/app
depends_on: [db, redis]
db:
image: pgvector/pgvector:pg16
volumes: [postgres_data:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
volumes:
postgres_data:
常见面试问题
Q1: AI 应用的数据库选型?
答案:
- PostgreSQL + pgvector:关系数据 + 向量搜索一站式解决,推荐大多数场景
- Supabase:托管 PostgreSQL + Auth + Storage + Realtime,快速搭建
- Neon:Serverless PostgreSQL,按用量计费,适合 Serverless 架构
- 如果向量数据量超过千万级,考虑专用向量数据库(Milvus/Qdrant)
Q2: 如何控制 AI 应用的成本?
答案:
- Token 限制:设置每次对话的最大 token 数
- 用户配额:每日/每月 API 调用次数限制
- 缓存:相同问题缓存 LLM 响应
- 模型分级:简单问题用便宜模型,复杂问题用强模型
- Prompt 优化:精简 system prompt,减少上下文 token