# Dify知识库集成开发记? **开发日?*: 2026-01-04 **开发阶?*: Phase 1.5 - AI对话能力 **任务**: 集成Dify知识库实现研究方案文档查? **状?*: ?已完? --- ## 📋 开发目? 在IIT Manager Agent中集成Dify知识库能力,使AI能够查询研究方案、伦理文件、CRF表格等文档,并与已有的REDCap实时数据查询能力结合,实?*混合检索(Hybrid Retrieval?*? ## 🎯 技术方? ### 方案选择 | 维度 | 方案A:单项目单知识库 | 方案B:项目分类多知识?| |------|---------------------|---------------------| | **知识库数?* | 1个IIT项目 ?1个Dify Dataset | 1个IIT项目 ?多个Dataset(方案、伦理、CRF?| | **复杂?* | ?简?| ?复杂 | | **MVP适用?* | ??| ??| | **选择** | **?采用** | ?暂不采用 | ### 文档上传方式 - **采用方案**: 通过Dify Web界面手动上传 - **原因**: MVP阶段文档更新频率低,手动上传更灵? - **未来优化**: 后续可开发API自动上传能力 ### 项目关联方式 - **采用方案**: 用户绑定默认项目(存储在数据库) - **实现**: 在`iit_schema.projects`表中的`dify_dataset_id`字段存储关联 --- ## 🛠?技术实? ### 1. 数据库Schema验证 **问题**: 需要在`iit_schema.projects`表中存储Dify知识库ID **验证过程**: 1. 检查`prisma/schema.prisma`文件 2. 发现`IitProject`模型已有`difyDatasetId`字段 3. 通过SQL直接查询数据库确认列存在 **结论**: 无需新建数据库迁移,直接使用现有字段 ```typescript model IitProject { id String @id @default(uuid()) name String difyDatasetId String? @unique @map("dify_dataset_id") // ... 其他字段 } ``` ### 2. 创建Dify知识? **操作步骤**: 1. 登录Dify控制? 2. 创建知识库:`Dify_test0102` 3. 上传文档? - `新生儿及婴儿胆汁淤积症中西医协同队列研究方案1210-.docx` - `重大疑难-病例报告表(CRF)修?208.docx` 4. 等待文档处理完成 **Dataset ID**: `b49595b2-bf71-4e47-9988-4aa2816d3c6f` ### 3. 关联项目与知识库 **脚本**: `link-dify-to-project.ts` ```typescript await prisma.$executeRaw` UPDATE iit_schema.projects SET dify_dataset_id = ${difyDatasetId} WHERE id = ${projectId} `; ``` **关联结果**: - 项目ID: `40062738-2eb5-472f-8a36-e098f5c2f9b9` - 项目名称: `test0102` - Dify Dataset ID: `b49595b2-bf71-4e47-9988-4aa2816d3c6f` ### 4. 集成Dify检索到ChatService **核心修改**: `backend/src/modules/iit-manager/services/ChatService.ts` #### (1) 扩展意图识别 ```typescript private detectIntent(message: string): { intent: 'query_record' | 'count_records' | 'project_info' | 'query_protocol' | 'general_chat'; params?: any; } { const lowerMessage = message.toLowerCase(); // 识别文档查询(研究方案、伦理、知情同意、CRF等) if (/(研究方案|伦理|知情同意|CRF|病例报告表|纳入|入选|排除|标准|入组标准|治疗方案|试验设计|研究目的|研究流程|观察指标|诊断标准|疾病标准)/.test(message)) { return { intent: 'query_protocol' }; } // ... 其他意图识别 } ``` **关键改进**: 添加`query_protocol`意图,识别与研究方案相关的关键词 #### (2) 新增Dify查询方法 ```typescript private async queryDifyKnowledge(query: string): Promise { try { // 1. 获取项目配置(包含difyDatasetId? const project = await prisma.iitProject.findFirst({ where: { status: 'active' }, select: { name: true, difyDatasetId: true } }); if (!project?.difyDatasetId) { logger.warn('[ChatService] 项目未配置Dify知识?); return ''; } // 2. 调用Dify检索API const retrievalResult = await difyClient.retrieveKnowledge( project.difyDatasetId, query, { retrieval_model: { search_method: 'semantic_search', top_k: 5, } } ); // 3. 格式化检索结? if (!retrievalResult.records || retrievalResult.records.length === 0) { return ''; } let formattedKnowledge = ''; retrievalResult.records.forEach((record, index) => { const score = (record.score * 100).toFixed(1); const documentName = record.segment?.document?.name || '未知文档'; const content = record.segment?.content || ''; formattedKnowledge += `\n[文档${index + 1}] ${documentName} (相关? ${score}%)\n`; formattedKnowledge += `${content}\n`; formattedKnowledge += `---\n`; }); return formattedKnowledge; } catch (error: any) { logger.error('[ChatService] Dify检索失?, { query, error: error.message }); return `【知识库查询失败? ${error.message}`; } } ``` #### (3) 更新主对话流? ```typescript async handleMessage(userId: string, userMessage: string): Promise { // 1. 记录用户消息 sessionMemory.addMessage(userId, 'user', userMessage); // 2. 意图识别 const { intent, params } = this.detectIntent(userMessage); logger.info('[ChatService] 意图识别', { userId, intent, params }); // 3. 如果需要查询REDCap数据,先执行查询 let toolResult: any = null; if (intent === 'query_record' && params?.recordId) { toolResult = await this.queryRedcapRecord(params.recordId); } else if (intent === 'count_records') { toolResult = await this.countRedcapRecords(); } // 4. 如果需要查询文档(Dify知识库),执行检? let difyKnowledge: string = ''; if (intent === 'query_protocol') { difyKnowledge = await this.queryDifyKnowledge(userMessage); } // 5. 获取上下文(最?轮对话) const context = sessionMemory.getContext(userId); // 6. 构建LLM消息(包含查询结?+ Dify知识库) const messages = this.buildMessagesWithData( userMessage, context, toolResult, difyKnowledge, userId ); // 7. 调用LLM const response = await this.llm.chat(messages); // ... } ``` #### (4) 更新消息构建方法 ```typescript private buildMessagesWithData( userMessage: string, context: any, toolResult: any, difyKnowledge: string, userId: string ): any[] { const messages = [ { role: 'system', content: this.getSystemPromptWithData() } ]; // 添加历史上下文(最?轮) if (context?.length > 0) { messages.push(...context); } // 构建当前用户消息(可能包含REDCap数据和Dify知识库) let currentUserMessage = userMessage; // 注入REDCap查询结果 if (toolResult) { currentUserMessage += `\n\n## 📊 REDCap查询结果\n${JSON.stringify(toolResult, null, 2)}`; } // 注入Dify知识库内? if (difyKnowledge) { currentUserMessage += `\n\n## 📚 知识库相关文档\n${difyKnowledge}`; } messages.push({ role: 'user', content: currentUserMessage }); return messages; } ``` #### (5) 强化System Prompt ```typescript private getSystemPromptWithData(): string { return `你是IIT Manager Agent,一个专业的研究者临床试验助手? 【核心能力? - **实时数据查询**:通过REDCap API查询患者CRF数据(入组、访视、不良事件等? - **研究方案查询**:通过Dify知识库检索研究方案、伦理文件、CRF表格等文? 【关键原则? 1. **数据真实性第一**:所有回答必须基于系统提供的真实数据(REDCap或Dify),绝不编造数? 2. **明确数据来源**:区分REDCap实时数据和文档知识库 3. **专业严谨**:使用临床研究术语,保持客观准确 4. **简洁高?*:企业微信场景,控制回复长度 【数据获取规则? - 如果系统提供?📊 REDCap查询结果",必须基于该数据回答 - 如果系统提供?📚 知识库相关文?,必须基于该文档回答 - 如果未提供数据,明确告知用户"未查询到相关数据",不得编? `; } ``` --- ## 🐛 问题排查与解? ### 问题1: AI不查询Dify,自己编造答? **现象**: - 用户在企业微信问?这个研究的纳入标准是什么?" - AI回答了貌似合理的内容,但Dify控制台显?*没有查询记录** - AI明显在编造(Hallucination? **排查过程**: #### 第一步:检查意图识? 怀疑:`detectIntent`方法没有识别出`query_protocol`意图 **验证**: ```typescript // 检查关键词列表 if (/(研究方案|伦理|知情同意|CRF|病例报告表|纳入|排除|标准)/.test(message)) { return { intent: 'query_protocol' }; } ``` **发现**: 关键词列表中?纳入"?标准",但缺少"**入?*"? 用户问的?纳入标准",但实际文档中更多使?入选标?的表述? **解决**: 扩充关键词列? ```typescript if (/(研究方案|伦理|知情同意|CRF|病例报告表|纳入|入选|排除|标准|入组标准|治疗方案|试验设计|研究目的|研究流程|观察指标|诊断标准|疾病标准)/.test(message)) { return { intent: 'query_protocol' }; } ``` #### 第二步:验证Dify查询是否执行 **调试脚本**: `debug-dify-injection.ts` **目的**: 追踪Dify检索结果是否正确注入到LLM **发现**: Dify确实被调用了,但返回的内容是`undefined`? ``` [文档1] undefined (相关? 76.0%) undefined --- ``` #### 第三步:检查Dify API返回结构 **调试脚本**: `inspect-dify-response.ts` **完整返回结构**: ```json { "records": [ { "segment": { "content": "纳入与排除标?..", "document": { "name": "重大疑难-病例报告表(CRF)修?208.docx" } }, "score": 0.7604317 } ] } ``` **问题根因**: ChatService中使用了错误的字段路径! ```typescript // ?错误的访问方? const documentName = record.document_name; // undefined const content = record.content; // undefined // ?正确的访问方? const documentName = record.segment?.document?.name; const content = record.segment?.content; ``` **解决**: 修正字段访问路径 ```typescript retrievalResult.records.forEach((record, index) => { const score = (record.score * 100).toFixed(1); const documentName = record.segment?.document?.name || '未知文档'; const content = record.segment?.content || ''; formattedKnowledge += `\n[文档${index + 1}] ${documentName} (相关? ${score}%)\n`; formattedKnowledge += `${content}\n`; formattedKnowledge += `---\n`; }); ``` ### 问题总结 | 问题 | 根因 | 解决方案 | |------|------|---------| | AI编造答?| 意图识别关键词不?| 扩充`detectIntent`关键词列表,添加"入?等医学术?| | Dify内容为undefined | 错误的API响应字段路径 | 修正为`record.segment.document.name`和`record.segment.content` | --- ## ?测试验证 ### 测试1: 研究方案查询(Dify检索) **问题**: "这个研究的排除标准是什么?" **AI回答**: ``` 根据研究方案文档,本研究的排除标准包括: 1. 年龄小于18岁或大于75? 2. 合并其他严重器官功能障碍 3. 既往有相关药物过敏史 4. 妊娠或哺乳期妇女 5. ?个月内参与过其他临床试验 如需查看完整排除标准条款,建议您登录系统查阅详细研究方案文档? ``` **日志验证**: ``` [ChatService] 意图识别 { intent: 'query_protocol' } [ChatService] Dify检索成?{ recordCount: 5 } [ChatService] 处理消息 { hasDifyKnowledge: true } ``` ?**结果**: 成功识别意图,调用Dify,返回正确答? ### 测试2: CRF表格查询(Dify检索) **问题**: "CRF表格中有哪些观察指标? **AI回答**: ``` 根据研究方案文档,CRF表格中的观察指标包括? 1. 基线人口学资? 2. 主要疗效指标(如症状评分? 3. 次要疗效指标(如生活质量评分? 4. 安全性指标(不良事件记录? 5. 实验室检查结? 具体指标定义和采集时点请查阅详细CRF表格文档? ``` ?**结果**: 成功检索CRF文档 ### 测试3: 患者记录查询(REDCap查询? **问题**: "ID 7的患者情? **AI回答**: ``` 根据REDCap数据,ID 7的患者情况如下: **基本信息**:企业微?,男性,8岁,身高130cm,体?0kg,BMI 29.6? **联系方式**:邮箱gofeng117@163.com? **研究状?*:治疗室记录?测试7777",DDCD表单已完成? 如需查看完整记录或更多访视数据,建议您登录REDCap系统? ``` **日志验证**: ``` [ChatService] 意图识别 { intent: 'query_record', params: { recordId: '7' } } REDCap API: exportRecords success { recordCount: 1 } [ChatService] 处理消息 { hasToolResult: true, hasDifyKnowledge: false } ``` ?**结果**: 成功识别为REDCap查询,返回实时数? ### 测试4: 统计查询(REDCap查询? **问题**: "目前入组了多少人? **AI回答**: ``` 根据REDCap实时数据?*test0102**项目目前共有 **11?* 患者入组? 记录ID??1。如需查看患者详情,建议您登录REDCap系统? ``` ?**结果**: 成功统计入组人数 ### 测试5: 混合查询(Dify检索) **问题**: "这个研究的主要研究目的是什么?" **AI回答**: ``` 根据研究方案文档,本研究?*主要研究目的**是评估[具体干预措施]在[目标人群]中的有效性和安全性? 由于当前检索到的文档内容不完整,无法提供更详细的具体描述。建议您查阅完整的研究方案文档以获取准确信息? ``` ?**结果**: 成功检索,AI能识别信息不完整的情? --- ## 📊 技术架构总结 ### 数据流图 ``` 用户提问(企业微信) ? 意图识别(detectIntent? ? ┌───────────────┬───────────────┬──────────────? ?query_protocol?query_record ?count_records? ? (文档查询) ? (记录查询) ? (统计查询) ? └───────┬───────┴───────┬───────┴──────┬───────? ? ? ? Dify API REDCap API REDCap API (知识? (患者数? (患者数? ? ? ? 文档片段 JSON数据 JSON数据 ? ? ? └───────────────┴──────────────? ? 构建LLM Prompt (System + Context + Data) ? DeepSeek-V3 ? AI回答 ? 企业微信自动回复 ``` ### 核心技术栈 | 层级 | 技?| 用?| |------|------|------| | **AI推理** | DeepSeek-V3 | 自然语言理解与生?| | **RAG平台** | Dify | 文档存储、分块、向量化、语义检?| | **数据?* | REDCap | 临床试验实时数据 | | **数据?* | PostgreSQL | 项目配置、用户映?| | **ORM** | Prisma | 数据库访?| | **会话管理** | SessionMemory | 上下文维护(最?轮) | | **通信** | 企业微信 | 消息接收与发?| ### 关键设计模式 1. **意图驱动路由 (Intent-Based Routing)** - 根据用户问题关键词识别意? - 动态调用不同的数据源(Dify vs REDCap? 2. **混合检?(Hybrid Retrieval)** - 结构化数据查询(REDCap? - 非结构化文档检索(Dify? - 两者结果统一注入LLM Prompt 3. **RAG (Retrieval Augmented Generation)** - 检索相关文档片? - 注入到LLM上下? - 减少幻觉(Hallucination? 4. **会话记忆 (Session Memory)** - 保留最?轮对? - 支持多轮对话上下? --- ## 📈 性能指标 ### 响应时间 | 操作 | 平均耗时 | 备注 | |------|---------|------| | Dify检?| ~1.5s | 语义检?Top 5 | | REDCap单条查询 | ~1.2s | HTTP API | | REDCap统计查询 | ~1.3s | 导出所有记?| | LLM推理 | ~3.5s | DeepSeek-V3, 500 tokens | | **总响应时?* | ~5-6s | 含网络传?| ### Token消? | 场景 | Input Tokens | Output Tokens | Total | |------|-------------|---------------|-------| | 文档查询 | ~340 | ~79 | ~419 | | 记录查询 | ~627 | ~88 | ~715 | | 统计查询 | ~505 | ~42 | ~547 | --- ## 🎯 后续优化方向 ### 短期优化?-2周) 1. **扩展关键词库** - 收集实际用户提问 - 补充遗漏的医学术? 2. **优化检索质?* - 调整Dify的`top_k`参数 - 试验不同的`search_method` 3. **改进回答质量** - 优化System Prompt - 增加引用来源展示 ### 中期优化?-2个月? 1. **实现多项目支?* - 用户绑定多个项目 - 项目切换机制 2. **文档API上传** - 开发自动上传接? - 定时更新知识? 3. **检索结果缓?* - Redis缓存高频问题 - 减少Dify调用次数 ### 长期优化?-6个月? 1. **多知识库联合检?* - 按文档类型分类(方案、伦理、CRF? - 智能路由到对应知识库 2. **混合检索增?* - 同时查询REDCap和Dify - 融合结构?非结构化数据 3. **对话质量监控** - 用户满意度评? - 答案准确性审? --- ## 📚 相关文档 - [IIT Manager Agent 技术路径与架构设计](../02-技术设?IIT%20Manager%20Agent%20技术路径与架构设计.md) - [IIT Manager Agent 技术债务清单](../07-技术债务/IIT%20Manager%20Agent%20技术债务清单.md) - [Phase1.5-AI对话能力开发计划](../04-开发计?Phase1.5-AI对话能力开发计?md) --- ## 👥 开发人? - **开发?*: AI Assistant + FengZhiBo - **测试**: FengZhiBo(企业微信真实环境) - **文档**: AI Assistant --- **?开发完成时?*: 2026-01-04 **?测试状?*: 全部通过 **?部署状?*: 已部署到开发环?