Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md
HaHafeng b31255031e feat(iit-manager): Add WeChat Official Account integration for patient notifications
Features:
- PatientWechatCallbackController for URL verification and message handling
- PatientWechatService for template and customer messages
- Support for secure mode (message encryption/decryption)
- Simplified route /wechat/patient/callback for WeChat config
- Event handlers for subscribe/unsubscribe/text messages
- Template message for visit reminders

Technical details:
- Reuse @wecom/crypto for encryption (compatible with Official Account)
- Relaxed Fastify schema validation to prevent early request blocking
- Access token caching (7000s with 5min pre-refresh)
- Comprehensive logging for debugging

Testing: Local URL verification passed, ready for SAE deployment

Status: Code complete, waiting for WeChat platform configuration
2026-01-04 22:53:42 +08:00

16 KiB
Raw Blame History

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
  • ⚠️ 需要人工维护关键词列表

影响:

  • 当用户使用非标准表达时,可能无法正确识别意图
  • 例如:"帮我看一下那个7号的数据" 可能无法识别为query_record

改进方案:

方案A: LLM意图判断(推荐)

// 使用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分类模型

# 训练意图分类模型
from transformers import BertForSequenceClassification

model = BertForSequenceClassification.from_pretrained(
    'bert-base-chinese',
    num_labels=5
)

# 训练数据100-200个标注样本
# 推理速度:<100ms

优势:

  • 速度快(<100ms
  • 理解能力强
  • 成本低

劣势:

  • 需要标注训练数据
  • 需要部署模型服务
  • 需要持续迭代

建议:

  • Phase 2: 先使用方案ALLM判断快速验证效果
  • Phase 3: 如果量大再切换到方案BBERT模型

预计工作量: 2-3天


2. 上下文存储迁移到Redis

当前方案: 内存缓存Node.js Map

问题:

  • ⚠️ 单机内存,不支持分布式部署
  • ⚠️ 服务重启后上下文丢失
  • ⚠️ 内存占用无限制(虽有自动清理,但仍有风险)

影响:

  • 当后端服务重启时,所有用户的对话上下文会丢失
  • 如果部署多个实例,用户请求可能路由到不同实例,导致上下文丢失

改进方案:

// 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<void> {
    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. 保持最近3轮
    if (session.messages.length > 6) {
      session.messages = session.messages.slice(-6);
    }
    
    // 4. 存回Redis30分钟过期
    await this.redis.setex(key, this.EXPIRE_TIME, JSON.stringify(session));
  }

  async getContext(userId: string): Promise<string> {
    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响应时间占30%1.5-1.7秒)

影响:

  • 响应速度有提升空间
  • 相同问题第二次询问仍需1.5秒

改进方案:

// 使用Redis缓存Dify检索结果
private async queryDifyKnowledge(query: string): Promise<string> {
  // 1. 生成缓存keyquery的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. 缓存结果1小时
  await redis.setex(cacheKey, 3600, formattedKnowledge);
  
  return formattedKnowledge;
}

优势:

  • 相同问题响应速度提升1.5秒从4.8秒降到3.3秒)
  • 减少Dify API调用次数
  • 降低Dify服务器负载

劣势:

  • 文档更新后需要清除缓存
  • 缓存占用Redis内存

缓存失效策略:

  • 文档上传/更新/删除时清除对应Dataset的所有缓存
  • 缓存过期时间1小时

建议: Phase 2实施优先级中

预计工作量: 1天


4. REDCap数据缓存

当前方案: 每次都调用REDCap API查询

问题:

  • ⚠️ REDCap API响应时间占25%1.2-1.3秒)
  • ⚠️ 患者基本信息变化频率低,不需要每次实时查询

影响:

  • 响应速度有提升空间
  • 增加REDCap服务器负载

改进方案:

// 分层缓存策略
private async queryRedcapRecord(recordId: string): Promise<any> {
  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. 缓存结果5分钟
  await redis.setex(cacheKey, 300, JSON.stringify(records[0]));
  
  return records[0];
}

缓存策略:

数据类型 缓存时间 原因
患者基本信息 5分钟 变化频率低
统计数据 1分钟 需要较实时
项目配置 1小时 几乎不变

优势:

  • 响应速度提升1.2秒
  • 减少REDCap服务器负载

劣势:

  • 数据可能有5分钟延迟

建议: Phase 2实施需与用户确认是否接受5分钟延迟

预计工作量: 1天


🟡 P2 - 中优先级债务

5. 文档上传API开发

当前方案: 手动通过Dify界面上传文档

问题:

  • ⚠️ 不支持批量上传
  • ⚠️ 需要登录Dify系统
  • ⚠️ 无法自动化

影响:

  • PI无法自助上传研究文档
  • 需要技术人员协助

改进方案:

// 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项目无法区分用户属于哪个项目

改进方案:

数据模型更新:

// backend/prisma/schema.prisma

model IitUserMapping {
  // ... 现有字段 ...
  
  // 新增:用户的默认项目
  defaultProjectId  String?  @map("default_project_id")
}

ChatService更新:

async handleMessage(userId: string, userMessage: string): Promise<string> {
  // 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:

// 定义工具
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模块的智能引用系统

// 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** - 第3段 (相关度95%)
    "纳入标准年龄18-75岁符合诊断标准..."
[2] 📄 **CRF表格.docx** - 第5段 (相关度92%)
    "基线评估包括:诊断标准、入组时间..."
`;

// 3. 前端高亮显示引用
// 点击[1]跳转到引用详情

建议: Phase 3实施作为体验优化

预计工作量: 3-4天


🟢 P3 - 低优先级债务

9. 批量数据查询优化

当前方案: 单条记录查询

问题:

  • ⚠️ 如果用户问"所有患者的入组情况",需要多次查询

改进方案:

  • 支持批量查询
  • 生成数据摘要

建议: Phase 4实施

预计工作量: 2-3天


10. 多轮对话优化

当前方案: 保留最近3轮对话

问题:

  • ⚠️ 长对话可能丢失重要上下文

改进方案:

  • 智能上下文压缩(提取关键信息)
  • 长期记忆(存储重要信息到数据库)

建议: 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: 性能优化

  • 上下文迁移到Redis1天
  • Dify结果缓存1天
  • REDCap数据缓存1天
  • 性能测试与调优1天

预期效果:

  • 响应时间从4.8秒降到2-3秒
  • 支持分布式部署
  • 服务重启不丢失上下文

Week 3-4: 意图识别升级

  • 实现LLM意图判断2天
  • A/B测试对比1天
  • 上线灰度发布1天

预期效果:

  • 意图识别准确率保持100%
  • 支持复杂自然语言表达

Week 5: 多项目支持

  • 用户绑定默认项目2天

预期效果:

  • 支持多个IIT项目并行

📝 债务跟踪

已清偿债务

债务项 清偿时间 方案
AI幻觉问题 2026-01-03 RAG数据注入 + 严格System Prompt
上下文丢失 2026-01-03 SessionMemory最近3轮
响应速度慢 2026-01-04 优化意图识别 + 异步处理

进行中债务

债务项 负责人 预计完成
- -

待处理债务

见上文优先级列表


🔗 相关文档


文档维护: 技术团队
最后更新: 2026-01-04
版本历史:

  • v1.0 (2026-01-04): 初始版本Phase 1.5完成后整理