Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/04-开发计划/01-数据库设计.md
HaHafeng 5db4a7064c feat(iit): Implement real-time quality control system
Summary:

- Add 4 new database tables: iit_field_metadata, iit_qc_logs, iit_record_summary, iit_qc_project_stats

- Implement pg-boss debounce mechanism in WebhookController

- Refactor QC Worker for dual output: QC logs + record summary

- Enhance HardRuleEngine to support form-based rule filtering

- Create QcService for QC data queries

- Optimize ChatService with new intents: query_enrollment, query_qc_status

- Add admin batch operations: one-click full QC + one-click full summary

- Create IIT Admin management module: project config, QC rules, user mapping

Status: Code complete, pending end-to-end testing
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 21:56:11 +08:00

14 KiB
Raw Blame History

IIT Manager Agent 数据库设计

版本: V2.9
更新日期: 2026-02-05
关联文档: IIT Manager Agent V2.6 综合开发计划

V2.9.1 更新

  • 扩展 iit_skills 表支持 Cron Skill主动提醒
  • 扩展 iit_conversation_history 表增加反馈字段
  • 更新 iit_project_memory 内容结构(用户画像)
  • 新增 iit_pii_audit_logPII 脱敏审计日志(合规必需)

1. 数据库表总览

表名 用途 Phase 优先级
iit_skills Skill 配置存储 1 P0
iit_field_mapping 字段名映射字典 1 P0
iit_pii_audit_log PII 脱敏审计日志 1.5 P0
iit_task_run SOP 任务执行记录 2 P0
iit_pending_actions 待处理的违规记录 2 P0
iit_conversation_history 对话历史(流水账) 2 P1
iit_project_memory 项目级热记忆Markdown 2 P1
iit_weekly_reports 周报归档(历史书) 4 P1
iit_agent_trace ReAct 推理轨迹 5 P2
iit_form_templates 表单模板(视觉识别) 6 延后

2. Phase 1基础配置表

2.1 iit_skills - Skill 配置存储

model IitSkill {
  id           String   @id @default(uuid())
  projectId    String   // 绑定项目
  skillType    String   // qc_process | daily_briefing | general_chat | weekly_report | visit_reminder
  name         String   // 技能名称
  config       Json     // 核心配置 JSONSOP 流程图)
  isActive     Boolean  @default(true)
  version      Int      @default(1)
  
  // V2.9 新增:主动触发能力
  triggerType  String   @default("webhook") // 'webhook' | 'cron' | 'event'
  cronSchedule String?  // Cron 表达式,如 "0 9 * * *" (每天9点)
  
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  @@unique([projectId, skillType])
  @@map("iit_skills")
  @@schema("iit_schema")
}

触发类型说明

triggerType 触发方式 示例场景
webhook 用户消息触发(默认) 质控任务、问答查询
cron 定时触发 访视提醒、周报生成
event 事件触发(预留) AE 预警、数据变更通知

Skill 配置示例SOP 流程图)

{
  "name": "肺癌研究入组质控",
  "start_node": "baseline_check",
  "nodes": {
    "baseline_check": {
      "type": "hard_rule",
      "rules": [
        { "field": "age", "logic": { ">=": [{"var":"age"}, 18] }, "message": "年龄<18岁" },
        { "field": "age", "logic": { "<=": [{"var":"age"}, 75] }, "message": "年龄>75岁" },
        { "field": "ecog", "logic": { "<=": [{"var":"ecog"}, 2] }, "message": "ECOG>2" }
      ],
      "on_pass": "history_check",
      "on_fail": "end_with_violation"
    },
    "history_check": {
      "type": "soft_instruction",
      "instruction": "检查既往史,排除间质性肺炎、活动性感染、严重心血管疾病。",
      "tools": ["read_clinical_data"],
      "on_pass": "medication_check",
      "on_fail": "end_review_required"
    },
    "human_review": {
      "type": "human_review",
      "description": "需要 CRC 人工复核",
      "on_approve": "end_success",
      "on_reject": "end_rejected"
    }
  }
}

Cron Skill 配置示例V2.9 新增)

{
  "skillType": "visit_reminder",
  "name": "每日访视提醒",
  "triggerType": "cron",
  "cronSchedule": "0 9 * * *",
  "config": {
    "start_node": "check_upcoming_visits",
    "nodes": {
      "check_upcoming_visits": {
        "type": "soft_instruction",
        "instruction": "查询未来 3 天内到期的访视,生成提醒列表",
        "tools": ["read_clinical_data"],
        "on_pass": "send_reminder",
        "on_fail": "end_no_visits"
      },
      "send_reminder": {
        "type": "soft_instruction",
        "instruction": "根据用户画像选择合适的通知方式和语气,发送提醒",
        "tools": ["send_message"],
        "on_pass": "end_success"
      }
    }
  }
}

2.2 iit_field_mapping - 字段名映射字典

model IitFieldMapping {
  id          String   @id @default(uuid())
  projectId   String   // 项目级别映射
  aliasName   String   // LLM 可能传的名称(如 "gender", "性别"
  actualName  String   // REDCap 实际字段名(如 "sex"
  createdAt   DateTime @default(now())

  @@unique([projectId, aliasName])
  @@index([projectId])
  @@map("iit_field_mapping")
  @@schema("iit_schema")
}

