# IIT / CRA Agent 最小复现项目对账执行手册(Phase 1) > 文档版本:v1.0 > 创建日期:2026-03-08 > 目标:用最小复现项目定位根因,不做盲修 > 适用问题:报告与事件不一致、AI 实时流水不一致、AI 对话结论错误 --- ## 1. 执行原则 1. **先对账,后修复**:每个异常必须先确认“错在数据、规则、聚合、还是展示”。 2. **单项目封闭验证**:只使用“纳入排除标准测试”项目,不混其他项目。 3. **同一时间窗口**:所有 API / SQL 在同一时段采样,避免时间漂移。 4. **一条问题一条证据链**:必须保留“输入 -> 处理中间态 -> 输出”。 --- ## 2. 最小复现项目准备 项目:`纳入排除标准测试` 固定对象: - 患者:`2 / 3 / 4`(至少包含不完整录入与违规样本) - 事件:筛选期 + 第一次月经周期结束时(若项目定义如此) - 规则:D1/D2/D3/D4/D6 至少各有 1 条命中场景 冻结窗口: - 执行前停止自动批任务(避免数据持续变化) - 手动执行一次“一键全量质控”,记录触发时间 T0 - 所有采样以 T0 后 1-3 分钟为准 --- ## 3. 四层对账流程(按顺序) ## 3.1 事实层(REDCap 是否联通) 目标:确认“源头有数据”。 检查项: - REDCap 中是否存在目标患者/事件数据 - `record_summary` 是否包含对应 `record_id` - `SyncManager` 最近同步时间是否晚于 T0 判定: - REDCap 有、平台无 -> 联通/同步问题 - REDCap 无 -> 上游录入问题,不是质控引擎问题 ## 3.2 执行层(规则是否正确执行) 目标:确认“规则判断是否符合临床预期”。 检查项: - `qc_field_status` 是否有该患者对应 D1/D2/D3/D6 记录 - `status/severity/message/actual_value/expected_value` 是否合理 - `qc_event_status` 是否与字段级状态一致 判定: - 执行结果本身错 -> 规则定义/引擎问题 - 执行结果正确、展示错 -> 聚合/前端问题 ## 3.3 聚合层(报表和大盘是否同口径) 目标:确认“同名指标是否来自同一口径与同一快照”。 检查项: - 大盘:`getQcCockpitData` - 报告:`getQcReport` / `refreshQcReport` - 趋势:`getTrend` - D1/D2/D3D4/D6:各报表 API 重点看: - 通过率口径(按受试者 vs 按日志) - 健康分是否来自 `healthScore` 真实值 - 报告缓存是否过期/未刷新 ## 3.4 对话层(AI 工具链路是否选对) 目标:确认“AI 回答错误是查询错还是推理错”。 检查项: - 问题触发了哪个工具(`read_report` / `look_up_data` / `check_quality` / `search_knowledge`) - 工具返回数据是否完整(如实验室检查字段是否缺失) - 最终回答是否与工具结果一致 判定: - 工具返回错 -> 数据查询/映射/项目隔离问题 - 工具返回对、回答错 -> Prompt/回答策略问题 --- ## 4. 针对当前三大类问题的定位矩阵 ## 4.1 第一大类:报告与关键事件 | 现象 | 优先怀疑 | 第一检查点 | |---|---|---| | D1/D2/D3D4/D6 与维度评分不一致 | 聚合口径漂移 | `getStats()` vs 各报表 SQL | | 质控 0 个受试者 | 执行未落库或 projectId 错 | `qc_field_status` 是否有该项目数据 | | 待处理 252 但健康分 100 | 健康分 fallback / 评分权重缺陷 | 前端 `healthScore` fallback、HealthScoreEngine 维度权重 | | 上方通过率 100,下方趋势 33 | 趋势口径不同 | `getTrend()` 当前读 `iit_qc_logs` | | 质控完成无热力图 | `qc_event_status` 空或事件列构建失败 | `getHeatmapData()` 查询结果 | | 执行摘要无信息 | 报告缓存旧 / 生成失败 | `iit_qc_reports` 最新记录 + refresh | | 报告分 64 vs 大盘 100 | 报告快照与实时不一致 | `report.generatedAt` vs cockpit now | | D1 无数据 | D1 规则缺失或 rule_category 错 | `qc_field_status where D1` | | D2 事件数=1 且明细异常 | D2 统计规则/activeEvents定义不清 | `getCompletenessReport()` 的 byRecordEvent | | 已回复仍显示 0 | 状态机未推进或统计口径错 | `iit_equeries.status` 分布 | | 无“重开质疑”操作 | 前端缺动作入口(后端有状态) | EQueryPage 操作列 | ## 4.2 第二大类:AI 实时工作流水 | 现象 | 优先怀疑 | 第一检查点 | |---|---|---| | 流水问题总数 444 vs 待处理 252 | 指标对象不同 | 时间线来自 `qc_field_status`,待处理来自 `iit_equeries` | | 事件编码生成逻辑不明 | 事件标签映射缺失 | `eventLabel` 来源:`qc_event_status` / fallback | | 日期筛选按钮无效 | API 过滤未生效或前端未传 | `getTimeline(date=YYYY-MM-DD)` 返回是否变化 | ## 4.3 第三大类:AI 对话助手 | 现象 | 优先怀疑 | 第一检查点 | |---|---|---| | 已签署知情显示 0 | 工具选路错误或字段未映射 | `look_up_data` 查询字段覆盖 | | 3号患者严重问题被说成无问题 | read_report 缓存滞后或筛选逻辑错 | `QcReportService` 缓存时间与 issue 列表 | | 总体通过率异常(分项非0,总体0) | 聚合口径错误 | 报告 summary.passRate 公式 | | 查询患者2信息不全 | 工具默认返回字段不完整 | `look_up_data` 默认 data 结构 | | 4号患者访视名错误/状态描述偏差 | eventLabel 回退技术ID + 业务叙述模板粗糙 | `eventLabel` 链路与回答模板 | --- ## 5. 执行清单(逐项打勾) ## 5.1 一次完整排查(建议 2-3 小时) - [ ] 执行 `batch-qc`,记录 T0、返回 `totalRecords/totalEventCombinations/passRate` - [ ] 拉取驾驶舱:`qc-cockpit` - [ ] 拉取报告:`qc-cockpit/report`(先读缓存,再 refresh) - [ ] 拉取趋势:`qc-cockpit/trend` - [ ] 拉取时间线:`qc-cockpit/timeline` - [ ] 拉取 D1/D2/D3D4/D6 报表 - [ ] 拉取 `field-issues`(critical + warning) - [ ] 拉取 eQuery stats 与 list - [ ] 对 5 条 AI 问答样例做工具链路记录 ## 5.2 SQL 对账模板(只读) > 以下为只读核对 SQL,请在测试库或只读会话执行。 ```sql -- 1) 项目级统计快照 SELECT project_id, total_records, passed_records, failed_records, warning_records, health_score, health_grade, d1_pass_rate, d2_pass_rate, d3_pass_rate, d5_pass_rate, d6_pass_rate, d7_pass_rate FROM iit_schema.qc_project_stats WHERE project_id = :project_id; ``` ```sql -- 2) 字段级问题总量(SSOT) SELECT status, severity, rule_category, COUNT(*) AS cnt FROM iit_schema.qc_field_status WHERE project_id = :project_id GROUP BY status, severity, rule_category ORDER BY rule_category, status, severity; ``` ```sql -- 3) 事件级状态 SELECT record_id, event_id, event_label, status, fields_total, fields_passed, fields_failed, fields_warning FROM iit_schema.qc_event_status WHERE project_id = :project_id ORDER BY record_id, event_id; ``` ```sql -- 4) eQuery 状态分布 SELECT status, COUNT(*) AS cnt FROM iit_schema.iit_equeries WHERE project_id = :project_id GROUP BY status ORDER BY status; ``` --- ## 6. 修复优先级建议(按风险) P0(先修): 1. 通过率口径统一(大盘/趋势/报告明确区分) 2. 健康分来源统一(禁前端 fallback 推算) 3. 报告缓存刷新策略(批量质控后强制刷新并透出快照时间) 4. 时间线与 eQuery 统计文案区分(避免同名误读) P1(随后): 1. EQuery “重开”前端操作入口(后端状态机已支持) 2. D2“活跃事件/缺失字段”定义可视化说明 3. AI 对话输出模板升级(访视表格化 + 证据引用) P2(优化): 1. 工具调用 trace 可视化(问题 -> 工具 -> 结果 -> 回答) 2. 指标字典落地到接口 schema,前后端共享类型 --- ## 7. 本阶段交付物要求 完成 Phase 1 后,必须输出: 1. `问题-根因对照表`(你列出的每条问题都要有结论) 2. `证据包`(API 返回 + SQL 结果 + 截图) 3. `修复方案分批计划`(P0/P1/P2 + 影响面 + 回归用例) 没有这三项,不进入大规模代码修改。