# 前端项目任务拆分文档 (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` 中添加 ``
**输出契约**:
- 交付物: 路由配置文件
- 验收标准: 路由可正常跳转(临时创建空白页面组件)
- 质量要求: 懒加载配置正确,props 传递配置正确
**后置任务**: T8
---
### T8: 创建主布局
**优先级**: P0(阻塞)
**复杂度**: 中
**预估工时**: 1小时
**输入契约**:
- 前置依赖: T7
- 设计稿: 参考设计文档布局
**实现内容**:
1. 修改 `App.vue`:
```vue
模型管理
知识库
对话
Agent
```
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% 用于调试和优化
---
**任务拆分完成,等待审批。**