# 前端项目任务拆分文档 (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 ``` 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% 用于调试和优化 --- **任务拆分完成,等待审批。**