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

939 lines
21 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.

# 前端项目任务拆分文档 (TASK)
## 任务名称
frontend-vue3
## 任务依赖图
```mermaid
graph TD
T1[T1: 初始化项目脚手架] --> T2[T2: 配置Axios客户端]
T2 --> T3[T3: 封装模型管理API]
T2 --> T4[T4: 封装知识库API]
T2 --> T5[T5: 封装对话API]
T2 --> T6[T6: 封装Agent API]
T1 --> T7[T7: 配置路由]
T7 --> T8[T8: 创建主布局]
T3 --> T9[T9: 实现模型管理页]
T4 --> T10[T10: 实现知识库管理页]
T5 --> T11[T11: 实现对话列表页]
T5 --> T12[T12: 实现聊天页面]
T6 --> T13[T13: 实现Agent执行页]
T8 --> T9
T8 --> T10
T8 --> T11
T8 --> T12
T8 --> T13
T9 --> T14[T14: 集成测试]
T10 --> T14
T11 --> T14
T12 --> T14
T13 --> T14
T14 --> T15[T15: 文档编写]
style T1 fill:#e1f5fe
style T2 fill:#fff3e0
style T7 fill:#f3e5f5
style T8 fill:#e8f5e9
style T14 fill:#ffebee
style T15 fill:#fff9c4
```
## 原子任务列表
### T1: 初始化项目脚手架
**优先级**: P0阻塞
**复杂度**: 低
**预估工时**: 30分钟
**输入契约**:
- 前置依赖: 无
- 输入数据: 项目根目录路径
- 环境依赖: Node.js 18+, npm/pnpm
**实现内容**:
1. 创建 `frontend/` 文件夹
2. 使用 Vite 初始化 Vue3 项目
3. 安装核心依赖:
```bash
npm create vite@latest frontend -- --template vue
cd frontend
npm install
npm install vue-router axios element-plus @element-plus/icons-vue
```
4. 配置 `vite.config.js`(别名 @、端口 5173
5. 创建目录结构:
```
src/
├── api/
├── components/
├── views/
├── router/
├── utils/
├── assets/
└── styles/
```
**输出契约**:
- 交付物: 可运行的 Vue3 项目骨架
- 验收标准: `npm run dev` 启动成功,访问 localhost:5173 显示默认页面
- 质量要求: 目录结构清晰,依赖版本锁定
**后置任务**: T2, T7
---
### T2: 配置Axios客户端
**优先级**: P0阻塞
**复杂度**: 中
**预估工时**: 1小时
**输入契约**:
- 前置依赖: T1
- 输入数据: API Base URL (环境变量)
- 环境依赖: Axios 已安装
**实现内容**:
1. 创建 `.env.development`:
```
VITE_API_BASE_URL=http://localhost:8000/api/v1
```
2. 创建 `src/api/client.js`:
```javascript
import axios from 'axios'
import { ElMessage } from 'element-plus'
const client = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 30000
})
// 请求拦截器
client.interceptors.request.use(config => {
return config
})
// 响应拦截器
client.interceptors.response.use(
response => response.data,
error => {
// 错误处理逻辑(详见设计文档)
return Promise.reject(error)
}
)
export default client
```
3. 创建 `src/utils/message.js`(封装 ElMessage
**输出契约**:
- 交付物: 配置完成的 Axios 实例
- 验收标准:
- 拦截器正确处理 4xx/5xx 错误
- 环境变量正确读取
- 网络错误显示提示
- 质量要求: 错误提示用户友好,支持详细错误信息
**后置任务**: T3, T4, T5, T6
---
### T3: 封装模型管理API
**优先级**: P1
**复杂度**: 低
**预估工时**: 30分钟
**输入契约**:
- 前置依赖: T2
- 接口文档: `/models` 相关接口
- 环境依赖: Axios client
**实现内容**:
创建 `src/api/models.js`:
```javascript
import client from './client'
export const modelAPI = {
list(type) {
return client.get('/models', { params: { type } })
},
create(data) {
return client.post('/models', data)
},
getById(id) {
return client.get(`/models/${id}`)
},
update(id, data) {
return client.patch(`/models/${id}`, data)
},
delete(id) {
return client.delete(`/models/${id}`)
}
}
```
**输出契约**:
- 交付物: 模型 API 封装模块
- 验收标准: 所有方法签名与设计文档一致
- 质量要求: 参数类型明确,返回 Promise
**后置任务**: T9
---
### T4: 封装知识库API
**优先级**: P1
**复杂度**: 低
**预估工时**: 30分钟
**输入契约**:
- 前置依赖: T2
- 接口文档: `/kb` 相关接口
**实现内容**:
创建 `src/api/kb.js`:
```javascript
import client from './client'
export const kbAPI = {
list() {
return client.get('/kb')
},
create(data) {
return client.post('/kb', data)
},
getById(id) {
return client.get(`/kb/${id}`)
},
delete(id) {
return client.delete(`/kb/${id}`)
},
ingest(id, data) {
return client.post(`/kb/${id}/ingest`, {
...data,
background: true // 固定为异步
})
},
query(id, data) {
return client.post(`/kb/${id}/query`, data)
},
getStatus(id) {
return client.get(`/kb/${id}/status`)
}
}
```
**输出契约**:
- 交付物: 知识库 API 封装模块
- 验收标准: 所有方法可正常调用
- 质量要求: ingest 方法固定 background=true
**后置任务**: T10
---
### T5: 封装对话API
**优先级**: P1
**复杂度**: 低
**预估工时**: 30分钟
**输入契约**:
- 前置依赖: T2
- 接口文档: `/conversations` 相关接口
**实现内容**:
创建 `src/api/conversations.js`:
```javascript
import client from './client'
export const conversationAPI = {
create(data) {
return client.post('/conversations', data)
},
getById(id) {
return client.get(`/conversations/${id}`)
},
delete(id) {
return client.delete(`/conversations/${id}`)
},
getMessages(id, params) {
return client.get(`/conversations/${id}/messages`, { params })
},
chat(id, data) {
return client.post(`/conversations/${id}/chat`, data)
}
}
```
**输出契约**:
- 交付物: 对话 API 封装模块
- 验收标准: 支持分页参数传递
- 质量要求: getMessages 方法正确处理 limit/offset
**后置任务**: T11, T12
---
### T6: 封装Agent API
**优先级**: P1
**复杂度**: 低
**预估工时**: 20分钟
**输入契约**:
- 前置依赖: T2
- 接口文档: `/agent` 相关接口
**实现内容**:
创建 `src/api/agent.js`:
```javascript
import client from './client'
export const agentAPI = {
execute(data) {
return client.post('/agent/execute', data)
},
getLogs(agentId, params) {
return client.get(`/agent/logs/${agentId}`, { params })
}
}
```
**输出契约**:
- 交付物: Agent API 封装模块
- 验收标准: 方法可正常调用
- 质量要求: 参数传递正确
**后置任务**: T13
---
### T7: 配置路由
**优先级**: P0阻塞
**复杂度**: 低
**预估工时**: 30分钟
**输入契约**:
- 前置依赖: T1
- 路由设计: 参考设计文档
**实现内容**:
1. 创建 `src/router/index.js`:
```javascript
import { createRouter, createWebHistory } from 'vue-router'
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') }
]
export default createRouter({
history: createWebHistory(),
routes
})
```
2.`main.js` 中注册路由
3.`App.vue` 中添加 `<router-view />`
**输出契约**:
- 交付物: 路由配置文件
- 验收标准: 路由可正常跳转(临时创建空白页面组件)
- 质量要求: 懒加载配置正确props 传递配置正确
**后置任务**: T8
---
### T8: 创建主布局
**优先级**: P0阻塞
**复杂度**: 中
**预估工时**: 1小时
**输入契约**:
- 前置依赖: T7
- 设计稿: 参考设计文档布局
**实现内容**:
1. 修改 `App.vue`:
```vue
<template>
<el-container style="height: 100vh">
<el-aside width="200px">
<el-menu :default-active="$route.path" router>
<el-menu-item index="/models">
<el-icon><Setting /></el-icon>
<span>模型管理</span>
</el-menu-item>
<el-menu-item index="/knowledge-base">
<el-icon><Document /></el-icon>
<span>知识库</span>
</el-menu-item>
<el-menu-item index="/conversations">
<el-icon><ChatDotRound /></el-icon>
<span>对话</span>
</el-menu-item>
<el-menu-item index="/agent">
<el-icon><Tools /></el-icon>
<span>Agent</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<router-view />
</el-main>
</el-container>
</template>
```
2.`main.js` 中引入 Element Plus 样式
3. 创建全局样式 `src/styles/global.css`
**输出契约**:
- 交付物: 主布局组件
- 验收标准:
- 左侧菜单可正常导航
- 当前路由高亮显示
- 响应式布局正常
- 质量要求: 样式简洁,图标清晰
**后置任务**: T9, T10, T11, T12, T13
---
### T9: 实现模型管理页
**优先级**: P1
**复杂度**: 中
**预估工时**: 2小时
**输入契约**:
- 前置依赖: T3, T8
- API: modelAPI
- UI 组件: Element Plus
**实现内容**:
创建 `src/views/Models.vue`:
1. 模型列表表格ID, 名称, 类型, 状态, 默认, 操作)
2. 类型筛选Select: 全部/LLM/Embedding
3. 创建模型弹窗表单name, type, config, is_default
4. 编辑功能复用表单PATCH 更新)
5. 删除确认ElMessageBox
6. 加载状态ElLoading
**核心逻辑**:
```javascript
const modelList = ref([])
const loading = ref(false)
const dialogVisible = ref(false)
const formData = ref({})
const typeFilter = ref('')
const fetchModels = async () => {
loading.value = true
try {
modelList.value = await modelAPI.list(typeFilter.value)
} finally {
loading.value = false
}
}
const handleCreate = async () => {
await formRef.value.validate()
await modelAPI.create(formData.value)
ElMessage.success('创建成功')
dialogVisible.value = false
fetchModels()
}
const handleDelete = async (id) => {
await ElMessageBox.confirm('确认删除?')
await modelAPI.delete(id)
ElMessage.success('删除成功')
fetchModels()
}
```
**输出契约**:
- 交付物: 模型管理页面组件
- 验收标准:
- CRUD 操作全部可用
- 表单验证正确
- 错误提示显示
- 质量要求: 用户体验流畅,代码结构清晰
**后置任务**: T14
---
### T10: 实现知识库管理页
**优先级**: P1
**复杂度**: 高
**预估工时**: 3小时
**输入契约**:
- 前置依赖: T4, T8
- API: kbAPI, modelAPI获取 embedding 列表)
**实现内容**:
创建 `src/views/KnowledgeBase.vue`:
1. 知识库列表ID, 名称, 描述, 文档数, 操作)
2. 创建知识库表单
3. **文档摄取弹窗**:
- 动态添加/删除文档行
- 每行title, content (textarea), source, metadata (JSON)
- Embedding 模型选择(从模型列表获取 type=embedding
- 提交后显示成功提示(不追踪状态)
4. **查询弹窗**:
- 查询文本输入
- k 值选择1-10
- Embedding 模型选择
- 结果展示(卡片形式,显示 content + score
5. 状态查看(显示文档数、索引状态)
6. 删除知识库
**核心逻辑**:
```javascript
const kbList = ref([])
const documents = ref([{ title: '', content: '', source: '', metadata: {} }])
const embeddingModels = ref([])
const queryResults = ref([])
const addDocument = () => {
documents.value.push({ title: '', content: '', source: '', metadata: {} })
}
const handleIngest = async () => {
await kbAPI.ingest(currentKbId.value, {
documents: documents.value,
embedding_name: selectedEmbedding.value
})
ElMessage.success('文档摄取任务已提交')
ingestDialogVisible.value = false
}
const handleQuery = async () => {
queryResults.value = await kbAPI.query(currentKbId.value, {
query: queryForm.value.query,
k: queryForm.value.k,
embedding_name: selectedEmbedding.value
})
}
```
**输出契约**:
- 交付物: 知识库管理页面组件
- 验收标准:
- 可动态添加多个文档
- 摄取提交成功显示提示
- 查询返回结果正确展示
- 状态信息准确显示
- 质量要求: 表单复杂但易用,查询结果清晰
**后置任务**: T14
---
### T11: 实现对话列表页
**优先级**: P1
**复杂度**: 低
**预估工时**: 1小时
**输入契约**:
- 前置依赖: T5, T8
- API: conversationAPI
**实现内容**:
创建 `src/views/Conversations.vue`:
1. 会话列表表格ID, 标题, 用户ID, 创建时间, 操作)
2. 创建会话表单user_id, title
3. "进入聊天"按钮(跳转到 `/conversations/:id/chat`
4. 删除会话(确认弹窗)
**核心逻辑**:
```javascript
const conversationList = ref([])
const fetchConversations = async () => {
conversationList.value = await conversationAPI.list()
}
const handleCreate = async () => {
const newConv = await conversationAPI.create(formData.value)
ElMessage.success('创建成功')
fetchConversations()
// 可选:自动跳转到聊天页
router.push(`/conversations/${newConv.id}/chat`)
}
const enterChat = (id) => {
router.push(`/conversations/${id}/chat`)
}
```
**输出契约**:
- 交付物: 对话列表页面组件
- 验收标准:
- 列表正确展示
- 创建会话成功
- 跳转聊天页正常
- 质量要求: 交互简洁明了
**后置任务**: T14
---
### T12: 实现聊天页面
**优先级**: P1
**复杂度**: 高
**预估工时**: 3小时
**输入契约**:
- 前置依赖: T5, T8
- API: conversationAPI, kbAPI, modelAPI
- 路由参数: conversation_id
**实现内容**:
创建 `src/views/Chat.vue`:
1. **顶部配置栏**:
- RAG 开关Switch
- 知识库选择(显示在 RAG 启用时)
- LLM 选择
2. **消息区域**:
- 消息列表(用户/助手气泡)
- 显示来源信息sources
- "加载更多"按钮(分页)
- 自动滚动到底部
3. **输入区域**:
- 文本输入框(支持 Enter 发送)
- 发送按钮
4. **分页加载逻辑**:
- 初始 limit=50, offset=0
- 点击"加载更多" offset+=50
**核心逻辑**:
```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 })
const loadMessages = async (loadMore = false) => {
const params = {
limit: pagination.value.limit,
offset: loadMore ? pagination.value.offset : 0
}
const newMessages = await conversationAPI.getMessages(conversationId.value, params)
if (loadMore) {
messages.value = [...newMessages, ...messages.value]
pagination.value.offset += pagination.value.limit
} else {
messages.value = newMessages
}
pagination.value.hasMore = newMessages.length === pagination.value.limit
}
const sendMessage = async () => {
const userMessage = { role: 'user', content: inputText.value }
messages.value.push(userMessage)
const response = await conversationAPI.chat(conversationId.value, {
user_input: inputText.value,
kb_id: useRag.value ? selectedKbId.value : null,
llm_name: selectedLlm.value,
use_rag: useRag.value
})
messages.value.push(response)
inputText.value = ''
scrollToBottom()
}
const scrollToBottom = () => {
nextTick(() => {
messageArea.value.scrollTop = messageArea.value.scrollHeight
})
}
```
**输出契约**:
- 交付物: 聊天页面组件
- 验收标准:
- 消息正确展示(用户/助手区分)
- 分页加载正常
- RAG 切换生效
- 来源信息显示
- 自动滚动到底部
- 质量要求: 聊天体验流畅UI 友好
**后置任务**: T14
---
### T13: 实现Agent执行页
**优先级**: P1
**复杂度**: 中
**预估工时**: 2小时
**输入契约**:
- 前置依赖: T6, T8
- API: agentAPI, kbAPI, modelAPI
**实现内容**:
创建 `src/views/Agent.vue`:
1. **任务输入区**:
- 任务描述Textarea
- 知识库选择(可选)
- LLM 选择
- 执行按钮
2. **结果展示区**:
- 执行状态(成功/失败)
- 输出结果Card 显示)
- Agent ID 展示
3. **日志展示区**(自动加载):
- 工具调用日志表格
- 列:工具名称、输入、输出、时间
- 支持展开查看详细 JSON
**核心逻辑**:
```javascript
const taskInput = ref('')
const selectedKbId = ref(null)
const selectedLlm = ref(null)
const executionResult = ref(null)
const toolCallLogs = ref([])
const executing = ref(false)
const handleExecute = async () => {
executing.value = true
try {
const result = await agentAPI.execute({
task: taskInput.value,
kb_id: selectedKbId.value,
llm_name: selectedLlm.value
})
executionResult.value = result
// 自动加载日志
if (result.agent_id) {
const logs = await agentAPI.getLogs(result.agent_id)
toolCallLogs.value = logs.tool_calls
}
} finally {
executing.value = false
}
}
```
**输出契约**:
- 交付物: Agent 执行页面组件
- 验收标准:
- 任务执行成功
- 结果正确展示
- 日志自动加载并显示
- 加载状态显示
- 质量要求: 日志信息清晰JSON 展示友好
**后置任务**: T14
---
### T14: 集成测试
**优先级**: P0
**复杂度**: 中
**预估工时**: 2小时
**输入契约**:
- 前置依赖: T9, T10, T11, T12, T13
- 环境依赖: 后端服务运行在 localhost:8000
**实现内容**:
1. **功能测试**:
- 创建 LLM 模型配置
- 创建 Embedding 模型配置
- 创建知识库
- 摄取测试文档
- 查询知识库
- 创建会话
- 发送消息(启用/禁用 RAG
- 执行 Agent 任务
- 查看 Agent 日志
2. **边界测试**:
- 表单验证(空值、格式错误)
- 网络错误处理(关闭后端)
- 404 错误(不存在的 ID
- 分页边界offset 超出范围)
3. **用户体验测试**:
- Loading 状态显示
- 成功/失败提示
- 路由跳转流畅
- 响应式布局
**测试清单**:
- [ ] 模型管理所有操作
- [ ] 知识库所有操作
- [ ] 对话所有操作
- [ ] Agent 执行和日志
- [ ] 错误场景处理
- [ ] 用户体验验证
**输出契约**:
- 交付物: 测试报告(记录在 ACCEPTANCE 文档)
- 验收标准: 所有核心流程通过
- 质量要求: 发现的问题及时修复
**后置任务**: T15
---
### T15: 文档编写
**优先级**: P1
**复杂度**: 低
**预估工时**: 1小时
**输入契约**:
- 前置依赖: T14
- 项目信息: package.json, 环境配置
**实现内容**:
1. 创建 `frontend/README.md`:
```markdown
# LangChain Learning Kit - 前端
## 技术栈
- Vue 3 + Vite
- Element Plus
- Axios + Vue Router
## 环境要求
- Node.js 18+
- npm 9+
## 快速开始
\`\`\`bash
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 构建生产包
npm run build
\`\`\`
## 环境配置
创建 `.env.development`:
\`\`\`
VITE_API_BASE_URL=http://localhost:8000/api/v1
\`\`\`
## 功能说明
- 模型管理:/models
- 知识库:/knowledge-base
- 对话:/conversations
- Agent/agent
## 注意事项
- 确保后端服务运行在 localhost:8000
- 浏览器访问 http://localhost:5173
```
2. 创建 `.env.example`:
```
VITE_API_BASE_URL=http://localhost:8000/api/v1
```
3. 更新 `.gitignore`:
```
.env.local
dist/
node_modules/
```
**输出契约**:
- 交付物: README.md, .env.example
- 验收标准: 文档清晰,新用户可按文档启动项目
- 质量要求: 说明完整,格式规范
**后置任务**: 无(最后任务)
---
## 任务执行顺序
### 第一批(并行)
- T1: 初始化项目脚手架
### 第二批(并行)
- T2: 配置 Axios 客户端
- T7: 配置路由
### 第三批(并行)
- T3: 封装模型管理 API
- T4: 封装知识库 API
- T5: 封装对话 API
- T6: 封装 Agent API
- T8: 创建主布局
### 第四批(并行)
- T9: 实现模型管理页
- T10: 实现知识库管理页
- T11: 实现对话列表页
- T12: 实现聊天页面
- T13: 实现 Agent 执行页
### 第五批(串行)
- T14: 集成测试
- T15: 文档编写
---
## 风险控制
### 任务风险
1. **T10 复杂度高**: 文档摄取多字段,可能需要更多时间
- 缓解:预留缓冲时间,优先实现核心功能
2. **T12 分页逻辑**: offset/limit 边界处理
- 缓解:参考设计文档,做好边界检查
3. **T14 后端依赖**: 需要后端服务正常运行
- 缓解:提前验证后端 API 可用性
### 时间风险
- **总预估工时**: 约 16 小时
- **建议工期**: 2-3 个工作日
- **缓冲时间**: 预留 20% 用于调试和优化
---
**任务拆分完成,等待审批。**