# IIT Manager Agent 技术债务清单 **文档版本**: v1.0 **最后更?*: 2026-01-04 **当前阶段**: Phase 1.5 完成 --- ## 📋 文档说明 本文档记录IIT Manager Agent模块的技术债务,包括当前的临时方案、已知限制、待优化项,以及未来改进计划? --- ## 🎯 技术债务优先级定? | 优先?| 说明 | 处理时机 | |-------|------|---------| | **P0 - 阻塞?* | 影响核心功能,必须立即处?| 立即 | | **P1 - 高优先级** | 影响用户体验或性能,建议Phase 2处理 | 1个月?| | **P2 - 中优先级** | 功能增强,可在Phase 3处理 | 3个月?| | **P3 - 低优先级** | 优化项,长期规划 | 6个月?| --- ## 🔴 P0 - 阻塞性债务 **当前状?*: ?无P0级债务 --- ## 🟠 P1 - 高优先级债务 ### 1. 意图识别升级 **当前方案**: 关键词匹配(正则表达式) **问题**: - ⚠️ 无法理解复杂的自然语言 - ⚠️ 容易误判边缘case - ⚠️ 需要人工维护关键词列表 **影响**: - 当用户使用非标准表达时,可能无法正确识别意图 - 例如?帮我看一下那?号的数据" 可能无法识别为`query_record` **改进方案**: **方案A: LLM意图判断**(推荐) ```typescript // 使用LLM进行意图分类 const intentPrompt = `你是意图识别专家。用户消息:${userMessage} 请判断用户意图,从以下选项中选择? 1. query_record - 查询特定患者记? 2. count_records - 统计患者数? 3. query_protocol - 查询研究方案文档 4. project_info - 查询项目信息 5. general_chat - 普通对? 只返回JSON: {"intent": "xxx", "params": {...}} `; const intentResult = await llm.chat([{ role: 'user', content: intentPrompt }]); ``` **优势**: - ?理解能力强,支持复杂表达 - ?无需维护关键? - ?适应性好 **劣势**: - ?增加一次LLM调用(~1秒,+¥0.0001成本? - ?总响应时间增加到~6? **方案B: BERT分类模型** ```python # 训练意图分类模型 from transformers import BertForSequenceClassification model = BertForSequenceClassification.from_pretrained( 'bert-base-chinese', num_labels=5 ) # 训练数据?00-200个标注样? # 推理速度?100ms ``` **优势**: - ?速度快(<100ms? - ?理解能力? - ?成本? **劣势**: - ?需要标注训练数? - ?需要部署模型服? - ?需要持续迭? **建议**: - Phase 2: 先使用方案A(LLM判断),快速验证效? - Phase 3: 如果量大,再切换到方案B(BERT模型? **预计工作?*: 2-3? --- ### 2. 上下文存储迁移到Redis **当前方案**: 内存缓存(Node.js Map? **问题**: - ⚠️ 单机内存,不支持分布式部? - ⚠️ 服务重启后上下文丢失 - ⚠️ 内存占用无限制(虽有自动清理,但仍有风险? **影响**: - 当后端服务重启时,所有用户的对话上下文会丢失 - 如果部署多个实例,用户请求可能路由到不同实例,导致上下文丢失 **改进方案**: ```typescript // backend/src/modules/iit-manager/agents/SessionMemory.ts import Redis from 'ioredis'; export class SessionMemory { private redis: Redis; private readonly EXPIRE_TIME = 1800; // 30分钟 constructor() { this.redis = new Redis(config.redisUrl); } async addMessage(userId: string, role: 'user' | 'assistant', content: string): Promise { const key = `session:${userId}`; const message = { role, content, timestamp: Date.now() }; // 1. 获取当前会话 const sessionData = await this.redis.get(key); const session = sessionData ? JSON.parse(sessionData) : { messages: [] }; // 2. 添加消息 session.messages.push(message); // 3. 保持最?? if (session.messages.length > 6) { session.messages = session.messages.slice(-6); } // 4. 存回Redis?0分钟过期? await this.redis.setex(key, this.EXPIRE_TIME, JSON.stringify(session)); } async getContext(userId: string): Promise { const key = `session:${userId}`; const sessionData = await this.redis.get(key); if (!sessionData) return ''; const session = JSON.parse(sessionData); return session.messages .map(m => `${m.role === 'user' ? '用户' : 'AI'}: ${m.content}`) .join('\n\n'); } } ``` **优势**: - ?支持分布式部? - ?服务重启不丢失上下文 - ?内存占用可控 **劣势**: - ?增加Redis依赖 - ?每次读写需要网络IO(~1-2ms? **建议**: Phase 2实施,优先级中高 **预计工作?*: 1? --- ### 3. Dify检索结果缓? **当前方案**: 每次都调用Dify API检? **问题**: - ⚠️ 相同问题重复检索,浪费时间 - ⚠️ Dify API响应时间?0%?.5-1.7秒) **影响**: - 响应速度有提升空? - 相同问题第二次询问仍需1.5? **改进方案**: ```typescript // 使用Redis缓存Dify检索结? private async queryDifyKnowledge(query: string): Promise { // 1. 生成缓存key(query的hash? const cacheKey = `dify:${md5(query)}`; // 2. 尝试从缓存获? const cached = await redis.get(cacheKey); if (cached) { logger.info('Dify检索命中缓?, { query }); return cached; } // 3. 调用Dify API const result = await difyClient.retrieveKnowledge(...); // 4. 格式化结? const formattedKnowledge = this.formatDifyResult(result); // 5. 缓存结果?小时? await redis.setex(cacheKey, 3600, formattedKnowledge); return formattedKnowledge; } ``` **优势**: - ?相同问题响应速度提升1.5秒(?.8秒降?.3秒) - ?减少Dify API调用次数 - ?降低Dify服务器负? **劣势**: - ?文档更新后需要清除缓? - ?缓存占用Redis内存 **缓存失效策略**: - 文档上传/更新/删除时,清除对应Dataset的所有缓? - 缓存过期时间?小时 **建议**: Phase 2实施,优先级? **预计工作?*: 1? --- ### 4. REDCap数据缓存 **当前方案**: 每次都调用REDCap API查询 **问题**: - ⚠️ REDCap API响应时间?5%?.2-1.3秒) - ⚠️ 患者基本信息变化频率低,不需要每次实时查? **影响**: - 响应速度有提升空? - 增加REDCap服务器负? **改进方案**: ```typescript // 分层缓存策略 private async queryRedcapRecord(recordId: string): Promise { const cacheKey = `redcap:record:${recordId}`; // 1. 尝试从缓存获? const cached = await redis.get(cacheKey); if (cached) { return JSON.parse(cached); } // 2. 调用REDCap API const records = await redcap.exportRecords({ records: [recordId] }); // 3. 缓存结果?分钟? await redis.setex(cacheKey, 300, JSON.stringify(records[0])); return records[0]; } ``` **缓存策略**: | 数据类型 | 缓存时间 | 原因 | |---------|---------|------| | 患者基本信?| 5分钟 | 变化频率?| | 统计数据 | 1分钟 | 需要较实时 | | 项目配置 | 1小时 | 几乎不变 | **优势**: - ?响应速度提升1.2? - ?减少REDCap服务器负? **劣势**: - ?数据可能?分钟延迟 **建议**: Phase 2实施,需与用户确认是否接?分钟延迟 **预计工作?*: 1? --- ## 🟡 P2 - 中优先级债务 ### 5. 文档上传API开? **当前方案**: 手动通过Dify界面上传文档 **问题**: - ⚠️ 不支持批量上? - ⚠️ 需要登录Dify系统 - ⚠️ 无法自动? **影响**: - PI无法自助上传研究文档 - 需要技术人员协? **改进方案**: ```typescript // backend/src/modules/iit-manager/routes/index.ts // 上传文档到项目知识库 router.post('/projects/:projectId/documents', async (request, reply) => { const { projectId } = request.params; const file = await request.file(); // 1. 获取项目配置 const project = await prisma.iitProject.findUnique({ where: { id: projectId }, select: { difyDatasetId: true } }); // 2. 上传到Dify const buffer = await file.toBuffer(); const result = await difyClient.uploadDocumentDirectly( project.difyDatasetId, buffer, file.filename ); // 3. 等待索引完成 await difyClient.waitForDocumentProcessing( project.difyDatasetId, result.document.id ); return reply.send({ success: true, documentId: result.document.id }); }); // 删除文档 router.delete('/projects/:projectId/documents/:documentId', async (request, reply) => { // 实现文档删除 }); // 获取文档列表 router.get('/projects/:projectId/documents', async (request, reply) => { // 实现文档列表查询 }); ``` **前端界面**(可选): - 文档上传表单 - 文档列表展示 - 文档状态追踪(uploading ?indexing ?completed? **建议**: Phase 3实施,优先级? **预计工作?*: 2-3? --- ### 6. 用户绑定默认项目 **当前方案**: 所有用户共享同一个活跃项目(`status='active'`? **问题**: - ⚠️ 无法支持多项? - ⚠️ 不同用户可能关注不同项目 **影响**: - 如果有多个IIT项目,无法区分用户属于哪个项? **改进方案**: **数据模型更新**: ```typescript // backend/prisma/schema.prisma model IitUserMapping { // ... 现有字段 ... // 新增:用户的默认项目 defaultProjectId String? @map("default_project_id") } ``` **ChatService更新**: ```typescript async handleMessage(userId: string, userMessage: string): Promise { // 1. 获取用户的默认项? const userMapping = await prisma.iitUserMapping.findFirst({ where: { wecomUserId: userId } }); const projectId = userMapping?.defaultProjectId; // 2. 基于项目查询数据 const project = await prisma.iitProject.findUnique({ where: { id: projectId } }); // 后续逻辑... } ``` **建议**: Phase 2后期实施,当有多个项目时 **预计工作?*: 1-2? --- ### 7. Function Calling升级 **当前方案**: 关键词意图识??手动调用工具 **问题**: - ⚠️ 无法自动决定是否调用工具 - ⚠️ 无法根据上下文自动提取参? **影响**: - 如果用户?7号患者和8号患者哪个更严重?,当前无法自动查询两个患? **改进方案**: 使用DeepSeek-V3?*Native Function Calling**: ```typescript // 定义工具 const tools = [ { type: 'function', function: { name: 'query_redcap_record', description: '查询REDCap中特定患者的记录', parameters: { type: 'object', properties: { recordId: { type: 'string', description: '患者记录ID' } }, required: ['recordId'] } } }, { type: 'function', function: { name: 'query_dify_knowledge', description: '检索研究方案、CRF表格等文?, parameters: { type: 'object', properties: { query: { type: 'string', description: '查询问题' } }, required: ['query'] } } } ]; // LLM自动决定调用哪些工具 const response = await llm.chat(messages, { tools }); // 处理工具调用 if (response.tool_calls) { for (const toolCall of response.tool_calls) { if (toolCall.function.name === 'query_redcap_record') { const args = JSON.parse(toolCall.function.arguments); const result = await this.queryRedcapRecord(args.recordId); // 继续对话... } } } ``` **优势**: - ?LLM自动决定是否调用工具 - ?自动提取参数(如recordId? - ?支持多工具并行调? - ?更智能、更灵活 **劣势**: - ?增加一次LLM调用 - ?总响应时间可能增加到7-8? **建议**: Phase 3实施,作为高级功? **预计工作?*: 3-5? --- ### 8. 智能引用系统 **当前方案**: Dify返回的文档片段直接显? **问题**: - ⚠️ 无法溯源到具体文档和位置 - ⚠️ 用户无法验证信息来源 **影响**: - 用户体验不够透明 **改进方案**: 参考ASL模块的智能引用系统: ```typescript // 1. 收集引用信息 interface Citation { id: number; documentName: string; segmentIndex: number; score: number; content: string; } // 2. AI回答中插入引用标? const answer = `根据研究方案[1]和CRF表格[2],纳入标准包括: 1. 年龄18-75岁[1] 2. 符合诊断标准[1][2] 3. 签署知情同意书[3] --- 📚 **参考文?* [1] 📄 **研究方案.pdf** - ??(相关?5%) "纳入标准:年?8-75岁,符合诊断标准..." [2] 📄 **CRF表格.docx** - ??(相关?2%) "基线评估包括:诊断标准、入组时?.." `; // 3. 前端高亮显示引用 // 点击[1]跳转到引用详? ``` **建议**: Phase 3实施,作为体验优? **预计工作?*: 3-4? --- ## 🟢 P3 - 低优先级债务 ### 9. 批量数据查询优化 **当前方案**: 单条记录查询 **问题**: - ⚠️ 如果用户?所有患者的入组情况",需要多次查? **改进方案**: - 支持批量查询 - 生成数据摘要 **建议**: Phase 4实施 **预计工作?*: 2-3? --- ### 10. 多轮对话优化 **当前方案**: 保留最?轮对? **问题**: - ⚠️ 长对话可能丢失重要上下文 **改进方案**: - 智能上下文压缩(提取关键信息? - 长期记忆(存储重要信息到数据库) **建议**: Phase 4实施 **预计工作?*: 5-7? --- ## 📊 债务优先级总览 | 债务?| 优先?| 影响 | 工作?| 建议时间 | |-------|--------|------|--------|----------| | 意图识别升级 | P1 | 准确?| 2-3?| Phase 2 | | 上下文迁移Redis | P1 | 可用?| 1?| Phase 2 | | Dify结果缓存 | P1 | 性能 | 1?| Phase 2 | | REDCap数据缓存 | P1 | 性能 | 1?| Phase 2 | | 文档上传API | P2 | 功能 | 2-3?| Phase 3 | | 用户绑定项目 | P2 | 功能 | 1-2?| Phase 2后期 | | Function Calling | P2 | 智能?| 3-5?| Phase 3 | | 智能引用系统 | P2 | 体验 | 3-4?| Phase 3 | | 批量查询优化 | P3 | 功能 | 2-3?| Phase 4 | | 多轮对话优化 | P3 | 体验 | 5-7?| Phase 4 | --- ## 🎯 Phase 2 债务清偿计划 ### Week 1-2: 性能优化 - [ ] 上下文迁移到Redis?天) - [ ] Dify结果缓存?天) - [ ] REDCap数据缓存?天) - [ ] 性能测试与调优(1天) **预期效果**: - 响应时间?.8秒降?-3? - 支持分布式部? - 服务重启不丢失上下文 ### Week 3-4: 意图识别升级 - [ ] 实现LLM意图判断?天) - [ ] A/B测试对比?天) - [ ] 上线灰度发布?天) **预期效果**: - 意图识别准确率保?00% - 支持复杂自然语言表达 ### Week 5: 多项目支? - [ ] 用户绑定默认项目?天) **预期效果**: - 支持多个IIT项目并行 --- ## 📝 债务跟踪 ### 已清偿债务 | 债务?| 清偿时间 | 方案 | |-------|---------|------| | AI幻觉问题 | 2026-01-03 | RAG数据注入 + 严格System Prompt | | 上下文丢?| 2026-01-03 | SessionMemory(最?轮) | | 响应速度?| 2026-01-04 | 优化意图识别 + 异步处理 | ### 进行中债务 | 债务?| 负责?| 预计完成 | |-------|--------|----------| | ?| - | - | ### 待处理债务 见上文优先级列表 --- ## 🔗 相关文档 - [IIT Manager Agent 技术路径与架构设计](../02-技术设?IIT Manager Agent 技术路径与架构设计.md) - [Phase1.5-AI对话能力开发计划](../04-开发计?Phase1.5-AI对话能力开发计?md) - [MVP开发任务清单](../04-开发计?MVP开发任务清?md) --- **文档维护**: 技术团? **最后更?*: 2026-01-04 **版本历史**: - v1.0 (2026-01-04): 初始版本,Phase 1.5完成后整?