项目完整文件结构
ai-content-studio/
├── 📄 package.json # 项目依赖配置
├── 📄 tsconfig.json # TypeScript 配置
├── 📄 next.config.js # Next.js 配置
├── 📄 .env.example # 环境变量示例
├── 📄 .gitignore # Git 忽略文件
├── 📄 README.md # 项目说明文档
│
├── 📁 public/ # 静态资源
│ ├── logo.svg # 网站图标
│ └── images/ # 图片资源
│
├── 📁 src/ # 源代码目录
│ ├── 📁 app/ # Next.js 14 App Router
│ │ ├── layout.tsx # 根布局(Ant Design 配置)
│ │ ├── page.tsx # 首页
│ │ ├── globals.css # 全局样式
│ │ │
│ │ ├── 📁 (dashboard)/ # 主应用路由组
│ │ │ ├── layout.tsx # 仪表盘布局
│ │ │ ├── projects/ # 项目列表页
│ │ │ │ └── page.tsx
│ │ │ ├── create/ # 创作页面
│ │ │ │ └── page.tsx
│ │ │ ├── settings/ # 设置页面
│ │ │ │ └── api/
│ │ │ │ └── page.tsx # API 配置页
│ │ │ └── [id]/ # 项目详情页
│ │ │ └── page.tsx
│ │ │
│ │ └── 📁 api/ # API 路由
│ │ └── ai/ # AI 相关接口
│ │ ├── plan/ # 规划 Agent
│ │ │ └── route.ts
│ │ ├── write/ # 写作 Agent
│ │ │ └── route.ts
│ │ ├── optimize/ # 优化 Agent
│ │ │ └── route.ts
│ │ └── test/ # API 测试
│ │ └── route.ts
│ │
│ ├── 📁 components/ # React 组件
│ │ ├── 📁 agents/ # Agent 相关组件
│ │ │ ├── AgentCard.tsx # Agent 状态卡片
│ │ │ └── AgentPipeline.tsx # Agent 流水线
│ │ ├── 📁 editor/ # 编辑器组件
│ │ │ └── ContentEditor.tsx # 内容编辑器
│ │ └── 📁 layout/ # 布局组件
│ │ ├── Header.tsx # 头部导航
│ │ ├── Sidebar.tsx # 侧边栏
│ │ └── Footer.tsx # 页脚
│ │
│ ├── 📁 lib/ # 核心逻辑库
│ │ ├── 📁 ai/ # AI 相关
│ │ │ ├── client.ts # AI 客户端工厂
│ │ │ └── monitor.ts # 使用监控
│ │ ├── 📁 agents/ # Agent 实现
│ │ │ ├── planner.ts # 规划 Agent
│ │ │ ├── writer.ts # 写作 Agent
│ │ │ ├── optimizer.ts # 优化 Agent
│ │ │ └── orchestrator.ts # Agent 协调器
│ │ ├── 📁 db/ # 数据库
│ │ │ ├── supabase.ts # Supabase 客户端
│ │ │ ├── queries.ts # 数据库查询
│ │ │ └── types.ts # 类型定义
│ │ ├── 📁 prompts/ # Prompt 模板
│ │ │ ├── planner.ts # 规划 Prompt
│ │ │ ├── writer.ts # 写作 Prompt
│ │ │ └── optimizer.ts # 优化 Prompt
│ │ └── 📁 utils/ # 工具函数
│ │ ├── text.ts # 文本处理
│ │ └── format.ts # 格式化
│ │
│ ├── 📁 stores/ # 状态管理
│ │ ├── projectStore.ts # 项目状态
│ │ └── agentStore.ts # Agent 状态
│ │
│ ├── 📁 hooks/ # 自定义 Hooks
│ │ ├── useProject.ts # 项目管理
│ │ └── useAgentStream.ts # 流式响应
│ │
│ ├── 📁 types/ # TypeScript 类型
│ │ ├── agent.ts # Agent 类型
│ │ └── project.ts # 项目类型
│ │
│ └── 📁 theme/ # 主题配置
│ └── themeConfig.ts # Ant Design 主题
│
└── 📁 database/ # 数据库脚本
└── schema.sql # 数据库表结构
核心文件详细代码和注释
1. package.json - 项目依赖配置
{
"name": "ai-content-studio",
"version": "1.1.0",
"description": "AI 驱动的内容创作工作台 - 基于多 Agent 协作",
// 项目脚本命令
"scripts": {
// 开发模式:启动热重载开发服务器
"dev": "next dev",
// 生产构建:编译 TypeScript 和优化代码
"build": "next build",
// 生产启动:运行编译后的应用
"start": "next start",
// 代码检查:ESLint 检查代码规范
"lint": "next lint",
// 自动修复:自动修复可修复的代码问题
"lint:fix": "next lint --fix",
// 类型检查:检查 TypeScript 类型错误(不生成文件)
"type-check": "tsc --noEmit",
// 代码格式化:Prettier 格式化所有代码
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
// 生成数据库类型:从 Supabase 自动生成 TypeScript 类型
"db:generate-types": "npx supabase gen types typescript --project-id YOUR_PROJECT_ID > src/lib/db/types.ts"
},
// 生产依赖
"dependencies": {
// ===== 核心框架 =====
"next": "14.0.4", // Next.js 框架
"react": "^18.2.0", // React 库
"react-dom": "^18.2.0", // React DOM 渲染
// ===== UI 组件库 =====
"antd": "^5.12.0", // Ant Design 组件库
"@ant-design/icons": "^5.2.6", // Ant Design 图标
"@ant-design/nextjs-registry": "^1.0.0", // Next.js 集成
// ===== AI 相关 =====
"ai": "^3.0.0", // Vercel AI SDK
"@ai-sdk/openai": "^0.0.42", // OpenAI 适配器(DeepSeek 兼容)
"zod": "^3.22.4", // Schema 验证
// ===== 状态管理 =====
"zustand": "^4.4.7", // 轻量级状态管理
// ===== 数据库 =====
"@supabase/supabase-js": "^2.39.0", // Supabase 客户端
// ===== 工具库 =====
"dayjs": "^1.11.10", // 日期处理(Ant Design 依赖)
"nanoid": "^5.0.4" // ID 生成
},
// 开发依赖
"devDependencies": {
"@types/node": "^20", // Node.js 类型定义
"@types/react": "^18", // React 类型定义
"@types/react-dom": "^18", // React DOM 类型定义
"eslint": "^8", // 代码检查工具
"eslint-config-next": "14.0.4",// Next.js ESLint 配置
"prettier": "^3.1.1", // 代码格式化工具
"typescript": "^5" // TypeScript 编译器
},
// 引擎要求
"engines": {
"node": ">=18.17.0", // 最低 Node.js 版本
"npm": ">=9.0.0" // 最低 npm 版本
}
}
关键依赖说明:
- Ant Design:
- 企业级 UI 组件库
- 60+ 组件开箱即用
- 完善的中文文档
- Vercel AI SDK:
- 统一的 AI 接口
- 支持流式响应
- 兼容多个 AI 提供商
- Zustand:
- 比 Redux 简单 10 倍
- 性能好、体积小
- TypeScript 友好
3. src/theme/themeConfig.ts - 主题配置
/**
* Ant Design 主题配置
*
* 定制品牌色、圆角、字体等
* 所有组件都会应用这些配置
*/
import type { ThemeConfig } from 'antd';
export const theme: ThemeConfig = {
// ===== Token 级别配置 =====
// 这些是设计系统的基础变量
token: {
// ----- 品牌色 -----
colorPrimary: '#1890ff', // 主色:蓝色(按钮、链接等)
colorSuccess: '#52c41a', // 成功色:绿色
colorWarning: '#faad14', // 警告色:橙色
colorError: '#ff4d4f', // 错误色:红色
colorInfo: '#1890ff', // 信息色:蓝色
// ----- 圆角 -----
borderRadius: 8, // 基础圆角:8px
borderRadiusLG: 12, // 大圆角:12px(卡片等)
borderRadiusSM: 4, // 小圆角:4px(按钮等)
// ----- 间距 -----
padding: 16, // 基础内边距
paddingLG: 24, // 大内边距
paddingSM: 12, // 小内边距
// ----- 字体 -----
fontSize: 14, // 基础字号
fontSizeHeading1: 32, // h1 字号
fontSizeHeading2: 28, // h2 字号
fontSizeHeading3: 24, // h3 字号
// 字体家族(优先使用系统字体,性能好)
fontFamily: `-apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue",
Arial, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", sans-serif`,
// ----- 阴影 -----
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
boxShadowSecondary: '0 4px 16px rgba(0, 0, 0, 0.08)',
},
// ===== 组件级别配置 =====
// 针对特定组件的定制
components: {
// ----- 按钮组件 -----
Button: {
controlHeight: 40, // 默认高度:40px
controlHeightLG: 48, // 大按钮高度:48px
controlHeightSM: 32, // 小按钮高度:32px
fontSize: 14, // 字号
fontSizeLG: 16, // 大按钮字号
borderRadius: 8, // 圆角
paddingContentHorizontal: 16, // 水平内边距
},
// ----- 输入框组件 -----
Input: {
controlHeight: 40, // 默认高度
fontSize: 14, // 字号
borderRadius: 8, // 圆角
paddingBlock: 8, // 上下内边距
paddingInline: 12, // 左右内边距
},
// ----- 卡片组件 -----
Card: {
borderRadiusLG: 12, // 圆角
paddingLG: 24, // 内边距
boxShadowTertiary: '0 1px 4px rgba(0, 0, 0, 0.08)',
},
// ----- 表单组件 -----
Form: {
labelFontSize: 14, // 标签字号
verticalLabelPadding: '0 0 8px', // 垂直布局标签内边距
},
// ----- 消息提示 -----
Message: {
contentPadding: '12px 16px',
fontSize: 14,
},
},
};
主题配置的好处:
- 统一视觉:所有组件自动应用相同的设计规范
- 易于维护:修改一处,全局生效
- 品牌定制:轻松更换品牌色
使用示例:
// 所有按钮都会自动应用这些样式
<Button type="primary">提交</Button> // 高度 40px,圆角 8px
<Button size="large">大按钮</Button> // 高度 48px
4. src/lib/ai/client.ts - AI 客户端工厂
/**
* AI 客户端工厂
*
* 职责:
* 1. 统一管理多个 AI 提供商(DeepSeek、OpenAI、Claude)
* 2. 根据配置自动选择 AI 服务
* 3. 提供一致的调用接口
*
* 设计模式:工厂模式
*/
import { createOpenAI } from '@ai-sdk/openai';
import { createAnthropic } from '@ai-sdk/anthropic';
/**
* AI 提供商类型
*/
export type AIProvider = 'deepseek' | 'openai' | 'claude';
/**
* AI 配置接口
*/
export interface AIConfig {
provider: AIProvider; // 提供商
deepseekKey?: string; // DeepSeek API Key
openaiKey?: string; // OpenAI API Key
claudeKey?: string; // Claude API Key
}
/**
* 获取当前 AI 配置
*
* 优先级:
* 1. 环境变量(服务端)
* 2. localStorage(客户端)
* 3. 默认值(DeepSeek)
*
* @returns AI 配置对象
*/
export function getAIConfig(): AIConfig {
// 服务端:从环境变量读取
if (typeof window === 'undefined') {
return {
provider: (process.env.AI_PROVIDER as AIProvider) || 'deepseek',
deepseekKey: process.env.DEEPSEEK_API_KEY,
openaiKey: process.env.OPENAI_API_KEY,
claudeKey: process.env.ANTHROPIC_API_KEY,
};
}
// 客户端:从 localStorage 读取
const stored = localStorage.getItem('ai_config');
if (stored) {
try {
return JSON.parse(stored);
} catch {
// JSON 解析失败,返回默认值
}
}
// 默认配置
return {
provider: 'deepseek',
deepseekKey: process.env.NEXT_PUBLIC_DEEPSEEK_API_KEY,
};
}
/**
* 创建 AI 客户端
*
* 使用工厂模式,根据配置创建对应的客户端
*
* @param config - AI 配置(可选,不传则使用默认配置)
* @returns AI 客户端实例
*
* @example
* // 使用默认配置(DeepSeek)
* const client = createAIClient();
*
* // 使用自定义配置
* const client = createAIClient({
* provider: 'openai',
* openaiKey: 'sk-...',
* });
*/
export function createAIClient(config?: AIConfig) {
// 获取配置
const aiConfig = config || getAIConfig();
// 根据提供商创建对应的客户端
switch (aiConfig.provider) {
case 'deepseek':
// DeepSeek 使用 OpenAI 兼容格式
// 只需修改 baseURL 和 API Key
return createOpenAI({
apiKey: aiConfig.deepseekKey || process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',
});
case 'openai':
// OpenAI 官方
return createOpenAI({
apiKey: aiConfig.openaiKey || process.env.OPENAI_API_KEY,
});
case 'claude':
// Anthropic Claude
return createAnthropic({
apiKey: aiConfig.claudeKey || process.env.ANTHROPIC_API_KEY,
});
default:
// 不支持的提供商,抛出错误
throw new Error(`不支持的 AI 提供商: ${aiConfig.provider}`);
}
}
/**
* 获取模型名称
*
* 不同提供商使用不同的模型名称
*
* @param config - AI 配置(可选)
* @returns 模型名称字符串
*
* @example
* const modelName = getModelName(); // 'deepseek-chat'
*/
export function getModelName(config?: AIConfig): string {
const aiConfig = config || getAIConfig();
// 模型名称映射
const modelMap: Record<AIProvider, string> = {
deepseek: 'deepseek-chat', // DeepSeek 通用模型
openai: 'gpt-4-turbo-preview', // GPT-4 Turbo
claude: 'claude-3-sonnet-20240229', // Claude 3 Sonnet
};
return modelMap[aiConfig.provider] || 'deepseek-chat';
}
/**
* 保存 AI 配置
*
* 保存到 localStorage(仅客户端)
*
* @param config - 要保存的配置
*
* @example
* saveAIConfig({
* provider: 'deepseek',
* deepseekKey: 'sk-...',
* });
*/
export function saveAIConfig(config: AIConfig): void {
if (typeof window !== 'undefined') {
localStorage.setItem('ai_config', JSON.stringify(config));
}
}
设计亮点:
- 工厂模式:
- 统一接口,隐藏实现细节
- 易于扩展新的 AI 提供商
- 配置优先级:
- 环境变量 > localStorage > 默认值
- 灵活适配不同场景
- 类型安全:
- 完整的 TypeScript 类型定义
- 编译时检查,减少运行时错误
使用示例:
// 在 Agent 中使用
import { createAIClient, getModelName } from '@/lib/ai/client';
const client = createAIClient();
const model = getModelName();
const result = await generateText({
model: client(model),
prompt: '你好',
});
5. src/lib/agents/planner.ts - 规划 Agent
/**
* 规划 Agent
*
* 职责:
* 1. 接收用户输入的主题和要求
* 2. 调用 AI 生成文章大纲
* 3. 返回结构化的大纲数据
*
* 这是多 Agent 系统的第一个 Agent
*/
import { generateObject } from 'ai';
import { createAIClient, getModelName } from '@/lib/ai/client';
import { z } from 'zod';
import { buildPlannerPrompt } from '@/lib/prompts/planner';
/**
* 大纲 Schema 定义
*
* 使用 Zod 定义数据结构:
* 1. 自动验证 AI 返回的数据
* 2. 自动生成 TypeScript 类型
* 3. 确保数据格式正确
*/
const OutlineSchema = z.object({
// 文章标题
title: z.string().describe('吸引人的文章标题'),
// 简介部分
introduction: z.object({
hook: z.string().describe('开场白,吸引读者'),
thesis: z.string().describe('文章核心论点'),
wordCount: z.number().describe('建议字数'),
}),
// 主体章节(数组)
sections: z.array(
z.object({
heading: z.string().describe('章节标题'),
points: z.array(z.string()).describe('核心要点列表'),
wordCount: z.number().describe('建议字数'),
tips: z.string().optional().describe('写作建议'),
})
).min(3).max(10), // 限制章节数量:3-10个
// 结论部分
conclusion: z.object({
summary: z.string().describe('总结要点'),
callToAction: z.string().describe('行动号召'),
wordCount: z.number().describe('建议字数'),
}),
// SEO 相关
keywords: z.array(z.string()).min(5).max(10).describe('关键词列表'),
seoTitle: z.string().describe('SEO 优化标题'),
metaDescription: z.string().max(160).describe('元描述(最多160字)'),
});
/**
* 从 Schema 自动推导 TypeScript 类型
*
* 这样我们就不需要手动定义类型了
*/
export type Outline = z.infer<typeof OutlineSchema>;
/**
* 规划参数接口
*/
export interface PlanContentParams {
topic: string; // 文章主题
type: 'blog' | 'xiaohongshu' | 'article' | 'weixin'; // 文章类型
audience: string; // 目标受众
wordCount: number; // 总字数要求
tone: 'professional' | 'casual' | 'humorous'; // 语气风格
}
/**
* 规划内容(主函数)
*
* 这是规划 Agent 的核心函数
*
* @param params - 规划参数
* @returns 结构化的文章大纲
*
* @throws {Error} 当 AI 调用失败或返回数据格式错误时
*
* @example
* const outline = await planContent({
* topic: 'AI 在前端开发中的应用',
* type: 'blog',
* audience: '前端开发者',
* wordCount: 2000,
* tone: 'professional',
* });
*
* console.log(outline.title); // "AI 赋能前端:开发效率提升指南"
* console.log(outline.sections); // [{ heading: '...', points: [...] }]
*/
export async function planContent(
params: PlanContentParams
): Promise<Outline> {
// 步骤 1: 创建 AI 客户端
const client = createAIClient();
const modelName = getModelName();
// 步骤 2: 构建 Prompt
// buildPlannerPrompt 会根据参数生成详细的提示词
const prompt = buildPlannerPrompt(params);
// 步骤 3: 调用 AI 生成结构化数据
// generateObject 是 Vercel AI SDK 的函数
// 它会:
// 1. 调用 AI 模型
// 2. 解析返回的 JSON
// 3. 使用 Zod Schema 验证数据
// 4. 如果验证失败,会自动重试
const result = await generateObject({
model: client(modelName), // AI 模型
schema: OutlineSchema, // 数据结构定义
prompt: prompt, // 提示词
temperature: 0.7, // 创造性参数(0-1,越高越有创意)
});
// 步骤 4: 返回验证后的数据
// result.object 已经是符合 OutlineSchema 的数据
return result.object;
}
/**
* 规划内容(带重试)
*
* 在网络不稳定的情况下,提供自动重试功能
*
* @param params - 规划参数
* @param maxRetries - 最大重试次数(默认 3 次)
* @returns 结构化的文章大纲
*/
export async function planContentWithRetry(
params: PlanContentParams,
maxRetries: number = 3
): Promise<Outline> {
let lastError: Error | null = null;
// 重试循环
for (let i = 0; i < maxRetries; i++) {
try {
return await planContent(params);
} catch (error) {
lastError = error as Error;
// 如果不是最后一次尝试,等待后重试
if (i < maxRetries - 1) {
// 指数退避:第 1 次等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
}
}
}
// 所有重试都失败,抛出最后一个错误
throw lastError || new Error('规划失败');
}
核心技术点:
- Zod Schema 验证:
- 定义数据结构
- 自动验证 AI 返回
- 生成 TypeScript 类型
- generateObject:
- Vercel AI SDK 的核心功能
- 比普通的 generateText 更可靠
- 自动处理 JSON 解析和验证
- 重试机制:
- 指数退避算法
- 提高成功率
面试要点:
- "我实现了一个规划 Agent,使用 Zod 进行 Schema 验证,确保 AI 返回的数据格式正确"
- "采用了指数退避的重试策略,在网络不稳定时提高成功率"