Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/05-测试文档/IIT Manager Agent V2.9 补充:业务规则与数据治理细则 (1).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

200 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **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=>