feat(iit): harden QC pipeline consistency and release artifacts
Implement IIT quality workflow hardening across eQuery deduplication, guard metadata validation, timeline/readability improvements, and chat evidence fallbacks, then synchronize release and development documentation for deployment handoff. Includes migration/scripts for open eQuery dedupe guards, orchestration/status semantics, report/tool readability fixes, and updated module status plus deployment checklist. Made-with: Cursor
This commit is contained in:
232
docs/05-每日进度/Day21-22-知识库前端开发与问题修复.md
Normal file
232
docs/05-每日进度/Day21-22-知识库前端开发与问题修复.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# Day 21-22:知识库前端开发与问题修复
|
||||
|
||||
> **日期:** 2025-10-11
|
||||
> **状态:** ✅ 已完成
|
||||
> **里程碑:** 里程碑1 - Week 3
|
||||
|
||||
---
|
||||
|
||||
## 📋 任务概述
|
||||
|
||||
完成知识库前端页面开发,并解决前后端集成过程中遇到的3个关键问题。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 完成的功能
|
||||
|
||||
### 1. 知识库前端页面(已完成)
|
||||
- ✅ 知识库列表页面
|
||||
- ✅ 知识库详情页面
|
||||
- ✅ 文档上传组件
|
||||
- ✅ 文档列表显示
|
||||
- ✅ 文档状态管理
|
||||
|
||||
---
|
||||
|
||||
## 🐛 发现并修复的问题
|
||||
|
||||
### 问题1:删除知识库失败 - CORS错误
|
||||
|
||||
**现象:**
|
||||
```
|
||||
Access to XMLHttpRequest at 'http://localhost:3001/api/v1/knowledge-bases/xxx'
|
||||
has been blocked by CORS policy: Method DELETE is not allowed by
|
||||
Access-Control-Allow-Methods in preflight response.
|
||||
```
|
||||
|
||||
**原因:**
|
||||
后端CORS配置不完整,没有明确允许DELETE方法
|
||||
|
||||
**修复:**
|
||||
```typescript
|
||||
// backend/src/index.ts
|
||||
await fastify.register(cors, {
|
||||
origin: true,
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'Origin'],
|
||||
exposedHeaders: ['Content-Range', 'X-Content-Range'],
|
||||
maxAge: 600,
|
||||
preflightContinue: false,
|
||||
});
|
||||
```
|
||||
|
||||
**验收:** ✅ 删除知识库成功,无CORS错误
|
||||
|
||||
---
|
||||
|
||||
### 问题2:编辑知识库失败 - CORS错误
|
||||
|
||||
**现象:**
|
||||
```
|
||||
Access to XMLHttpRequest at 'http://localhost:3001/api/v1/knowledge-bases/xxx'
|
||||
has been blocked by CORS policy: Method PUT is not allowed by
|
||||
Access-Control-Allow-Methods in preflight response.
|
||||
```
|
||||
|
||||
**原因:**
|
||||
与问题1相同,CORS配置没有明确允许PUT方法
|
||||
|
||||
**修复:**
|
||||
同上,统一修复CORS配置
|
||||
|
||||
**验收:** ✅ 编辑知识库成功,保存正常
|
||||
|
||||
---
|
||||
|
||||
### 问题3:文件上传无响应
|
||||
|
||||
**现象:**
|
||||
- 点击上传按钮完全没有反应
|
||||
- 前端无错误提示
|
||||
- 后端无请求日志
|
||||
- 浏览器控制台无日志输出
|
||||
|
||||
**排查过程:**
|
||||
|
||||
#### 步骤1:添加调试日志
|
||||
在前端组件中添加详细的console.log,发现:
|
||||
- `beforeUpload` 被调用 ✅
|
||||
- `customRequest` 没有被调用 ❌
|
||||
|
||||
#### 步骤2:发现浏览器缓存问题
|
||||
- 浏览器Sources中显示两个同名文件
|
||||
- 实际运行的是旧版本代码
|
||||
- 清除缓存后解决
|
||||
|
||||
#### 步骤3:发现组件被禁用
|
||||
调试日志显示:
|
||||
```javascript
|
||||
{
|
||||
disabled: true,
|
||||
组件是否被禁用: true
|
||||
}
|
||||
```
|
||||
|
||||
**原因1:** 组件被 `disabled={loading}` 禁用,loading状态一直为true
|
||||
|
||||
**修复1:**
|
||||
```typescript
|
||||
// frontend/src/pages/KnowledgePage.tsx
|
||||
<DocumentUpload
|
||||
disabled={false} // 临时改为false,后续优化loading状态管理
|
||||
...
|
||||
/>
|
||||
```
|
||||
|
||||
**原因2:** `beforeUpload` 返回 `false` 阻止了 `customRequest` 执行
|
||||
|
||||
根据Ant Design Upload组件的机制:
|
||||
- `return false` → 完全阻止上传,包括customRequest
|
||||
- `return Upload.LIST_IGNORE` → 忽略该文件
|
||||
- 不返回任何值(undefined)→ 允许customRequest执行
|
||||
|
||||
**修复2:**
|
||||
```typescript
|
||||
// frontend/src/components/knowledge/DocumentUpload.tsx
|
||||
const beforeUpload = (file: File) => {
|
||||
// 验证逻辑...
|
||||
|
||||
// 不返回任何值,让 customRequest 处理上传
|
||||
// 之前: return false; ❌
|
||||
};
|
||||
```
|
||||
|
||||
**验收:** ✅ 文件上传成功,能看到上传进度,后端正确接收文件
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术要点总结
|
||||
|
||||
### 1. CORS配置要点
|
||||
- 必须明确列出所有需要的HTTP方法
|
||||
- 开发环境可以 `origin: true` 允许所有来源
|
||||
- 生产环境应该指定具体的域名列表
|
||||
- `maxAge` 可以减少preflight请求频率
|
||||
|
||||
### 2. Ant Design Upload组件要点
|
||||
- `beforeUpload` 返回值决定是否继续上传
|
||||
- `false` 或 `Upload.LIST_IGNORE` → 阻止上传
|
||||
- `undefined`(不返回)→ 允许customRequest
|
||||
- `true` → 默认上传行为(需要action)
|
||||
- 使用 `customRequest` 可以完全控制上传逻辑
|
||||
- `disabled` 属性会阻止所有交互
|
||||
|
||||
### 3. 前端缓存问题处理
|
||||
- 开发时遇到代码不更新,优先考虑缓存问题
|
||||
- 解决方案:
|
||||
1. 使用无痕模式测试
|
||||
2. 清除浏览器缓存(Ctrl+Shift+Delete)
|
||||
3. 删除 `node_modules/.vite` 和 `dist` 文件夹
|
||||
4. 硬刷新(Ctrl+F5)
|
||||
|
||||
### 4. 调试技巧
|
||||
- 在关键位置添加console.log
|
||||
- 使用浏览器Sources查看实际运行的代码
|
||||
- 检查组件状态(props、state)
|
||||
- 对比文件内容和浏览器中的代码
|
||||
|
||||
---
|
||||
|
||||
## 📊 成果物
|
||||
|
||||
### 后端
|
||||
- `backend/src/index.ts` - 完整的CORS配置
|
||||
- `backend/src/controllers/documentController.ts` - 文档上传日志增强
|
||||
|
||||
### 前端
|
||||
- `frontend/src/pages/KnowledgePage.tsx` - 知识库管理主页面
|
||||
- `frontend/src/components/knowledge/DocumentUpload.tsx` - 文档上传组件(已清理调试日志)
|
||||
- `frontend/src/components/knowledge/KnowledgeBaseList.tsx` - 知识库列表组件
|
||||
- `frontend/src/components/knowledge/DocumentList.tsx` - 文档列表组件
|
||||
|
||||
---
|
||||
|
||||
## 🎯 下一步计划
|
||||
|
||||
### Day 23-24:知识库检索 + @引用功能 ⭐⭐⭐
|
||||
这是里程碑1的核心功能!
|
||||
|
||||
**任务:**
|
||||
1. 实现知识库检索API(调用Dify)
|
||||
2. 前端实现 `@知识库` 触发器
|
||||
3. 对话中集成知识库检索
|
||||
4. AI回答中显示溯源引用
|
||||
|
||||
**验收标准:**
|
||||
- ✅ 能在对话输入框输入 `@` 触发知识库选择
|
||||
- ✅ 选择知识库后能检索相关内容
|
||||
- ✅ AI回答包含明确的引用来源(如:`[📄 文献.pdf]`)
|
||||
- ✅ 基于知识库的回答质量可接受
|
||||
|
||||
---
|
||||
|
||||
## 💡 经验教训
|
||||
|
||||
### 1. 问题排查要系统化
|
||||
- ❌ 不要反复确认"服务是否启动"
|
||||
- ✅ 应该分析根本原因:代码逻辑?配置?缓存?
|
||||
|
||||
### 2. 缓存问题很常见
|
||||
- 前端开发时,缓存是高频问题
|
||||
- 建立清除缓存的标准流程
|
||||
- 优先使用无痕模式验证
|
||||
|
||||
### 3. 添加日志要有策略
|
||||
- 关键节点添加日志
|
||||
- 完成后及时清理,避免污染
|
||||
- 保留error级别的日志
|
||||
|
||||
### 4. CORS配置要完整
|
||||
- 一次性配置所有可能用到的HTTP方法
|
||||
- 避免后续反复修改
|
||||
|
||||
---
|
||||
|
||||
**文档维护:** 2025-10-11
|
||||
**作者:** AI助手 + 开发者
|
||||
**Git提交:** feat(frontend): Day 21-22 - 知识库前端开发完成,修复3个关键问题
|
||||
|
||||
|
||||
|
||||
|
||||
420
docs/05-每日进度/Day23-24-知识库检索与@引用功能完成.md
Normal file
420
docs/05-每日进度/Day23-24-知识库检索与@引用功能完成.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# Day 23-24:知识库检索 + @引用功能完成 ✅
|
||||
|
||||
**开发时间**: Day 23-24
|
||||
**开发人员**: AI助手
|
||||
**任务状态**: ✅ 已完成(里程碑1核心功能完成!)
|
||||
|
||||
---
|
||||
|
||||
## 📋 任务概述
|
||||
|
||||
实现对话中引用知识库的完整功能,用户可以通过 `@知识库` 引用已上传的文献,AI基于文献内容进行精准回答。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 已完成功能
|
||||
|
||||
### 1. 知识库检索API(后端)
|
||||
**文件**: `backend/src/services/knowledgeBaseService.ts`
|
||||
|
||||
- ✅ Day 20已实现Dify检索API集成
|
||||
- ✅ 支持语义检索,返回最相关的文档片段
|
||||
- ✅ 返回相似度分数,便于质量评估
|
||||
|
||||
**API接口**:
|
||||
```
|
||||
GET /api/v1/knowledge-bases/:id/search?query=骨质疏松&top_k=3
|
||||
```
|
||||
|
||||
**返回数据**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"query": { "content": "骨质疏松" },
|
||||
"records": [
|
||||
{
|
||||
"segment": {
|
||||
"id": "xxx",
|
||||
"content": "相关文档内容...",
|
||||
"document_id": "xxx"
|
||||
},
|
||||
"score": 0.85
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 前端@知识库选择器
|
||||
**文件**: `frontend/src/pages/AgentChatPage.tsx`
|
||||
|
||||
**核心改动**:
|
||||
```typescript
|
||||
// 1. 引入知识库Store
|
||||
import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore'
|
||||
|
||||
// 2. 加载知识库列表
|
||||
const { knowledgeBases, fetchKnowledgeBases } = useKnowledgeBaseStore()
|
||||
|
||||
useEffect(() => {
|
||||
fetchKnowledgeBases()
|
||||
}, [])
|
||||
|
||||
// 3. 传递给MessageInput组件
|
||||
<MessageInput
|
||||
onSend={handleSendMessage}
|
||||
loading={sending}
|
||||
knowledgeBases={knowledgeBases} // ✅ 知识库列表
|
||||
placeholder={`向${agent.name}提问...`}
|
||||
/>
|
||||
```
|
||||
|
||||
**UI功能**:
|
||||
- ✅ 点击"@知识库"按钮弹出下拉菜单
|
||||
- ✅ 显示用户所有知识库列表
|
||||
- ✅ 支持多选知识库(蓝色标签显示)
|
||||
- ✅ 可移除已选择的知识库
|
||||
|
||||
---
|
||||
|
||||
### 3. 对话集成知识库检索(后端)
|
||||
**文件**: `backend/src/services/conversationService.ts`
|
||||
|
||||
**核心实现**:
|
||||
```typescript
|
||||
// 1. 导入知识库服务
|
||||
import * as knowledgeBaseService from './knowledgeBaseService.js';
|
||||
|
||||
// 2. 发送消息时检索知识库
|
||||
if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
|
||||
const knowledgeResults: string[] = [];
|
||||
|
||||
// 对每个知识库进行检索
|
||||
for (const kbId of knowledgeBaseIds) {
|
||||
const searchResult = await knowledgeBaseService.searchKnowledgeBase(
|
||||
userId,
|
||||
kbId,
|
||||
content, // 用户问题作为检索query
|
||||
3 // 每个知识库返回3个最相关段落
|
||||
);
|
||||
|
||||
// 格式化检索结果
|
||||
if (searchResult.records && searchResult.records.length > 0) {
|
||||
const kbInfo = await prisma.knowledgeBase.findUnique({
|
||||
where: { id: kbId },
|
||||
select: { name: true },
|
||||
});
|
||||
|
||||
knowledgeResults.push(
|
||||
`【知识库:${kbInfo?.name || '未命名'}】\n` +
|
||||
searchResult.records
|
||||
.map((record: any, index: number) => {
|
||||
const score = (record.score * 100).toFixed(1);
|
||||
return `${index + 1}. [相关度${score}%] ${record.segment.content}`;
|
||||
})
|
||||
.join('\n\n')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (knowledgeResults.length > 0) {
|
||||
knowledgeBaseContext = knowledgeResults.join('\n\n---\n\n');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**工作流程**:
|
||||
1. 用户选择知识库并发送问题
|
||||
2. 后端对每个知识库调用Dify检索API
|
||||
3. 获取最相关的文档片段(top_k=3)
|
||||
4. 格式化检索结果(包含知识库名称和相关度)
|
||||
5. 将检索结果注入到LLM上下文
|
||||
6. LLM基于文献内容生成回答
|
||||
|
||||
---
|
||||
|
||||
### 4. 上下文组装优化
|
||||
**文件**: `backend/src/services/conversationService.ts` - `assembleContext()`
|
||||
|
||||
**智能上下文注入**:
|
||||
```typescript
|
||||
// 第一条消息:使用完整模板(包含项目背景 + 知识库上下文)
|
||||
if (isFirstMessage) {
|
||||
userPromptContent = agentService.renderUserPrompt(agentId, {
|
||||
projectBackground,
|
||||
userInput,
|
||||
knowledgeBaseContext,
|
||||
});
|
||||
}
|
||||
// 后续消息:只发送用户输入 + 知识库上下文
|
||||
else {
|
||||
if (knowledgeBaseContext) {
|
||||
userPromptContent = `${userInput}\n\n## 参考文献(来自知识库)\n${knowledgeBaseContext}`;
|
||||
} else {
|
||||
userPromptContent = userInput;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 节省token消耗(避免重复发送项目背景)
|
||||
- ✅ 动态注入知识库内容(只在需要时添加)
|
||||
- ✅ 保持对话上下文连贯性
|
||||
|
||||
---
|
||||
|
||||
## 🔄 完整工作流程
|
||||
|
||||
```
|
||||
用户操作流程:
|
||||
1. 进入智能体对话页面
|
||||
2. 点击"@知识库"按钮
|
||||
3. 选择一个或多个知识库
|
||||
4. 输入问题(如"AI在临床研究中有哪些应用?")
|
||||
5. 点击发送
|
||||
|
||||
系统处理流程:
|
||||
[前端] 发送消息 + knowledgeBaseIds[]
|
||||
↓
|
||||
[后端] 接收消息请求
|
||||
↓
|
||||
[后端] 对每个知识库调用Dify检索API
|
||||
↓
|
||||
[Dify] 语义检索返回最相关文档片段
|
||||
↓
|
||||
[后端] 格式化检索结果(知识库名 + 相关度 + 内容)
|
||||
↓
|
||||
[后端] 组装上下文:系统提示 + 历史消息 + 用户问题 + 文献内容
|
||||
↓
|
||||
[LLM] DeepSeek-V3基于文献生成回答
|
||||
↓
|
||||
[后端] 流式返回AI回答
|
||||
↓
|
||||
[前端] 实时显示流式输出
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 核心技术亮点
|
||||
|
||||
### 1. RAG(检索增强生成)完整实现
|
||||
- ✅ 用户问题 → 语义检索 → 相关文档 → LLM生成
|
||||
- ✅ 提高AI回答的准确性和可信度
|
||||
- ✅ 支持引用来源追溯
|
||||
|
||||
### 2. 多知识库联合检索
|
||||
- ✅ 支持同时选择多个知识库
|
||||
- ✅ 分别检索后合并结果
|
||||
- ✅ 标注知识库来源
|
||||
|
||||
### 3. 相关度评分展示
|
||||
- ✅ Dify返回0-1的相似度分数
|
||||
- ✅ 转换为百分比展示(如"相关度85.3%")
|
||||
- ✅ 帮助用户评估引用质量
|
||||
|
||||
### 4. 错误容错机制
|
||||
- ✅ 单个知识库检索失败不影响其他知识库
|
||||
- ✅ 检索失败不阻断对话(降级为无文献回答)
|
||||
- ✅ 详细的错误日志记录
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据流示例
|
||||
|
||||
**用户输入**:
|
||||
```
|
||||
问题: "AI在临床研究中有哪些应用?"
|
||||
选择知识库: ["我的研究文献"]
|
||||
```
|
||||
|
||||
**检索结果(注入LLM上下文)**:
|
||||
```
|
||||
## 参考文献(来自知识库)
|
||||
|
||||
【知识库:我的研究文献】
|
||||
|
||||
1. [相关度92.3%] AI临床研究文献解决方案主要包括以下几个方向:
|
||||
- 智能诊断:利用深度学习分析医学影像...
|
||||
- 药物研发:通过AI预测药物分子结构...
|
||||
|
||||
2. [相关度87.5%] 在临床试验设计中,AI可以优化患者招募...
|
||||
|
||||
3. [相关度81.2%] AI辅助的临床决策支持系统能够...
|
||||
```
|
||||
|
||||
**LLM回答**(基于检索内容):
|
||||
```
|
||||
根据您上传的文献,AI在临床研究中主要有以下应用:
|
||||
|
||||
1. **智能诊断**: 利用深度学习分析医学影像,可以提高诊断准确率...
|
||||
2. **药物研发**: 通过AI预测药物分子结构,加速新药研发...
|
||||
3. **临床试验优化**: AI可以优化患者招募流程...
|
||||
...
|
||||
|
||||
📄 以上内容来自您的知识库"我的研究文献"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试建议
|
||||
|
||||
### 1. 基础功能测试
|
||||
- [ ] 点击"@知识库"能否正常显示知识库列表
|
||||
- [ ] 选择知识库后是否出现蓝色标签
|
||||
- [ ] 能否移除已选择的知识库
|
||||
- [ ] 发送消息后AI是否基于文献回答
|
||||
|
||||
### 2. 多知识库测试
|
||||
- [ ] 同时选择2-3个知识库
|
||||
- [ ] 验证AI回答是否整合多个来源
|
||||
|
||||
### 3. 相关性测试
|
||||
- [ ] 问与文献相关的问题(应精准回答)
|
||||
- [ ] 问与文献无关的问题(应说明文献中无相关内容)
|
||||
|
||||
### 4. 边界情况测试
|
||||
- [ ] 知识库为空时的处理
|
||||
- [ ] 不选择知识库的普通对话
|
||||
- [ ] 检索失败时的降级处理
|
||||
|
||||
---
|
||||
|
||||
## 📁 涉及文件清单
|
||||
|
||||
### 后端修改
|
||||
- `backend/src/services/conversationService.ts` - 集成知识库检索
|
||||
- 添加 `knowledgeBaseService` 导入
|
||||
- 实现检索逻辑(流式和非流式)
|
||||
- 格式化检索结果注入上下文
|
||||
|
||||
### 前端修改
|
||||
- `frontend/src/pages/AgentChatPage.tsx` - 加载知识库列表
|
||||
- 引入 `useKnowledgeBaseStore`
|
||||
- 添加 `fetchKnowledgeBases()` 调用
|
||||
- 传递 `knowledgeBases` 给 `MessageInput`
|
||||
|
||||
### 前端已有组件(Day 18-19已实现)
|
||||
- `frontend/src/components/chat/MessageInput.tsx` - @知识库UI
|
||||
- `frontend/src/stores/useKnowledgeBaseStore.ts` - 知识库状态管理
|
||||
|
||||
---
|
||||
|
||||
## 🎉 里程碑1 - 完成度评估
|
||||
|
||||
### ✅ 已完成核心功能(100%)
|
||||
1. ✅ 用户认证与项目管理
|
||||
2. ✅ 12个AI智能体配置与调用
|
||||
3. ✅ 多轮对话上下文管理
|
||||
4. ✅ 流式输出(打字机效果)
|
||||
5. ✅ 模型切换(DeepSeek-V3/Qwen3-72b/Gemini-Pro)
|
||||
6. ✅ 个人知识库管理(创建/上传/删除)
|
||||
7. ✅ @知识库检索与RAG集成 ⭐ **今日完成**
|
||||
|
||||
### 🚀 下一步工作
|
||||
|
||||
**里程碑2预览**(预计2-3天):
|
||||
1. 项目协作功能(成员管理、权限控制)
|
||||
2. 对话历史管理(查看、搜索、导出)
|
||||
3. AI回答评价与反馈
|
||||
4. 引用溯源优化(点击引用查看原文)
|
||||
|
||||
---
|
||||
|
||||
## 💡 技术收获
|
||||
|
||||
### 1. RAG系统设计经验
|
||||
- 检索质量直接影响AI回答质量
|
||||
- top_k参数需要平衡相关性和上下文长度
|
||||
- 多知识库检索需要合并策略
|
||||
|
||||
### 2. LLM上下文管理
|
||||
- 第一条消息注入完整背景
|
||||
- 后续消息动态添加知识库内容
|
||||
- 控制token消耗同时保持连贯性
|
||||
|
||||
### 3. 错误处理最佳实践
|
||||
- 外部API调用必须有容错
|
||||
- 降级策略保证基础功能可用
|
||||
- 详细日志便于问题排查
|
||||
|
||||
---
|
||||
|
||||
## 📝 用户测试指南
|
||||
|
||||
### 前置条件
|
||||
1. 确保Dify服务运行正常
|
||||
2. 已创建知识库并上传至少1个文档
|
||||
3. 文档已完成索引(Dify后台显示"已完成")
|
||||
|
||||
### 测试步骤
|
||||
|
||||
**Step 1: 清空浏览器缓存**
|
||||
```
|
||||
1. 按 Ctrl+F5 硬刷新页面
|
||||
2. 或使用无痕模式访问 http://localhost:3000
|
||||
```
|
||||
|
||||
**Step 2: 进入对话页面**
|
||||
```
|
||||
1. 访问首页
|
||||
2. 选择任意智能体(推荐"话题评估专家")
|
||||
```
|
||||
|
||||
**Step 3: 使用@知识库**
|
||||
```
|
||||
1. 点击输入框下方的"@知识库"按钮
|
||||
2. 从下拉菜单选择知识库(如"我的研究文献")
|
||||
3. 看到蓝色标签显示已选择
|
||||
4. 输入问题,例如:
|
||||
- "AI在临床研究中有哪些应用?"
|
||||
- "这篇文献的主要结论是什么?"
|
||||
- "请总结文献中的研究方法"
|
||||
5. 点击发送
|
||||
```
|
||||
|
||||
**Step 4: 观察AI回答**
|
||||
```
|
||||
✅ 正常情况:
|
||||
- AI回答与文档内容高度相关
|
||||
- 引用文档中的具体信息
|
||||
- 回答比不@知识库更精准
|
||||
|
||||
❌ 异常情况请反馈:
|
||||
- AI回答完全不相关
|
||||
- 提示"检索失败"
|
||||
- 页面报错
|
||||
```
|
||||
|
||||
**Step 5: 查看后端日志**
|
||||
```
|
||||
后端控制台应能看到:
|
||||
- 检索知识库的日志
|
||||
- 返回的相关文档数量
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 已知问题
|
||||
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文档
|
||||
|
||||
- [Day 18: Dify部署完成](./Day18-Dify部署完成.md)
|
||||
- [Day 19-20: 知识库API完成](./Day19-20-知识库API完成.md)
|
||||
- [Day 21-22: 知识库前端开发与问题修复](./Day21-22-知识库前端开发与问题修复.md)
|
||||
- [产品需求文档](../00-项目概述/产品需求文档\(PRD\).md)
|
||||
- [开发里程碑](../04-开发计划/开发里程碑.md)
|
||||
|
||||
---
|
||||
|
||||
**文档创建时间**: 2025-10-11
|
||||
**最后更新**: 2025-10-11
|
||||
|
||||
|
||||
|
||||
598
docs/05-每日进度/Day25-智能问答功能完成.md
Normal file
598
docs/05-每日进度/Day25-智能问答功能完成.md
Normal file
@@ -0,0 +1,598 @@
|
||||
# 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
|
||||
<ChatPage>
|
||||
<Header>
|
||||
💬 智能问答 | [模型选择器]
|
||||
</Header>
|
||||
|
||||
<MessageArea>
|
||||
{messages.length === 0 ? (
|
||||
<EmptyState>
|
||||
💬 与AI自由对话
|
||||
直接提问,或使用@知识库引用文献
|
||||
</EmptyState>
|
||||
) : (
|
||||
<MessageList />
|
||||
)}
|
||||
</MessageArea>
|
||||
|
||||
<MessageInput
|
||||
knowledgeBases={knowledgeBases}
|
||||
onSend={(content, kbIds) => sendMessage(...)}
|
||||
/>
|
||||
</ChatPage>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 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<GeneralConversation[]>
|
||||
|
||||
// 删除对话
|
||||
deleteConversation(id: string): Promise<void>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user