langchain-learning-kit/docs/frontend-vue3/DESIGN_frontend-vue3.md

667 lines
14 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.

# 前端项目架构设计文档 (DESIGN)
## 任务名称
frontend-vue3
## 整体架构图
```mermaid
graph TB
subgraph "前端应用 (Vue3)"
A[App.vue] --> B[Vue Router]
B --> C1[Models 模型管理]
B --> C2[KnowledgeBase 知识库]
B --> C3[Conversations 对话列表]
B --> C4[Chat 聊天页]
B --> C5[Agent 执行页]
C1 --> D1[API: models.js]
C2 --> D2[API: kb.js]
C3 --> D3[API: conversations.js]
C4 --> D3
C5 --> D4[API: agent.js]
D1 --> E[Axios Client]
D2 --> E
D3 --> E
D4 --> E
end
E -->|HTTP Request| F[FastAPI Backend<br/>:8000/api/v1]
subgraph "公共层"
G[Error Handler<br/>错误拦截器]
H[Loading State<br/>加载状态]
I[Message Tips<br/>消息提示]
end
E --> G
E --> H
E --> I
style A fill:#e1f5fe
style E fill:#fff3e0
style F fill:#f3e5f5
style G fill:#ffebee
style H fill:#e8f5e9
style I fill:#fff9c4
```
## 系统分层设计
### 1. 展示层 (Views)
**职责**: 页面渲染、用户交互、状态展示
**核心页面**:
- `Models.vue`: 模型管理页
- `KnowledgeBase.vue`: 知识库管理页
- `Conversations.vue`: 对话列表页
- `Chat.vue`: 聊天界面
- `Agent.vue`: Agent 执行页
**页面设计规范**:
- 使用 Composition API (`<script setup>`)
- 表单使用 Element Plus Form 组件
- 数据表格使用 ElTable
- 弹窗使用 ElDialog
### 2. 服务层 (API)
**职责**: 封装 HTTP 请求、数据转换、错误处理
**API 模块**:
```javascript
// src/api/client.js - Axios 实例
axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 30000,
headers: { 'Content-Type': 'application/json' }
})
// src/api/models.js - 模型管理
export const modelAPI = {
list(type?: string), // GET /models
create(data), // POST /models
getById(id), // GET /models/:id
update(id, data), // PATCH /models/:id
delete(id) // DELETE /models/:id
}
// src/api/kb.js - 知识库
export const kbAPI = {
list(), // GET /kb
create(data), // POST /kb
getById(id), // GET /kb/:id
delete(id), // DELETE /kb/:id
ingest(id, data), // POST /kb/:id/ingest
query(id, data), // POST /kb/:id/query
getStatus(id) // GET /kb/:id/status
}
// src/api/conversations.js - 对话
export const conversationAPI = {
create(data), // POST /conversations
getById(id), // GET /conversations/:id
delete(id), // DELETE /conversations/:id
getMessages(id, params), // GET /conversations/:id/messages
chat(id, data) // POST /conversations/:id/chat
}
// src/api/agent.js - Agent
export const agentAPI = {
execute(data), // POST /agent/execute
getLogs(agentId, params) // GET /agent/logs/:agent_id
}
```
### 3. 路由层 (Router)
**职责**: 页面导航、路由守卫、参数传递
**路由配置**:
```javascript
// src/router/index.js
const routes = [
{
path: '/',
redirect: '/models'
},
{
path: '/models',
name: 'Models',
component: () => import('@/views/Models.vue')
},
{
path: '/knowledge-base',
name: 'KnowledgeBase',
component: () => import('@/views/KnowledgeBase.vue')
},
{
path: '/conversations',
name: 'Conversations',
component: () => import('@/views/Conversations.vue')
},
{
path: '/conversations/:id/chat',
name: 'Chat',
component: () => import('@/views/Chat.vue'),
props: true
},
{
path: '/agent',
name: 'Agent',
component: () => import('@/views/Agent.vue')
}
]
```
### 4. 工具层 (Utils)
**职责**: 通用函数、常量定义、辅助工具
**工具模块**:
```javascript
// src/utils/request.js - 请求拦截器
// src/utils/message.js - 消息提示封装
// src/utils/validator.js - 表单验证规则
// src/utils/constants.js - 常量定义
```
## 核心组件设计
### Component 1: Models.vue (模型管理)
**功能模块**:
1. 模型列表展示(表格)
2. 类型筛选LLM / Embedding
3. 创建模型弹窗
4. 编辑/删除操作
5. 设置默认模型
**数据流**:
```mermaid
sequenceDiagram
participant U as User
participant V as Models.vue
participant API as modelAPI
participant B as Backend
U->>V: 访问页面
V->>API: modelAPI.list()
API->>B: GET /models
B-->>API: 模型列表
API-->>V: 渲染表格
U->>V: 点击"创建模型"
V->>V: 打开表单弹窗
U->>V: 填写表单并提交
V->>API: modelAPI.create(data)
API->>B: POST /models
B-->>API: 创建成功
API-->>V: 更新列表
V->>U: 提示成功
```
**核心状态**:
```javascript
const modelList = ref([])
const loading = ref(false)
const dialogVisible = ref(false)
const formData = ref({
name: '',
type: 'llm',
config: {},
is_default: false
})
const typeFilter = ref('')
```
### Component 2: KnowledgeBase.vue (知识库管理)
**功能模块**:
1. 知识库列表
2. 创建知识库
3. 文档摄取(多文档输入)
4. 向量查询
5. 状态查看(文档数、索引状态)
6. 删除知识库
**文档摄取界面**:
- 支持动态添加多个文档
- 每个文档包含title, content, source, metadata
- 选择 embedding 模型
- 提交后显示成功(不追踪状态)
**查询界面**:
- 输入查询文本
- 选择 k 值(返回数量)
- 展示结果列表content + score
**核心状态**:
```javascript
const kbList = ref([])
const currentKb = ref(null)
const ingestDialogVisible = ref(false)
const queryDialogVisible = ref(false)
const documents = ref([{ title: '', content: '', source: '', metadata: {} }])
const queryForm = ref({ query: '', k: 3 })
const queryResults = ref([])
```
### Component 3: Conversations.vue (对话列表)
**功能模块**:
1. 会话列表展示
2. 创建新会话user_id + title
3. 跳转到聊天页
4. 删除会话
**核心状态**:
```javascript
const conversationList = ref([])
const createDialogVisible = ref(false)
const newConversation = ref({ user_id: 1, title: '' })
```
### Component 4: Chat.vue (聊天界面)
**功能模块**:
1. 消息历史展示(分页加载)
2. 发送消息
3. RAG 开关
4. 选择知识库和 LLM
5. 显示来源sources
**分页加载策略**:
- 初始加载: limit=50, offset=0
- "加载更多"按钮: offset += 50
- 消息逆序展示(最新在下)
**消息展示**:
```vue
<div class="message-list">
<div v-for="msg in messages" :key="msg.id" :class="msg.role">
<div class="content">{{ msg.content }}</div>
<div v-if="msg.msg_metadata?.sources" class="sources">
来源: {{ msg.msg_metadata.sources }}
</div>
</div>
</div>
```
**核心状态**:
```javascript
const conversationId = ref(route.params.id)
const messages = ref([])
const inputText = ref('')
const useRag = ref(true)
const selectedKbId = ref(null)
const selectedLlm = ref(null)
const pagination = ref({ limit: 50, offset: 0, hasMore: true })
```
### Component 5: Agent.vue (Agent 执行)
**功能模块**:
1. 任务输入
2. 选择知识库(可选)
3. 选择 LLM
4. 执行结果展示
5. 工具调用日志(自动展示)
**执行流程**:
```mermaid
sequenceDiagram
participant U as User
participant V as Agent.vue
participant API as agentAPI
participant B as Backend
U->>V: 输入任务并提交
V->>API: agentAPI.execute(data)
API->>B: POST /agent/execute
B-->>API: { agent_id, output, success }
API-->>V: 展示结果
V->>API: agentAPI.getLogs(agent_id)
API->>B: GET /agent/logs/:agent_id
B-->>API: { tool_calls: [...] }
API-->>V: 展示日志表格
```
**核心状态**:
```javascript
const taskInput = ref('')
const selectedKbId = ref(null)
const selectedLlm = ref(null)
const executionResult = ref(null)
const toolCallLogs = ref([])
const executing = ref(false)
```
## 接口契约定义
### Request 数据结构
**创建模型**:
```typescript
interface CreateModelRequest {
name: string
type: 'llm' | 'embedding'
config: Record<string, any>
is_default?: boolean
}
```
**文档摄取**:
```typescript
interface IngestRequest {
documents: Array<{
content: string
title?: string
source?: string
metadata?: Record<string, any>
}>
embedding_name: string
background?: boolean // 固定为 true
}
```
**发送消息**:
```typescript
interface ChatRequest {
user_input: string
kb_id?: number
llm_name?: string
use_rag?: boolean
}
```
**执行 Agent**:
```typescript
interface AgentExecuteRequest {
task: string
kb_id?: number
llm_name?: string
}
```
### Response 数据结构
**模型列表**:
```typescript
interface ModelResponse {
id: number
name: string
type: 'llm' | 'embedding'
config: Record<string, any>
is_default: boolean
status: string
created_at: string
}
```
**查询结果**:
```typescript
interface QueryResponse {
results: Array<{
content: string
metadata: Record<string, any>
score: number
}>
result_count: number
}
```
**消息响应**:
```typescript
interface MessageResponse {
message_id: number
conversation_id: number
role: 'user' | 'assistant'
content: string
metadata?: {
sources?: Array<{ title: string, source: string }>
model?: string
}
}
```
**Agent 日志**:
```typescript
interface ToolCallLog {
id: number
agent_id: string
tool_name: string
call_input: Record<string, any>
call_output: Record<string, any>
created_at: string
}
```
## 异常处理策略
### HTTP 错误拦截
**Axios Response Interceptor**:
```javascript
// src/api/client.js
axios.interceptors.response.use(
response => response.data,
error => {
const { response } = error
if (!response) {
ElMessage.error('网络连接失败,请检查网络')
return Promise.reject(error)
}
const { status, data } = response
const message = data?.detail || '请求失败'
switch (status) {
case 400:
ElMessage.error(`请求错误: ${message}`)
break
case 404:
ElMessage.error(`资源不存在: ${message}`)
break
case 500:
ElMessage.error(`服务器错误: ${message}`)
break
default:
ElMessage.error(`错误 ${status}: ${message}`)
}
return Promise.reject(error)
}
)
```
### 表单验证规则
**Element Plus Rules**:
```javascript
// src/utils/validator.js
export const modelRules = {
name: [
{ required: true, message: '请输入模型名称', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择模型类型', trigger: 'change' }
]
}
export const kbRules = {
name: [
{ required: true, message: '请输入知识库名称', trigger: 'blur' }
]
}
export const chatRules = {
user_input: [
{ required: true, message: '请输入消息内容', trigger: 'blur' }
]
}
```
### 加载状态管理
**统一 Loading 处理**:
```javascript
// 组件内使用
const loading = ref(false)
const fetchData = async () => {
loading.value = true
try {
const data = await modelAPI.list()
// 处理数据
} catch (error) {
// 错误已被拦截器处理
} finally {
loading.value = false
}
}
```
## 数据流向图
### 对话流程数据流
```mermaid
flowchart LR
A[用户输入消息] --> B{是否启用RAG?}
B -->|是| C[选择知识库]
B -->|否| D[直接发送]
C --> E[构造请求]
D --> E
E --> F[POST /conversations/:id/chat]
F --> G{请求成功?}
G -->|是| H[追加消息到列表]
G -->|否| I[显示错误]
H --> J[滚动到底部]
I --> K[用户重试]
```
### Agent 执行数据流
```mermaid
flowchart TB
A[输入任务] --> B[选择配置]
B --> C[POST /agent/execute]
C --> D{执行成功?}
D -->|是| E[显示输出]
D -->|否| F[显示错误]
E --> G[GET /agent/logs/:agent_id]
G --> H[展示工具调用日志]
H --> I[用户查看详情]
```
## 布局设计
### 主布局结构
```vue
<!-- App.vue -->
<el-container>
<el-aside width="200px">
<el-menu router>
<el-menu-item index="/models">模型管理</el-menu-item>
<el-menu-item index="/knowledge-base">知识库</el-menu-item>
<el-menu-item index="/conversations">对话</el-menu-item>
<el-menu-item index="/agent">Agent</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<router-view />
</el-main>
</el-container>
```
### 聊天页布局
```vue
<!-- Chat.vue -->
<el-container direction="vertical">
<el-header>
<div class="chat-config">
<el-switch v-model="useRag" label="启用RAG" />
<el-select v-model="selectedKbId" v-if="useRag">...</el-select>
<el-select v-model="selectedLlm">...</el-select>
</div>
</el-header>
<el-main class="message-area">
<el-button @click="loadMore" v-if="hasMore">加载更多</el-button>
<div v-for="msg in messages" :key="msg.id">...</div>
</el-main>
<el-footer>
<el-input v-model="inputText" @keyup.enter="sendMessage" />
<el-button @click="sendMessage">发送</el-button>
</el-footer>
</el-container>
```
## 环境配置
### 开发环境
```bash
# .env.development
VITE_API_BASE_URL=http://localhost:8000/api/v1
```
### 生产环境
```bash
# .env.production
VITE_API_BASE_URL=https://your-production-domain.com/api/v1
```
### Vite 配置
```javascript
// vite.config.js
export default defineConfig({
plugins: [vue()],
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true
}
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
```
## 依赖管理
### 核心依赖
```json
{
"dependencies": {
"vue": "^3.4.0",
"vue-router": "^4.2.5",
"axios": "^1.6.2",
"element-plus": "^2.5.0",
"@element-plus/icons-vue": "^2.3.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.0",
"vite": "^5.0.0"
}
}
```
## 设计原则总结
1. **单一职责**: 每个组件只负责一个功能模块
2. **API 封装**: 所有 HTTP 请求集中在 `src/api/`
3. **错误优先**: 统一拦截器 + 详细提示
4. **用户体验**: Loading 状态 + 操作反馈
5. **可维护性**: 清晰的目录结构 + 模块化设计
---
**架构设计完成,进入任务拆分阶段。**