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>
This commit is contained in:
2026-02-07 21:56:11 +08:00
parent 0c590854b5
commit 5db4a7064c
74 changed files with 13383 additions and 2129 deletions

View File

@@ -0,0 +1,200 @@
# **IIT Manager Agent V2.9 补充:业务规则与数据治理细则**
**文档性质:** 业务逻辑落地方案
**评审结论:** 4 点建议逻辑清晰,完全可行。本方案在原有基础上进行了 Postgres 原生特性的优化。
## **1\. 质控规则来源:自动化与人工的完美结合**
**评价**:非常合理。这是降低实施成本的关键。如果全部靠人工配,运营会累死;如果全部靠自动,医学逻辑会缺失。
**落地优化建议**
我们在 iit\_skills 表的 JSON 配置中,引入 **source** 字段来标记规则来源,方便管理。
// qc\_skill.json (最终生成的配置文件)
{
"hard\_rules": \[
// \=== 自动生成区 (Auto-Generated) \===
{
"field": "age",
"logic": { "\>=": \[{ "var": "age" }, 18\] },
"message": "年龄必须 \>= 18",
"source": "meta\_validation\_min", // 标记来源
"level": "warning"
},
{
"field": "informed\_consent\_date",
"logic": { "\!=": \[{ "var": "informed\_consent\_date" }, ""\] },
"message": "知情同意日期必填",
"source": "meta\_required",
"level": "error"
},
// \=== 人工配置区 (Manual) \===
{
"field": "visit\_date",
"logic": { "\<=": \[{ "var": "visit\_date" }, { "var": "today" }\] },
"message": "访视日期不能是未来",
"source": "manual\_config",
"level": "error"
}
\]
}
**实施流程**
1. **Sync**: RedcapAdapter 拉取 Metadata。
2. **Generate**: 代码遍历 Metadata生成一个 draft\_rules 数组。
3. **Merge**: 将 draft\_rules 与数据库里已有的 manual\_rules 合并。
4. **Confirm**: 在管理端展示,人工确认后保存。
## **2\. 质控数据存储:利用 JSONB 简化分层**
**评价**:分层思路是对的,但**建议简化物理表结构**。
如果每个字段的错误都存一行记录iit\_qc\_results当项目有 1000 个病人 x 400 个变量时,这张表会瞬间爆炸(千万级行数),查询变慢。
**Postgres 优化方案**
利用 Postgres 强大的 **JSONB** 能力12合并保留3
### **优化后的 Schema**
**(1) \+ (2) 合并为iit\_qc\_logs (记录级 \+ 字段级详情)**
model IitQcLog {
id String @id @default(uuid())
projectId String
recordId String
eventId String
// 核心结果
status String // 'PASS' | 'FAIL' | 'WARNING'
// 字段级详情,直接存 JSONB
// 格式: \[{ field: "age", error: "范围越界", level: "RED" }, { ... }\]
// 优势: Postgres 支持对 JSONB 内部字段建立索引,查询速度一样快,但表行数少 100 倍
issues Json
ruleVersion String // 对应问题4的解决方案
createdAt DateTime @default(now())
@@index(\[projectId, recordId\])
@@map("iit\_qc\_logs")
}
**(3) 保留iit\_qc\_project\_stats (每日汇总)**
* 用于 Dashboard 快速展示,避免每次都 COUNT(\*) 几百万行日志。
## **3\. 主动干预分级:防打扰机制**
**评价**:非常棒的\*\*“抗疲劳设计”\*\*。如果不分级PI 一天收 50 条推送,第二天就会把机器人拉黑。
**落地实现**
在 WechatService 中实现一个 **Notification Filter**
// NotificationFilter.ts
async function handleAlert(projectId, logs) {
// 1\. 红色:立即发送
const redIssues \= logs.filter(i \=\> i.level \=== 'RED');
if (redIssues.length \> 0\) {
await sendWechat("🚨 紧急报警: 发现 SAE 或严重违规...");
await sendSms("..."); // 可选
}
// 2\. 黄色:存入每日摘要队列 (Redis/DB),不立即发
const yellowIssues \= logs.filter(i \=\> i.level \=== 'YELLOW');
if (yellowIssues.length \> 0\) {
await addToDailyDigest(projectId, yellowIssues);
}
// 3\. 绿色:只记录日志,完全不发
}
## **4\. 潜在问题与解决方案:技术细节补全**
你提出的解决方案都很到位,我从技术落地角度做一点补充。
### **(1) 规则版本管理**
* **你的方案**:增加 rule\_version。✅
* **补充**iit\_skills 表本身应该有一个 version 字段(自增 Int。每次生成 IitQcLog 时,把这个 version 抄进去。这样以后回溯时,就知道当时是按哪套法律判的案。
### **(2) 性能问题**
* **你的方案**Webhook 只查单条,全量用异步。✅
* **补充**:这就是我们 V2.9 架构的天然优势。
* **实时**WebhookController \-\> SopEngine (单条)。
* **全量**pg-boss 定时任务 \-\> BatchQcJob (批量)。
### **(3) 重复质控 (防抖)**
* **你的方案**幂等性检查5分钟。✅
* **技术落地**:利用 pg-boss 的 **Debounce** 功能。
// WebhookController.ts
// 如果 5 分钟内来了同一个 record\_id 的 Webhook只执行最后一次
await boss.send('qc-job', { recordId }, {
singletonKey: \`qc-${projectId}-${recordId}\`, // 唯一键
singletonSeconds: 300 // 300秒防抖窗口
});
这样根本不需要写复杂的 Redis 锁pg-boss 帮你搞定。
### **(4) 字段映射变更**
* **你的方案**:重新同步。✅
* **补充**:增加一个 **"变更检测"**。
* 每次 Webhook 数据来了,检查一下 payload 里的字段名是否在我们的 iit\_field\_mapping 里。如果不认识,说明 REDCap 改了Agent 自动触发一次 Metadata Sync 任务。
## **5\. 异步架构落地场景 (Asynchronous Implementation)**
为了保证高并发下的系统稳定性,本方案在以下 4 个关键环节强制使用异步处理(基于 pg-boss
### **5.1 核心质控执行 (Core Execution)**
* **场景**CRC 在 REDCap 点击保存,触发 DET Webhook。
* **机制**
* **同步层 (Node.js)**:接收 HTTP 请求 ![][image1] 校验签名 ![][image1] 写入 pg-boss 队列 ![][image1] 立即返回 200 OK (耗时 \< 10ms)。
* **异步层 (Worker)**:后台 Worker 从队列获取 record\_id ![][image1] 拉取数据 ![][image1] 执行 Engine A/B ![][image1] 写入日志。
* **价值**:确保 EDC 前端操作零卡顿,彻底解耦录入与质控。
### **5.2 批量全量回溯 (Batch Processing)**
* **场景**:规则变更后(如入排标准修改),需要重新检查历史数据;或每日定时巡检。
* **机制**
* **调度器**:创建 BatchQcJob。
* **分片执行**:将 1000 条记录拆分为 20 个子任务(每批 50 条),并行推入队列。
* **流控**Worker 控制并发数,避免瞬间打爆 REDCap API。
### **5.3 "黄色"报警汇总 (Delayed Notifications)**
* **场景**:发现非紧急的逻辑矛盾或缺失值(黄色/绿色级别)。
* **机制**
* **写入**:质控 Worker 发现问题 ![][image1] 写入 iit\_qc\_logs ![][image1] 标记为 pending\_digest。
* **发送**:每日下午 17:00 定时任务触发 ![][image1] 聚合当日所有黄色问题 ![][image1] 生成一份简报发送给 PI。
* **价值**:防消息轰炸,提升用户体验。
### **5.4 规则自动同步 (Metadata Sync)**
* **场景**:项目初始化或 REDCap 字段变更。
* **机制**
* **触发**:用户点击"同步字段"按钮。
* **执行**:前端收到"任务已提交" ![][image1] 后台 Worker 调用 exportMetadata (耗时较长) ![][image1] 解析并更新 iit\_field\_mapping ![][image1] 更新任务状态。
* **价值**:防止长连接超时。
## **6\. 总结**
这 4 个建议是**完全成熟的生产级方案**。
* 它们解决了 **"规则从哪来"** (1)。
* 解决了 **"数据怎么存"** (2)。
* 解决了 **"怎么发通知"** (3)。
* 解决了 **"异常怎么办"** (4)。
配合之前的 **V2.9 极简架构**Engine \+ Tools \+ Skill以及本补充文档中的 **异步处理规范**,这套系统已经具备了极高的商业交付价值。建议直接纳入 PRD 开发。
[image1]: <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAXCAYAAADpwXTaAAAAX0lEQVR4XmNgGAWjYCQAeXn50+hiZAOgYU/QxcgGcnJy2kA8HV2cbAB03SwgDkIXB0lIkomnAfF1oBHM1DBsERCfRzGMHCCPy5ukAmgETEAXJwvIUzFpMMpTM9GOcAAAmV0cRTlI2MMAAAAASUVORK5CYII=>

View File

@@ -0,0 +1,93 @@
# **IIT Manager Agent智能化临床研究管理解决方案**
## **—— 策略汇报与核心机制讨论稿**
**汇报对象:** 临床研究负责人(PI)、申办方策略官、临床方法学专家
**汇报目标:** 确认 Agent 的行为准则、记忆逻辑与风险控制策略
**日期:** 2026-02-05
## **1\. 核心愿景:我们要打造什么样的 AI 助手?**
我们开发的不仅仅是一个问答机器人,而是一个**24/7 在线的、具备“长期记忆”与“合规意识”的虚拟项目经理**。
它旨在解决 IIT研究者发起的临床研究中的三大痛点
1. **数据质控滞后**:往往等到数据锁库前才发现录入错误,修正成本极高。
2. **项目记忆断层**CRC/CRA 人员流动导致对患者情况、历史决策的记忆丢失。
3. **执行偏差**方案Protocol执行细节依赖个人经验难以标准化。
## **2\. 策略架构:严谨与智能的“双脑”平衡**
为了适应临床研究既要“死扣方案”又要“灵活应变”的特点,我们设计了\*\*“双脑协同”\*\*模型:
### **🧠 左脑(严谨执行者)—— 对应“SOP 质控引擎”**
* **角色**像一位铁面无私的质控员QC
* **职责**执行入排标准、访视窗口、不良事件AE逻辑检查。
* **特点****零容忍**。它不依赖 AI 的“猜测”,而是基于既定的医学逻辑规则。如果方案规定年龄必须 \<75岁76岁的患者绝对无法通过。
* **价值**:确保合规性,规避审计风险。
### **🎨 右脑(智能助理)—— 对应“ReAct 推理引擎”**
* **角色**:像一位经验丰富的 CRC 组长。
* **职责**:回答模糊问题(“查一下最近发烧的病人”)、生成周报、解读复杂方案。
* **特点****灵活**。它能理解自然语言,综合多维度信息给出建议,并具备主动性(如主动提醒访视)。
* **价值**:提高效率,降低沟通成本。
## **3\. 核心议题记忆系统Memory System的策略设置**
**这是需要方法学团队重点讨论的部分。**
临床试验周期长达 1-3 年,普通的 AI 聊几句就“忘事”。我们设计了仿生的\*\*“三层记忆体系”\*\*,让 Agent 能够陪伴项目全周期。
### **3.1 记忆分层与业务含义**
| 记忆层级 | 对应业务场景 | 策略价值 |
| :---- | :---- | :---- |
| **L1短期流水账** *(Working Memory)* | **“刚才说了什么”** 如:刚才提到的患者 ID 是多少? | 保证对话连贯性,像人一样交流,无需重复上下文。 |
| **L2项目热记忆** *(Active Context)* | **“当前关注焦点”** 如P003 患者依从性差需重点盯防PI 偏好简报。 | **个性化与主动性**。Agent 知道每个人的角色偏好,也知道当前项目的“风险点”,不再是冷冰冰的机器。 |
| **L3项目历史书** *(Project Archive)* | **“项目大事记”** 如3个月前为什么修改了入排标准上周的 SAE 判定结论是什么? | **对抗人员流动**。即使 CRC 换人Agent 依然记得项目的所有历史决策和关键事件,实现“无缝交接”。 |
### **3.2 待讨论的策略问题(请方法学团队决策)**
**Q1什么样的信息值得进入“历史书”L3**
* *现状*:我们设定周报自动归档。
* *讨论*:是否需要将每一次“违规录入”都永久记录?还是只记录“经人工确认的违规”?这涉及到未来审计的痕迹管理。
**Q2Agent 的“主动性”边界在哪里(基于 L2 热记忆)?**
* *场景*Agent 发现某患者有脱落风险(基于过往对话)。
* *讨论*:是仅仅在周报中提示?还是每天早上发消息提醒 CRC还是直接向 PI 发出预警?我们需要定义“打扰预算”。
## **4\. 安全与合规:隐私保护策略**
针对临床数据的敏感性,我们在技术底层执行了严格的\*\*“隐私隔离策略”\*\*Phase 1.5 重点任务):
1. **PII 信息物理隔离**
* Agent 的大脑(大模型)**永远看不到**患者的真实姓名、身份证号或手机号。
* 所有敏感信息在发送给 AI 前,都会被替换为代号(如 \[PATIENT\_001\]AI 处理完逻辑后,再由本地系统还原显示给医生。
2. **数据所有权**
* 所有核心临床数据EDC数据只存储在私有数据库中不会用于训练公有模型。
## **5\. 开发路线图与里程碑**
我们计划用 **6周** 时间完成 MVP最小可行性产品交付
* **第 1-2 周(地基阶段)**:完成隐私脱敏中间件、基础质控规则(左脑)。
* *交付物*:能自动检查入排标准和逻辑错误的机器人。
* **第 3-4 周(记忆觉醒)**:上线三层记忆系统,实现周报自动生成。
* *交付物*:一个能记住项目历史、每周向 PI 汇报进度的助手。
* **第 5-6 周(智能进化)**:上线右脑推理与主动提醒功能。
* *交付物*:能回答复杂问题、主动管理任务的完整 Agent。
## **6\. 总结与下一步**
**IIT Manager Agent** 不是在替代 CRC而是在为临床研究团队配备一个\*\*“永远不睡觉、永远不遗忘、永远守规矩”\*\*的超级助理。
**下一步行动:**
1. **方法学团队**:请针对“记忆策略”中的 Q1、Q2 给出指导意见。
2. **技术团队**:立即启动 Phase 1 开发,优先部署隐私安全模块。

View File

@@ -0,0 +1,38 @@
# **Phase 1.5 补充任务:隐私安全与自动化工具**
**优先级:** P0 (必须在正式处理患者数据前完成)
**目的:** 解决合规性风险,降低项目部署的人力成本
## **1\. PII 数据脱敏中间件 (Anonymizer Middleware)**
在 SoftRuleEngine 和 ChatService 调用 LLM 之前,必须对文本进行处理。
* \[ \] **实现 PII 识别正则库**
* 识别身份证号、手机号、中文姓名2-4字、MRN 号。
* \[ \] **实现脱敏/还原逻辑**
* **发送前 (Masking)**: 张三 (ID: 420101...) \-\> \[PATIENT\_NAME\_1\] (ID: \[ID\_CARD\_1\])
* **接收后 (Unmasking)**: 将 LLM 回复中的 \[PATIENT\_NAME\_1\] 还原为 张三 显示给前端。
* \[ \] **安全审计日志**
* 记录所有发送给 LLM 的原始 Payload加密存储用于事后合规审计。
## **2\. Redcap Schema 自动对齐工具 (Auto-Mapper)**
减少 iit\_field\_mapping 的人工配置工作量。
* \[ \] **Data Dictionary 解析器**
* 读取 Redcap 导出的 Data Dictionary (CSV/JSON)。
* 提取所有字段的 Variable Name 和 Field Label。
* \[ \] **LLM 语义映射 Job**
* 输入:系统标准字段列表(如 age, gender, visit\_date
* 输入Redcap 字段列表(如 nl\_age, sex\_v2, d\_visit
* Prompt: "请将以下 Redcap 字段与系统标准字段进行语义匹配,返回 JSON 映射表。"
* \[ \] **人工确认 UI**
* 在管理后台提供一个界面,显示 LLM 猜测的映射关系,管理员点击 "Confirm" 后写入数据库。
## **3\. 错误处理与熔断机制**
* \[ \] **ReAct 循环熔断**
* 设置 SoftRuleEngine 最大重试次数为 3。
* 设置 ReActEngine 最大 Step 为 5。
* 超过限制时,返回固定的 Fallback 回复:"抱歉,该任务过于复杂或数据不足,请人工介入。"