初始化示例

INSERT INTO iit_field_mapping (project_id, alias_name, actual_name) VALUES
('project-uuid', 'age', 'age_calculated'),
('project-uuid', '年龄', 'age_calculated'),
('project-uuid', 'ecog', 'ecog_score'),
('project-uuid', '既往史', 'medical_history_text'),
('project-uuid', 'history', 'medical_history_text'),
('project-uuid', '性别', 'sex'),
('project-uuid', 'gender', 'sex');

2.5 Phase 1.5隐私安全表P0 合规必需)

2.5.1 iit_pii_audit_log - PII 脱敏审计日志

重要:临床数据包含大量患者隐私信息(姓名、身份证、手机号),在调用第三方 LLM 之前必须脱敏。 此表用于存储脱敏记录,便于事后合规审计。

model IitPiiAuditLog {
  id            String   @id @default(uuid())
  projectId     String
  userId        String   // 操作者
  sessionId     String   // 会话 ID关联 conversation_history
  
  // 脱敏内容(加密存储)
  originalHash  String   // 原始内容的 SHA256 哈希(不存明文)
  maskedPayload String   @db.Text  // 脱敏后发送给 LLM 的内容
  maskingMap    String   @db.Text  // 加密存储的映射表 { "[PATIENT_1]": "张三", ... }
  
  // 元数据
  piiCount      Int      // 检测到的 PII 数量
  piiTypes      String[] // 检测到的 PII 类型 ['name', 'id_card', 'phone']
  llmProvider   String   // 'qwen' | 'deepseek' | 'openai'
  
  createdAt     DateTime @default(now())

  @@index([projectId, userId])
  @@index([sessionId])
  @@index([createdAt])
  @@map("iit_pii_audit_log")
  @@schema("iit_schema")
}

PII 类型说明

PII 类型 正则模式 脱敏示例
name 中文姓名2-4字 张三 → [PATIENT_1]
id_card 身份证号18位 420101... → [ID_CARD_1]
phone 手机号11位 13800138000 → [PHONE_1]
mrn 病历号 MRN123456 → [MRN_1]

脱敏流程

用户输入: "张三身份证420101199001011234今天血压偏高"
    ↓ AnonymizerService.mask()
LLM 收到: "[PATIENT_1](身份证[ID_CARD_1])今天血压偏高"
    ↓ 同时写入 iit_pii_audit_log
    ↓ LLM 处理
LLM 返回: "[PATIENT_1] 的血压需要关注..."
    ↓ AnonymizerService.unmask()
用户看到: "张三 的血压需要关注..."

3. Phase 2SOP 执行与记忆表

3.1 iit_task_run - SOP 任务执行记录

model IitTaskRun {
  id              String    @id @default(uuid())
  projectId       String
  skillId         String    // 关联的 Skill
  recordId        String?   // 关联的患者(如有)
  triggeredBy     String    // 触发者 userId
  status          String    // RUNNING | SUSPENDED | COMPLETED | FAILED
  currentNode     String?   // 当前执行到的节点
  trace           Json?     // 执行轨迹
  resumeCallback  String?   // SUSPENDED 时,恢复后的下一步
  rejectCallback  String?   // SUSPENDED 被拒绝时的下一步
  suspendedAt     DateTime?
  resumedAt       DateTime?
  completedAt     DateTime?
  createdAt       DateTime  @default(now())
  updatedAt       DateTime  @updatedAt

  @@index([projectId, status])
  @@index([recordId])
  @@map("iit_task_run")
  @@schema("iit_schema")
}

3.2 iit_pending_actions - 待处理的违规记录

model IitPendingAction {
  id          String   @id @default(uuid())
  projectId   String
  taskRunId   String   // 来源任务
  recordId    String?  // 关联患者
  actionType  String   // violation | warning | review_required
  field       String?  // 违规字段
  message     String   // 违规描述
  severity    String   // error | warning | info
  resolvedBy  String?  // 处理人
  resolvedAt  DateTime?
  resolution  String?  // 处理结论
  createdAt   DateTime @default(now())

  @@index([projectId, actionType])
  @@index([recordId])
  @@map("iit_pending_actions")
  @@schema("iit_schema")
}

3.3 iit_conversation_history - 对话历史(流水账)

V2.8 设计:这是原始对话流水,不直接注入 Prompt只用于生成周报

V2.9 新增:增加反馈字段,支持用户点赞/点踩

model IitConversationHistory {
  id          String   @id @default(uuid())
  projectId   String
  userId      String
  recordId    String?  // 关联的患者(如有)
  role        String   // user | assistant
  content     String   @db.Text
  intent      String?  // 识别出的意图类型
  entities    Json?    // 提取的实体 { record_id, visit, ... }
  
  // V2.9 新增:反馈循环
  feedback    String?  // 'thumbs_up' | 'thumbs_down' | null
  feedbackReason String? // 点踩原因:'too_long' | 'inaccurate' | 'unclear'
  
  createdAt   DateTime @default(now())

  @@index([projectId, userId])
  @@index([projectId, recordId])
  @@index([createdAt])
  @@map("iit_conversation_history")
  @@schema("iit_schema")
}

