llm-chat/.qoder/quests/llm-chat-website.md

541 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 大语言模型聊天网站设计文档
## 概述
本项目是一个全栈大语言模型聊天网站支持用户与AI进行实时对话。系统采用前后端分离架构前端使用Vue.js构建用户界面后端使用Node.js提供API服务通过调用兼容OpenAI格式的第三方API实现智能对话功能。
### 核心特性
- 实时AI对话体验
- 对话历史记录与管理
- 用户会话状态保持
- 响应式Web界面
- 高性能缓存机制
- 轻量级本地数据存储
### 技术栈
- **前端**: Vue.js 3, Vue Router, Pinia, Axios, Element Plus
- **后端**: Node.js, Express.js, SQLite3, LRU-Cache
- **包管理**: pnpm
- **数据库**: SQLite (本地文件数据库)
- **第三方集成**: OpenAI兼容API服务
## 系统架构
### 整体架构图
```mermaid
graph TB
subgraph "客户端"
A[Vue.js前端]
A1[聊天界面]
A2[历史记录]
A3[用户设置]
end
subgraph "服务端"
B[Node.js后端]
B1[Express路由]
B2[会话管理]
B3[缓存层]
B4[数据访问层]
end
subgraph "数据存储"
C[SQLite数据库]
C1[用户表]
C2[对话表]
C3[消息表]
end
subgraph "外部服务"
D[第三方LLM API]
D1[OpenAI兼容接口]
end
A -->|HTTP/WebSocket| B
B -->|SQL查询| C
B -->|API调用| D
B3 -->|LRU缓存| B2
```
### 数据流架构
```mermaid
sequenceDiagram
participant U as 用户
participant F as Vue前端
participant B as Node.js后端
participant C as LRU缓存
participant DB as SQLite
participant API as 第三方LLM API
U->>F: 发送消息
F->>B: POST /api/chat/send
B->>C: 检查缓存
alt 缓存命中
C-->>B: 返回缓存结果
else 缓存未命中
B->>DB: 保存用户消息
B->>API: 调用LLM API
API-->>B: 返回AI回复
B->>DB: 保存AI回复
B->>C: 更新缓存
end
B-->>F: 返回对话结果
F-->>U: 显示AI回复
```
## 前端架构
### 组件层次结构
```mermaid
graph TD
A[App.vue] --> B[Layout组件]
B --> C[Header组件]
B --> D[Sidebar组件]
B --> E[Main组件]
E --> F[ChatView]
E --> G[HistoryView]
E --> H[SettingsView]
F --> I[ChatInput]
F --> J[MessageList]
F --> K[TypingIndicator]
J --> L[MessageItem]
L --> M[UserMessage]
L --> N[AIMessage]
D --> O[ConversationList]
O --> P[ConversationItem]
```
### 组件定义
#### 核心聊天组件
**ChatView.vue** - 主聊天界面
- 管理当前对话状态
- 处理消息发送逻辑
- 实现消息流式显示
**MessageList.vue** - 消息列表容器
- 虚拟滚动优化
- 消息懒加载
- 自动滚动到底部
**ChatInput.vue** - 消息输入组件
- 多行文本输入
- 发送按钮状态管理
- 快捷键支持(Ctrl+Enter)
#### 布局组件
**Layout.vue** - 主布局容器
- 响应式布局设计
- 侧边栏展开/收缩
- 移动端适配
**Sidebar.vue** - 侧边栏组件
- 对话历史列表
- 新建对话按钮
- 对话搜索功能
### 状态管理架构
使用Pinia进行状态管理主要包含以下Store:
**chatStore.js** - 聊天状态管理
```javascript
{
currentConversation: null,
messages: [],
isLoading: false,
isTyping: false
}
```
**conversationStore.js** - 对话管理
```javascript
{
conversations: [],
activeConversationId: null,
searchQuery: ''
}
```
**userStore.js** - 用户设置
```javascript
{
settings: {
theme: 'light',
fontSize: 'medium',
autoSave: true
}
}
```
### 路由配置
```javascript
const routes = [
{
path: '/',
component: Layout,
children: [
{ path: '', redirect: '/chat' },
{ path: '/chat/:id?', component: ChatView },
{ path: '/history', component: HistoryView },
{ path: '/settings', component: SettingsView }
]
}
]
```
### API集成层
**apiClient.js** - HTTP客户端封装
- Axios实例配置
- 请求/响应拦截器
- 错误处理机制
- 重试逻辑
**chatApi.js** - 聊天相关API
```javascript
export const chatApi = {
sendMessage: (conversationId, message) => {},
getConversations: () => {},
getMessages: (conversationId) => {},
createConversation: () => {},
deleteConversation: (id) => {}
}
```
## 后端架构
### API端点设计
#### 对话管理端点
| 方法 | 路径 | 描述 | 请求体 | 响应 |
|------|------|------|--------|------|
| POST | `/api/conversations` | 创建新对话 | `{ title?: string }` | `{ id, title, createdAt }` |
| GET | `/api/conversations` | 获取对话列表 | - | `[{ id, title, lastMessage, updatedAt }]` |
| GET | `/api/conversations/:id` | 获取对话详情 | - | `{ id, title, messages }` |
| DELETE | `/api/conversations/:id` | 删除对话 | - | `{ success: true }` |
#### 消息处理端点
| 方法 | 路径 | 描述 | 请求体 | 响应 |
|------|------|------|--------|------|
| POST | `/api/chat/send` | 发送消息 | `{ conversationId, message, stream? }` | `{ message, response }` |
| GET | `/api/messages/:conversationId` | 获取消息历史 | - | `[{ id, role, content, timestamp }]` |
### 数据模型设计
#### 数据库表结构
**conversations表**
```sql
CREATE TABLE conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL DEFAULT '新对话',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
**messages表**
```sql
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id INTEGER NOT NULL,
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
);
```
### 业务逻辑层
#### 对话服务 (ConversationService)
```javascript
class ConversationService {
// 创建新对话
async createConversation(title) {}
// 获取对话列表
async getConversations() {}
// 获取对话详情
async getConversationById(id) {}
// 删除对话
async deleteConversation(id) {}
// 更新对话标题
async updateConversationTitle(id, title) {}
}
```
#### 聊天服务 (ChatService)
```javascript
class ChatService {
constructor(llmApiClient, cache) {
this.llmApiClient = llmApiClient;
this.cache = cache;
}
// 处理用户消息
async processMessage(conversationId, userMessage) {
// 1. 保存用户消息到数据库
// 2. 构建上下文(包含历史消息)
// 3. 调用LLM API
// 4. 保存AI回复到数据库
// 5. 更新缓存
// 6. 返回结果
}
// 流式响应处理
async processStreamMessage(conversationId, userMessage) {}
}
```
#### LLM API客户端 (LLMApiClient)
```javascript
class LLMApiClient {
constructor(apiConfig) {
this.baseURL = apiConfig.baseURL;
this.apiKey = apiConfig.apiKey;
this.model = apiConfig.model;
}
// 调用聊天完成API
async createChatCompletion(messages, options = {}) {
const response = await fetch(`${this.baseURL}/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: this.model,
messages: messages,
stream: options.stream || false,
max_tokens: options.maxTokens || 2000,
temperature: options.temperature || 0.7
})
});
return response;
}
}
```
### 缓存策略
#### LRU缓存配置
```javascript
const LRU = require('lru-cache');
const cache = new LRU({
max: 500, // 最大缓存条目数
maxAge: 1000 * 60 * 30 // 30分钟过期
});
// 缓存键策略
const getCacheKey = (conversationId, messageHash) => {
return `conv:${conversationId}:msg:${messageHash}`;
};
```
#### 缓存使用场景
1. **对话上下文缓存** - 缓存最近的对话上下文,减少数据库查询
2. **API响应缓存** - 对相同输入的LLM响应进行缓存
3. **用户会话缓存** - 缓存用户会话信息
### 中间件系统
#### 请求日志中间件
```javascript
const requestLogger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
next();
};
```
#### 错误处理中间件
```javascript
const errorHandler = (err, req, res, next) => {
console.error('Error:', err);
res.status(500).json({
error: 'Internal Server Error',
message: process.env.NODE_ENV === 'development' ? err.message : '服务器内部错误'
});
};
```
#### 速率限制中间件
```javascript
const rateLimit = require('express-rate-limit');
const chatRateLimit = rateLimit({
windowMs: 1 * 60 * 1000, // 1分钟
max: 20, // 限制每个IP每分钟最多20次请求
message: '请求过于频繁,请稍后再试'
});
```
## 项目结构
```
chat-website/
├── package.json
├── pnpm-workspace.yaml
├── README.md
├── .gitignore
├── frontend/
│ ├── package.json
│ ├── vite.config.js
│ ├── index.html
│ ├── src/
│ │ ├── main.js
│ │ ├── App.vue
│ │ ├── components/
│ │ │ ├── layout/
│ │ │ │ ├── Layout.vue
│ │ │ │ ├── Header.vue
│ │ │ │ └── Sidebar.vue
│ │ │ ├── chat/
│ │ │ │ ├── ChatView.vue
│ │ │ │ ├── MessageList.vue
│ │ │ │ ├── MessageItem.vue
│ │ │ │ ├── ChatInput.vue
│ │ │ │ └── TypingIndicator.vue
│ │ │ └── common/
│ │ │ ├── Loading.vue
│ │ │ └── ErrorMessage.vue
│ │ ├── stores/
│ │ │ ├── index.js
│ │ │ ├── chat.js
│ │ │ ├── conversation.js
│ │ │ └── user.js
│ │ ├── api/
│ │ │ ├── client.js
│ │ │ ├── chat.js
│ │ │ └── conversation.js
│ │ ├── router/
│ │ │ └── index.js
│ │ ├── styles/
│ │ │ ├── main.css
│ │ │ ├── variables.css
│ │ │ └── components.css
│ │ └── utils/
│ │ ├── helpers.js
│ │ └── constants.js
│ └── public/
│ └── favicon.ico
└── backend/
├── package.json
├── app.js
├── server.js
├── config/
│ ├── database.js
│ └── llm.js
├── routes/
│ ├── index.js
│ ├── chat.js
│ └── conversations.js
├── services/
│ ├── ConversationService.js
│ ├── ChatService.js
│ └── LLMApiClient.js
├── models/
│ ├── database.js
│ ├── Conversation.js
│ └── Message.js
├── middleware/
│ ├── auth.js
│ ├── rateLimit.js
│ ├── logger.js
│ └── errorHandler.js
├── utils/
│ ├── cache.js
│ └── helpers.js
└── database/
├── schema.sql
└── chat.db
```
## 测试策略
### 前端测试
#### 单元测试 (Vitest)
- 组件逻辑测试
- Store状态管理测试
- 工具函数测试
#### 组件测试 (Vue Test Utils)
- 组件渲染测试
- 用户交互测试
- Props和Events测试
#### E2E测试 (Playwright)
- 完整对话流程测试
- 跨浏览器兼容性测试
- 移动端响应式测试
### 后端测试
#### 单元测试 (Jest)
**API端点测试**
```javascript
describe('Chat API', () => {
test('should send message successfully', async () => {
const response = await request(app)
.post('/api/chat/send')
.send({
conversationId: 1,
message: '你好'
});
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('response');
});
});
```
**服务层测试**
```javascript
describe('ChatService', () => {
test('should process message correctly', async () => {
const chatService = new ChatService(mockApiClient, mockCache);
const result = await chatService.processMessage(1, '测试消息');
expect(result).toHaveProperty('userMessage');
expect(result).toHaveProperty('aiResponse');
});
});
```
#### 集成测试
- 数据库操作测试
- 第三方API集成测试
- 缓存机制测试
#### 性能测试
- API响应时间测试
- 并发请求处理测试
- 内存使用监控