# Day 25:智能问答功能完成 ✅ **开发时间**: Day 25 **开发人员**: AI助手 **任务状态**: ✅ 已完成 --- ## 📋 任务概述 实现无项目、无智能体概念的纯AI对话功能,支持可选的@知识库引用。用户可以像在ChatGPT官网一样自由对话,同时可以通过@知识库引用个人文献获得更精准的回答。 --- ## ✅ 已完成功能 ### 1. 数据库Schema扩展 **文件**: `backend/prisma/schema.prisma` 新增两个数据表: #### GeneralConversation(通用对话表) ```prisma model GeneralConversation { id String @id @default(uuid()) userId String @map("user_id") title String modelName String? @map("model_name") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @default(now()) @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) messages GeneralMessage[] } ``` #### GeneralMessage(通用消息表) ```prisma model GeneralMessage { id String @id @default(uuid()) conversationId String @map("conversation_id") role String content String @db.Text model String? metadata Json? tokens Int? createdAt DateTime @default(now()) @map("created_at") conversation GeneralConversation @relation(...) } ``` **特点**: - ✅ 与项目对话完全独立 - ✅ 不依赖智能体配置 - ✅ 支持元数据存储(如知识库IDs) --- ### 2. 后端API实现 **文件**: `backend/src/controllers/chatController.ts` #### API接口列表 | 接口 | 方法 | 功能 | 参数 | |------|------|------|------| | `/api/v1/chat/stream` | POST | 发送消息(流式) | content, modelType, knowledgeBaseIds?, conversationId? | | `/api/v1/chat/conversations` | GET | 获取对话列表 | - | | `/api/v1/chat/conversations/:id` | DELETE | 删除对话 | id | #### 核心实现逻辑 ```typescript async sendMessageStream(request, reply) { // 1. 获取或创建对话(无需项目/智能体) if (conversationId) { // 续接已有对话 } else { // 创建新对话 conversation = await prisma.generalConversation.create({ userId, title: content.substring(0, 50), modelName: modelType, }); } // 2. 检索知识库(如果有) if (knowledgeBaseIds && knowledgeBaseIds.length > 0) { for (const kbId of knowledgeBaseIds) { const searchResult = await knowledgeBaseService.searchKnowledgeBase( userId, kbId, content, 3 ); // 格式化检索结果 knowledgeBaseContext += formatResults(searchResult); } } // 3. 组装上下文(极简) const messages = [ { role: 'system', content: '你是一个专业、友好的AI助手...' }, ...historyMessages, // 最近20条 { role: 'user', content: knowledgeBaseContext ? `${content}\n\n## 参考资料\n${knowledgeBaseContext}` : content } ]; // 4. 流式调用LLM for await (const chunk of adapter.chatStream(messages)) { reply.raw.write(`data: ${JSON.stringify(chunk)}\n\n`); } // 5. 保存消息到数据库 } ``` **特点**: - ✅ 无需agentId和projectId - ✅ 自动管理对话历史 - ✅ 集成知识库检索 - ✅ 极简的System Prompt --- ### 3. 前端页面实现 **文件**: `frontend/src/pages/ChatPage.tsx` **核心特性**: - ✅ 完全独立的对话页面 - ✅ 复用现有组件(MessageList, MessageInput, ModelSelector) - ✅ 支持@知识库功能 - ✅ 自动创建和续接对话 **页面结构**: ```tsx
💬 智能问答 | [模型选择器]
{messages.length === 0 ? ( 💬 与AI自由对话 直接提问,或使用@知识库引用文献 ) : ( )} sendMessage(...)} />
``` --- ### 4. 前端API封装 **文件**: `frontend/src/api/chatApi.ts` **接口方法**: ```typescript // 发送消息(流式) sendMessageStream( data: { content: string, modelType: string, knowledgeBaseIds?: string[], conversationId?: string }, onChunk: (content) => void, onComplete: (conversationId) => void, onError: (error) => void ) // 获取对话列表 getConversations(): Promise // 删除对话 deleteConversation(id: string): Promise ``` --- ### 5. 路由和导航 **修改文件**: - `frontend/src/App.tsx` - 添加 `/chat` 路由 - `frontend/src/layouts/MainLayout.tsx` - 添加"智能问答"菜单项 **导航顺序**: 1. 🏠 首页 2. 💬 **智能问答** ⭐ 新增 3. 🧪 智能体 4. 📁 知识库管理 5. 📜 历史记录 --- ## 🔄 完整工作流程 ### 场景1:纯对话(无知识库) ``` 用户访问 /chat ↓ 空白对话界面 ↓ 输入:"介绍一下自己" ↓ [后端] 创建新对话 ↓ [后端] 组装上下文: - System Prompt: "你是一个专业的AI助手" - User: "介绍一下自己" ↓ [LLM] DeepSeek-V3 回答 ↓ [前端] 流式显示回答 ``` ### 场景2:基于知识库对话 ``` 用户访问 /chat ↓ 点击 @知识库 → 选择"骨质疏松知识库" ↓ 输入:"这个知识库讲的是什么?" ↓ [后端] 调用Dify检索API ↓ [后端] 检索到3条相关文档片段 ↓ [后端] 组装上下文: - System Prompt - User: "这个知识库讲的是什么?" - 参考资料: 【知识库:骨质疏松知识库】... ↓ [LLM] 基于文档内容回答 ↓ [前端] 显示基于文献的精准回答 ``` --- ## 🎯 技术亮点 ### 1. 极简架构 - 无需项目背景 - 无需智能体配置 - 直达核心:用户 ↔ AI ↔ 知识库 ### 2. 灵活的知识库集成 - 完全可选(不@知识库 = 纯对话) - 多知识库支持(同时选择多个) - 实时检索(每次发送时检索最新内容) ### 3. 代码复用率高 - ✅ 复用 MessageList 组件 - ✅ 复用 MessageInput 组件 - ✅ 复用 ModelSelector 组件 - ✅ 复用 knowledgeBaseService - ✅ 复用 LLM适配器 ### 4. 独立的数据隔离 - 通用对话存储在独立的表 - 不影响项目对话数据 - 便于后续统计和分析 --- ## 📊 数据流示例 **请求示例**: ```json POST /api/v1/chat/stream { "content": "这个知识库讲的是什么?", "modelType": "deepseek-v3", "knowledgeBaseIds": ["7d1e08ae-7a40-4e62-8654-bb631dc47293"] } ``` **知识库检索**: ``` 🔍 检索 → Dify API ↓ 返回3条记录(相关度50.8%, 46.3%, 43.9%) ↓ 格式化: 【知识库:骨质疏松知识库】 1. [相关度50.8%] 文档上传与处理:支持在知识库... 2. [相关度46.3%] AI科研助手产品需求文档(PRD) 3. [相关度43.9%] 知识库融合对话功能... ``` **发送给LLM**: ``` System: 你是一个专业、友好的AI助手... User: 这个知识库讲的是什么? ## 参考资料(来自知识库) 【知识库:骨质疏松知识库】 1. [相关度50.8%] 文档上传与处理... ... ``` **AI回答**: ``` 根据您的知识库内容,这是一份关于"AI科研助手"的产品需求文档(PRD)。 主要内容包括: 1. 文档管理功能... 2. 知识库融合对话功能... ... 【文献来源】骨质疏松知识库 ``` --- ## 🐛 已知问题 ### 1. 问题描述不当导致检索质量差 **现象**:问"这个文档里有什么?"检索到的内容相关度低 **原因**: - 问题太宽泛,语义模糊 - Dify检索需要具体的关键词或概念 **建议**: - 使用具体问题:"骨质疏松的治疗方法有哪些?" - 使用文档中的关键词提问 ### 2. 英文文档 vs 中文问题 **现象**:阿尔兹海默症知识库检索到英文片段 **原因**: - 文档是英文的 - 中文问题匹配度相对较低 **建议**: - 使用英文提问 - 或者在问题中包含文档中的专业术语 --- ## 📁 涉及文件清单 ### 后端新增 - `backend/src/controllers/chatController.ts` - 通用对话Controller - `backend/src/routes/chatRoutes.ts` - 通用对话路由 - `backend/prisma/schema.prisma` - 新增通用对话表 - `backend/migrations/add_general_chat.sql` - 数据库迁移SQL ### 后端修改 - `backend/src/index.ts` - 注册chatRoutes ### 前端新增 - `frontend/src/pages/ChatPage.tsx` - 智能问答页面 - `frontend/src/api/chatApi.ts` - 通用对话API封装 ### 前端修改 - `frontend/src/App.tsx` - 添加 /chat 路由 - `frontend/src/layouts/MainLayout.tsx` - 添加"智能问答"菜单项 --- ## 🧪 测试验证 ### ✅ 已验证功能 1. **纯对话功能** - ✅ 无需项目/智能体 - ✅ 直接与AI对话 - ✅ 流式输出正常 - ✅ 模型切换正常 2. **@知识库功能** - ✅ 下拉菜单选择知识库 - ✅ 检索功能正常(调用Dify API) - ✅ 知识库内容成功注入到AI上下文 - ✅ AI基于知识库内容回答 3. **对话历史** - ✅ 自动创建对话 - ✅ 续接已有对话 - ✅ 上下文连贯(最近20条消息) --- ## 🎯 关键技术实现 ### 1. 无依赖的对话架构 **传统模式(项目对话)**: ``` 用户 → 选择项目 → 选择智能体 → 对话 依赖:projectId + agentId ``` **智能问答模式**: ``` 用户 → 对话 依赖:无 ``` ### 2. 知识库检索集成 ```typescript // 检索知识库 if (knowledgeBaseIds && knowledgeBaseIds.length > 0) { for (const kbId of knowledgeBaseIds) { const searchResult = await knowledgeBaseService.searchKnowledgeBase( userId, kbId, content, 3 ); // 格式化并追加到上下文 } } // 组装最终Prompt const userContent = knowledgeBaseContext ? `${content}\n\n## 参考资料(来自知识库)\n${knowledgeBaseContext}` : content; ``` ### 3. 对话续接机制 **首次发送**: ```json { "content": "你好", "modelType": "deepseek-v3" } → 创建新对话,返回 conversationId ``` **后续发送**: ```json { "content": "继续聊", "modelType": "deepseek-v3", "conversationId": "xxx" } → 续接对话,加载历史消息 ``` --- ## 💡 设计亮点 ### 1. 用户体验优化 **问题**:传统智能体模式需要选择项目和智能体,流程复杂 **解决**:智能问答直达对话,0步骤开始 **问题**:用户可能不知道如何使用知识库 **解决**:@知识库完全可选,不影响基础使用 ### 2. 架构清晰性 ``` 应用架构: ┌─────────────────────────┐ │ 项目-智能体模式 │ │ - 结构化的研究流程 │ │ - 专业领域AI │ │ - 项目背景上下文 │ └─────────────────────────┘ ┌─────────────────────────┐ │ 智能问答模式 │ │ - 自由对话 │ │ - 通用AI助手 │ │ - 可选知识库辅助 │ └─────────────────────────┘ ``` 两种模式互不干扰,满足不同场景需求。 ### 3. 代码复用率 **新增代码**:~400行 **复用代码**:~2000行(组件、服务、适配器) **复用率**:83% --- ## 📝 用户使用指南 ### 快速开始 1. 访问 `http://localhost:3000` 2. 点击左侧导航"💬 智能问答" 3. 输入问题,开始对话 ### 使用@知识库 1. 点击输入框下方的"@知识库"按钮 2. 选择一个或多个知识库 3. 输入问题(建议具体问题,如:"治疗方法有哪些?") 4. 点击发送 5. AI会基于知识库内容回答 ### 最佳实践 **✅ 推荐的问题类型**: - 具体问题:"骨质疏松的病因是什么?" - 概念解释:"什么是阿尔兹海默症?" - 信息提取:"文献中提到了哪些治疗方法?" **❌ 不推荐的问题**: - 太宽泛:"这个文档有什么?"(检索效果差) - 无关问题:"今天天气怎么样?"(浪费检索资源) --- ## 🔗 与Day 23-24的关系 **Day 23-24**:在项目智能体对话中实现@知识库 - ✅ 功能完整 - ⚠️ 但受限于智能体角色(如"选题评价"会忽略知识库内容) **Day 25**:独立的智能问答 - ✅ 无角色限制 - ✅ 专注于基于知识库回答问题 - ✅ 提供最纯粹的测试环境 --- ## 🎉 里程碑1 - 100%完成! ### 核心功能清单 1. ✅ 用户认证与项目管理 2. ✅ 12个AI智能体配置与调用 3. ✅ 多轮对话上下文管理 4. ✅ 流式输出(打字机效果) 5. ✅ 模型切换(DeepSeek-V3/Qwen3/Gemini) 6. ✅ 个人知识库管理 7. ✅ @知识库检索与RAG集成(Day 23-24) 8. ✅ **智能问答功能**(Day 25)⭐ 今日完成 --- ## 🚀 下一步规划 ### 里程碑2预览(预计3-4天) 1. **对话历史增强** - 对话列表展示 - 搜索和筛选 - 导出为Markdown 2. **引用溯源优化** - 点击引用查看原文 - 高亮显示相关片段 - 文档来源追踪 3. **项目协作功能** - 成员管理 - 权限控制 - 共享知识库 --- ## 📊 技术收获 ### 1. 架构设计 - 通过"通用对话"补充"项目对话"的不足 - 两种模式并存,互不干扰 - 代码高度复用 ### 2. API设计 - RESTful风格 - 可选参数灵活性(conversationId?, knowledgeBaseIds?) - 流式输出性能优化 ### 3. 前端组件化 - MessageList、MessageInput高度解耦 - 易于在不同场景复用 - Props设计合理 --- **文档创建时间**: 2025-10-11 **最后更新**: 2025-10-11