3.4 iit_project_memory - 项目级热记忆

V2.8 核心表:存储 Markdown 格式的热记忆,每次对话都注入 System Prompt

V2.9 扩展:增加用户画像结构

model IitProjectMemory {
  id          String   @id @default(uuid())
  projectId   String   @unique
  content     String   @db.Text  // Markdown 格式的热记忆
  lastUpdatedBy String  // 'system_daily_job' | 'admin_user_id' | 'profiler_job'
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@map("iit_project_memory")
  @@schema("iit_schema")
}

内容示例V2.9 增强版)

# 用户画像 (User Profiles)

## 张医生 (user_id: zhangyi)
- **角色**: PI
- **偏好**: 简洁汇报,只看结论,不要废话
- **关注点**: AE、入组进度
- **最佳通知时间**: 08:30
- **禁令**: 回复不超过 100 字
- **反馈统计**: 👍 12 / 👎 1

## 王护士 (user_id: wanghushi)
- **角色**: CRC
- **偏好**: 详细步骤,需要解释
- **关注点**: 访视安排、数据录入
- **最佳通知时间**: 09:00

# 当前状态 (Active Context)
- 当前阶段:入组冲刺期
- 重点关注P005 患者依从性差,需每日提醒
- 本周目标:完成 3 例入组
- P003 SAE 已判定为"可能无关"2月5日 PI 决策)

# 常见问题 (FAQ)
- 访视窗口V1 Day 1±3, V2 Day 28±7

# 系统禁令 (Rules)
- 严禁在未授权情况下删除数据
- 写操作必须经过人工确认

4. Phase 4周报归档

4.1 iit_weekly_reports - 周报归档(历史书)

V2.8 核心表:存储每周的关键决策、进度、踩坑记录

model IitWeeklyReport {
  id          String   @id @default(uuid())
  projectId   String
  weekNumber  Int      // 第几周(从项目开始计算)
  weekStart   DateTime // 周起始日期
  weekEnd     DateTime // 周结束日期
  summary     String   @db.Text  // Markdown 格式的周报内容
  metrics     Json?    // 结构化指标 { enrolled: 3, queries: 5, ... }
  createdBy   String   // 'system_scheduler' | 'admin_user_id'
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@unique([projectId, weekNumber])
  @@index([projectId])
  @@map("iit_weekly_reports")
  @@schema("iit_schema")
}

内容示例

## Week 5 (2026-02-03 ~ 2026-02-09)

### 进度
- 本周新入组3 例
- 累计入组15 / 30 例
- 完成率50%

### 关键决策
- 2026-02-05: PI 会议决定放宽入排标准,允许 ECOG 3 分患者入组
- 2026-02-07: 确认 P003 AE 与研究药物"可能无关"

### 踩坑记录
- 曾尝试自动录入化验单,因 OCR 精度不足失败,已回退为人工复核

### 待办
- 清理 1 月份遗留的 Query
- 准备 2 月底期中分析数据

5. Phase 5ReAct 追踪表

5.1 iit_agent_trace - ReAct 推理轨迹

用于调试,不发送给用户,仅在 Admin 后台查看

model IitAgentTrace {
  id          String   @id @default(uuid())
  projectId   String
  userId      String
  query       String   @db.Text  // 用户原始问题
  intentType  String?  // 识别的意图类型
  trace       Json     // ReAct 的完整思考过程
  tokenUsage  Int?     // 消耗的 Token 数
  duration    Int?     // 执行时长ms
  success     Boolean
  createdAt   DateTime @default(now())

  @@index([projectId, createdAt])
  @@index([userId])
  @@map("iit_agent_trace")
  @@schema("iit_schema")
}

6. Phase 6视觉能力表延后到 V3.0

6.1 iit_form_templates - 表单模板

model IitFormTemplate {
  id          String   @id @default(uuid())
  projectId   String
  formName    String   // REDCap 表单名称
  fieldSchema Json     // 表单字段结构
  keywords    String[] // 用于匹配的关键词
  createdAt   DateTime @default(now())

  @@map("iit_form_templates")
  @@schema("iit_schema")
}

7. 数据库迁移命令

# 生成迁移
npx prisma db push

# 生成客户端
npx prisma generate

# 查看表结构
npx prisma studio

8. 索引设计总结

索引 用途
iit_skills [projectId, skillType] (unique) 按项目查询 Skill
iit_field_mapping [projectId, aliasName] (unique) 字段映射查询
iit_task_run [projectId, status] 查询运行中/挂起的任务
iit_conversation_history [projectId, userId] 按用户查询对话
iit_conversation_history [projectId, recordId] 按患者查询对话
iit_conversation_history [createdAt] 按时间范围查询
iit_weekly_reports [projectId, weekNumber] (unique) 按周查询报告
iit_agent_trace [projectId, createdAt] 按时间查询调试日志

文档维护人AI Agent
最后更新2026-02-05