# IIT Manager Agent V2.6 综合开发计划 > **版本:** V2.6(极简架构 + SOP状态机 + 双脑路由) > **日期:** 2026-02-02 > **团队规模:** 2人 > **预估周期:** 6周 > **核心目标:** 实现数据质控 Agent 的完整闭环 + 智能化交互 + 扩展能力层 --- ## 0. 架构适配性评估 本架构设计充分考虑了临床研究的多种业务场景,通过 **SOP状态机 + 双引擎 + 可扩展工具层** 的设计,实现了良好的适配性和扩展性。 ### 0.1 目标场景覆盖度 | 场景 | 覆盖度 | 核心支撑组件 | 备注 | |------|--------|-------------|------| | **1. 拍照识别 + 自动录入** | 🟡 60% | VisionService + ToolsService | 需新增视觉能力 | | **2. 数据质控** | 🟢 95% | HardRuleEngine + SoftRuleEngine | 核心场景,完全覆盖 | | **3. 入排标准判断** | 🟢 90% | SopEngine + 硬规则配置 | 配置 Skill 即可 | | **4. 方案偏离检测** | 🟢 80% | SoftRuleEngine + search_protocol | 需配置访视窗口规则 | | **5. AE事件检测** | 🟢 80% | 硬规则触发 + 软指令评估 | 需配置AE识别规则 | | **6. 伦理合规检测** | 🟢 80% | HardRuleEngine | 配置伦理规则即可 | | **7. 定期报告生成** | 🟡 50% | SchedulerService + ReportService | 需新增定时任务 | ### 0.2 架构扩展性评价 **为什么说这套架构适配性强?** | 扩展维度 | 实现方式 | 复杂度 | |----------|----------|--------| | **新增质控规则** | 在 `iit_skills` 表插入 JSON 配置 | ⭐ 低 | | **新增业务场景** | 新增 Skill 类型 + 配置 SOP 流程 | ⭐⭐ 中低 | | **新增工具能力** | 在 ToolsService 增加工具定义 | ⭐⭐ 中低 | | **新增数据源** | 新增 Adapter(如 OdmAdapter) | ⭐⭐⭐ 中 | | **新增交互入口** | 复用 ChatService 路由逻辑 | ⭐⭐ 中低 | **核心优势**: 1. **配置驱动**:新业务场景主要是"写配置"而非"写代码" 2. **插件式工具**:ToolsService 支持动态注册新工具 3. **引擎复用**:所有场景共享 HardRuleEngine / SoftRuleEngine 4. **SOP 状态机**:流程可配置、可追溯、可审计 ### 0.3 完整架构图(含扩展能力) ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 入口层 (Multi-Channel) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ 企业微信文本 │ │ 企业微信图片 │ │ PC Workbench │ │ 定时触发 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 路由层 (Router) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ ChatService │ │VisionService │ │ API Routes │ │Scheduler │ │ │ │ (文本路由) │ │ (图片识别) │ │ (REST API) │ │ (定时) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 调度层 (SopEngine) │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ Skill 配置 (Postgres) │ │ │ │ • qc_process (质控流程) • ae_detection (AE检测) │ │ │ │ • inclusion_check (入排) • protocol_deviation (方案偏离) │ │ │ │ • ethics_check (伦理) • weekly_report (周报) │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────┼──────────────────┐ │ │ ▼ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │HardRuleEngine│ │SoftRuleEngine│ │ReportService │ │ │ │ (CPU规则) │ │ (LLM推理) │ │ (报告生成) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 工具层 (ToolsService) │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │read_clinical_data│ │write_clinical_data│ │search_protocol │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │check_visit_window│ │assess_ae_causality│ │check_ethics │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │get_project_stats │ │manage_issue │ │send_notification│ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 适配器层 (Adapters) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │RedcapAdapter │ │ DifyClient │ │WechatAdapter │ │VLMAdapter│ │ │ │ (EDC数据) │ │ (知识库) │ │ (消息推送) │ │ (视觉) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 1. 架构决策总结 本计划基于以下 5 份架构设计文档的综合审查: | 文档 | 核心观点 | 状态 | |------|----------|------| | **架构决策白皮书** | 放弃 MCP/复杂框架,采用 Postgres-Only + Service-First | ✅ 认可 | | **V2.2 实施指南** | 混合双引擎(硬规则 + 软指令)+ 用户偏好 | ✅ 认可 | | **V2.2 工具泛化** | 3-5 个"瑞士军刀"通用工具替代 100 个专用工具 | ✅ 认可 | | **V2.3 健壮性设计** | 三层防御(模糊映射 + 容错重试 + 空结果兜底) | ✅ 认可 | | **V2.4 SOP状态机** | 粗粒度 SOP 节点 + 节点内 ReAct | ✅ 认可 | ### 1.1 最终架构选型:双脑路由模型 > **核心理念**:左脑(SOP) 保证严谨合规,右脑(ReAct) 提供灵活智能 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 企业微信 / 前端入口 │ │ [文本消息] [图片消息] [定时触发] │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 🧠 意图路由层 (IntentService) │ │ LLM 驱动,非正则匹配 │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 输入: "帮我查下那个发烧的病人是谁?" │ │ │ │ 输出: { type: "QA_QUERY", entities: {...}, needsClarification } │ │ │ └────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ 📐 左脑 (SOP) │ │ 🎨 右脑 (ReAct) │ │ ❓ 追问机制 │ │ 结构化任务 │ │ 开放性查询 │ │ 信息不全 │ │ 写操作必经 │ │ 只读不写 │ │ 主动澄清 │ │ │ │ │ │ │ │ • 质控流程 │ │ • 多步推理 │ │ • "请问您指的是 │ │ • 入排判断 │ │ • 模糊查询 │ │ 哪位患者?" │ │ • 数据录入 │ │ • 统计分析 │ │ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ SopEngine (状态机) │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 节点A: HardRuleEngine → 节点B: SoftRuleEngine → 节点C: ... │ │ │ └────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ ToolsService (工具层) │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 🔓 只读工具 (ReAct 可用) │ 🔒 读写工具 (仅 SOP 可用) │ │ │ │ • read_clinical_data │ • write_clinical_data │ │ │ │ • search_protocol │ • manage_issue │ │ │ │ • get_project_stats │ • update_record │ │ │ └─────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 适配器层 (Adapters) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │RedcapAdapter │ │ DifyClient │ │WechatAdapter │ │VLMAdapter│ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` **双脑对比**: | 维度 | 左脑 (SOP 状态机) | 右脑 (ReAct Agent) | |------|-------------------|-------------------| | **擅长** | 执行标准流程、合规检查 | 处理模糊提问、多步查询 | | **典型指令** | "对 P001 进行入排质控" | "帮我查下最近那个发烧的病人" | | **思维方式** | 线性执行 (Step 1 → Step 2) | 循环推理 (思考→查库→再思考) | | **数据权限** | 读写皆可 | **只读 (Read-Only)** | | **用户评价** | "靠谱但死板" | "聪明但不可控" | ### 1.2 核心设计原则 | 原则 | 描述 | |------|------| | **Postgres-Only** | 无 Redis,用 pg-boss 替代队列,用 Postgres 存储 Skill 配置 | | **Service-First** | 不用 MCP Server,用 Service Class 实现工具调用 | | **混合双引擎** | 硬规则(CPU) + 软指令(LLM),能用规则的不用 AI | | **SOP 状态机** | 粗粒度节点控制流程,节点内 ReAct 保持灵活性 | | **三层防御** | 字段映射 + 自我修正 + 空结果兜底 | --- ## 2. 现有代码资产盘点 ### 2.1 已完成的组件 | 组件 | 路径 | 状态 | 备注 | |------|------|------|------| | ChatService | `services/ChatService.ts` | ✅ 可复用 | 需扩展路由逻辑 | | SessionMemory | `agents/SessionMemory.ts` | ✅ 可复用 | 内存存储,支持过期清理 | | RedcapAdapter | `adapters/RedcapAdapter.ts` | ✅ 可复用 | 核心数据访问层 | | WechatService | `services/WechatService.ts` | ✅ 可复用 | 企业微信消息推送 | | DifyClient | `common/rag/DifyClient.ts` | ✅ 可复用 | 知识库检索 | | LLMFactory | `common/llm/adapters/LLMFactory.ts` | ✅ 可复用 | 统一 LLM 调用 | ### 2.2 待开发的组件 | 组件 | 优先级 | 说明 | |------|--------|------| | `iit_skills` 表 | P0 | Skill 配置存储 | | `iit_field_mapping` 表 | P0 | 字段名映射字典 | | `ToolsService` 类 | P0 | 统一工具管理 | | `HardRuleEngine` 类 | P0 | JSON Logic 执行器 | | `SoftRuleEngine` 类 | P1 | LLM 推理 + 自我修正 | | `SopEngine` 类 | P1 | 状态机调度器 | | `iit_user_preferences` 表 | P2 | 用户偏好存储 | --- ## 3. 开发阶段规划 ### Phase 1:基础设施层(Week 1) #### Day 1-2:数据库 Schema 扩展 **目标**:创建 Skill 配置和字段映射表 ##### 任务清单 - [ ] **T1.1** 设计 `iit_skills` 表结构 ```prisma model IitSkill { id String @id @default(uuid()) projectId String // 绑定项目 skillType String // qc_process | daily_briefing | general_chat name String // 技能名称 config Json // 核心配置 JSON isActive Boolean @default(true) version Int @default(1) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([projectId, skillType]) @@map("iit_skills") @@schema("iit_schema") } ``` - [ ] **T1.2** 设计 `iit_field_mapping` 表结构 ```prisma model IitFieldMapping { id String @id @default(uuid()) projectId String // 项目级别映射 aliasName String // LLM 可能传的名称(如 "gender", "性别") actualName String // REDCap 实际字段名(如 "sex") createdAt DateTime @default(now()) @@unique([projectId, aliasName]) @@map("iit_field_mapping") @@schema("iit_schema") } ``` - [ ] **T1.3** 执行数据库迁移 ```bash npx prisma db push npx prisma generate ``` - [ ] **T1.4** 插入测试数据(第一个 Skill 配置) **验收标准**: - [ ] 表创建成功 - [ ] 能正常 CRUD 操作 - [ ] 测试 Skill 配置可查询 --- #### Day 3-4:ToolsService 实现 **目标**:创建统一的工具管理层 ##### 任务清单 - [ ] **T2.1** 创建 `ToolsService.ts` ``` backend/src/modules/iit-manager/services/ToolsService.ts ``` - [ ] **T2.2** 实现工具定义(TOOL_DEFINITIONS) ```typescript export const TOOL_DEFINITIONS = [ { name: "read_clinical_data", description: "读取 REDCap 临床数据", parameters: { type: "object", properties: { record_id: { type: "string" }, fields: { type: "array", items: { type: "string" } } }, required: ["record_id", "fields"] } }, { name: "search_protocol", description: "检索研究方案文档", parameters: { ... } }, { name: "manage_issue", description: "提出质疑或发送通知", parameters: { ... } }, { name: "get_project_stats", description: "获取项目统计数据", parameters: { ... } } ]; ``` - [ ] **T2.3** 实现字段映射逻辑(第一层防御) ```typescript private async mapFields(projectId: string, fields: string[]): Promise { const mappings = await prisma.iitFieldMapping.findMany({ where: { projectId } }); const mappingDict = Object.fromEntries( mappings.map(m => [m.aliasName.toLowerCase(), m.actualName]) ); return fields.map(f => mappingDict[f.toLowerCase()] || f); } ``` - [ ] **T2.4** 实现 `executeTool()` 统一入口 - [ ] **T2.5** 实现空结果兜底(第三层防御) **验收标准**: - [ ] 4 个工具定义完成 - [ ] 字段映射逻辑生效 - [ ] 空结果返回友好消息 --- #### Day 5:HardRuleEngine 实现 **目标**:创建 CPU 执行的硬规则引擎 ##### 任务清单 - [ ] **T3.1** 安装 json-logic-js ```bash npm install json-logic-js npm install -D @types/json-logic-js ``` - [ ] **T3.2** 创建 `HardRuleEngine.ts` ``` backend/src/modules/iit-manager/engines/HardRuleEngine.ts ``` - [ ] **T3.3** 实现规则执行逻辑 ```typescript import jsonLogic from 'json-logic-js'; export class HardRuleEngine { run(rules: HardRule[], data: Record): RuleResult[] { const errors: RuleResult[] = []; for (const rule of rules) { const passed = jsonLogic.apply(rule.logic, data); if (!passed) { errors.push({ field: rule.field, message: rule.message, severity: rule.severity || 'error' }); } } return errors; } } ``` - [ ] **T3.4** 编写单元测试 **验收标准**: - [ ] 能正确执行 `{ ">=": [{ "var": "age" }, 18] }` 类规则 - [ ] 返回结构化错误列表 - [ ] 单元测试覆盖主要场景 --- ### Phase 2:引擎层实现(Week 2) #### Day 6-7:SoftRuleEngine 实现 **目标**:创建 LLM 推理引擎(含自我修正) ##### 任务清单 - [ ] **T4.1** 创建 `SoftRuleEngine.ts` ``` backend/src/modules/iit-manager/engines/SoftRuleEngine.ts ``` - [ ] **T4.2** 实现自我修正回路(第二层防御) ```typescript async runWithRetry( instruction: string, context: any, maxRetries: number = 3 ): Promise { let history: Message[] = [...]; for (let i = 0; i < maxRetries; i++) { const response = await this.llm.chat(history); if (response.hasToolCall) { try { const result = await this.tools.executeTool( response.toolName, response.args ); history.push({ role: 'tool', content: JSON.stringify(result) }); } catch (error) { // 自我修正:告诉 LLM 它错了 history.push({ role: 'user', content: `工具调用失败: ${error.message}。请检查参数并重试。` }); continue; } } else { return this.parseResult(response.content); } } return { passed: false, reason: '多次重试后仍失败' }; } ``` - [ ] **T4.3** 实现结果解析(要求 LLM 返回结构化 JSON) - [ ] **T4.4** 编写单元测试 **验收标准**: - [ ] 能调用工具并获取结果 - [ ] 工具失败时能自动重试 - [ ] 返回结构化判断结果 --- #### Day 8-9:SopEngine 实现 **目标**:创建 SOP 状态机调度器 ##### 任务清单 - [ ] **T5.1** 创建 `SopEngine.ts` ``` backend/src/modules/iit-manager/engines/SopEngine.ts ``` - [ ] **T5.2** 定义 Skill 配置格式(SOP 流程图) ```typescript interface SopConfig { name: string; start_node: string; nodes: { [nodeId: string]: { type: 'hard_rule' | 'soft_instruction'; // hard_rule 类型 rules?: HardRule[]; // soft_instruction 类型 instruction?: string; tools?: string[]; // 流转 on_pass: string; on_fail: string; on_error?: string; } } } ``` - [ ] **T5.3** 实现状态机执行逻辑 ```typescript async run(skillConfig: SopConfig, data: any): Promise { let currentNodeId = skillConfig.start_node; let context = { ...data }; const trace: TraceItem[] = []; while (currentNodeId && !currentNodeId.startsWith('end')) { const node = skillConfig.nodes[currentNodeId]; trace.push({ node: currentNodeId, timestamp: new Date() }); let result: NodeResult; if (node.type === 'hard_rule') { result = this.hardEngine.run(node.rules, context); } else { result = await this.softEngine.runWithRetry(node.instruction, context); } // 状态流转 currentNodeId = result.passed ? node.on_pass : node.on_fail; // 记录违规 if (!result.passed) { await this.savePendingAction(result); } } return { trace, finalState: currentNodeId }; } ``` - [ ] **T5.4** 实现违规记录保存(Shadow State) - [ ] **T5.5** 编写集成测试 **验收标准**: - [ ] 能按流程图顺序执行节点 - [ ] 硬规则和软指令都能正确调度 - [ ] 违规记录保存到 `iit_pending_actions` 表 --- #### Day 10:ChatService 集成 **目标**:将 SopEngine 集成到现有 ChatService ##### 任务清单 - [ ] **T6.1** 扩展意图识别逻辑 ```typescript private detectIntent(message: string): Intent { // 识别质控任务 if (/质控|检查|校验|QC/.test(message)) { return { type: 'qc_task', ... }; } // 其他意图... } ``` - [ ] **T6.2** 增加质控任务路由 ```typescript async handleMessage(userId: string, message: string): Promise { const intent = this.detectIntent(message); if (intent.type === 'qc_task') { // 路由到 SopEngine return this.handleQcTask(userId, intent); } // 普通问答继续走原有逻辑 return this.handleGeneralChat(userId, message); } ``` - [ ] **T6.3** 实现 `handleQcTask()` 方法 **验收标准**: - [ ] 质控任务走 SopEngine - [ ] 普通问答走原有 LLM 逻辑 - [ ] 两条路径互不干扰 --- ### Phase 3:配置与测试(Week 3) #### Day 11-12:第一个完整 Skill 配置 **目标**:配置第一个项目的质控流程 ##### 任务清单 - [ ] **T7.1** 设计肺癌研究质控流程(示例) ```json { "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" }, "medication_check": { "type": "soft_instruction", "instruction": "检查合并用药,排除其他抗肿瘤药物。", "tools": ["read_clinical_data"], "on_pass": "end_success", "on_fail": "end_review_required" } } } ``` - [ ] **T7.2** 插入 Skill 配置到数据库 - [ ] **T7.3** 配置字段映射 ```sql 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'); ``` **验收标准**: - [ ] Skill 配置存储成功 - [ ] 字段映射配置完成 --- #### Day 13-14:端到端测试 **目标**:完整流程测试 ##### 测试场景 | 场景 | 输入 | 期望输出 | |------|------|----------| | **场景1:年龄不合规** | `{ "age": 16, "ecog": 1 }` | 触发硬规则违规,记录到 pending_actions | | **场景2:病史违规** | `{ "age": 30, "ecog": 1, "history": "间质性肺炎" }` | AI 识别违规,转人工复核 | | **场景3:全部通过** | `{ "age": 45, "ecog": 0, "history": "无特殊" }` | 流程正常结束 | | **场景4:字段名映射** | Agent 传 `fields=["年龄"]` | 自动映射为 `age_calculated` | | **场景5:工具失败重试** | REDCap 返回空 | Agent 收到友好提示,正确回复用户 | ##### 任务清单 - [ ] **T8.1** 编写端到端测试脚本 - [ ] **T8.2** 通过企业微信发送测试消息 - [ ] **T8.3** 验证 pending_actions 记录 - [ ] **T8.4** 验证 audit_log 记录 - [ ] **T8.5** 性能测试(目标 < 5秒响应) **验收标准**: - [ ] 5 个测试场景全部通过 - [ ] 响应时间 < 5秒 - [ ] 日志完整可追溯 --- #### Day 15:文档与收尾 ##### 任务清单 - [ ] **T9.1** 更新 API 文档 - [ ] **T9.2** 更新模块状态文档 - [ ] **T9.3** 记录技术债务 - [ ] **T9.4** 代码 Review 与合并 --- ### Phase 4:定时任务与高级工具(Week 4 前半) > **目标**:实现定时报告、高级质控工具 #### Day 16-17:定时任务与报告生成 **目标**:实现每周自动生成研究进度报告 ##### 任务清单 - [ ] **T10.1** 创建 `SchedulerService.ts`(基于 pg-boss) ``` backend/src/modules/iit-manager/services/SchedulerService.ts ``` - [ ] **T10.2** 实现定时任务调度 ```typescript import PgBoss from 'pg-boss'; export class SchedulerService { private boss: PgBoss; async init() { this.boss = new PgBoss(process.env.DATABASE_URL); await this.boss.start(); // 注册周报任务处理器 await this.boss.work('weekly-report', this.handleWeeklyReport.bind(this)); // 每周一早上9点执行 await this.boss.schedule('weekly-report', '0 9 * * 1', { projectId: 'all' }); } private async handleWeeklyReport(job: Job) { const report = await this.reportService.generateWeeklyReport(job.data.projectId); await this.wechatService.sendToAdmins(report); } } ``` - [ ] **T10.3** 创建 `ReportService.ts` ``` backend/src/modules/iit-manager/services/ReportService.ts ``` - [ ] **T10.4** 实现周报生成逻辑 ```typescript export class ReportService { async generateWeeklyReport(projectId: string): Promise { const stats = await this.getProjectStats(projectId); const report = ` 📊 **${stats.projectName} 周报** 📅 ${stats.weekRange} **入组进度** - 本周新入组:${stats.newEnrollments} 例 - 累计入组:${stats.totalEnrollments} / ${stats.targetEnrollments} 例 - 完成率:${stats.completionRate}% **数据质量** - 待处理质疑:${stats.pendingQueries} 条 - 本周关闭质疑:${stats.closedQueries} 条 - 方案偏离:${stats.protocolDeviations} 例 **AE/SAE** - 本周新增 AE:${stats.newAEs} 例 - 本周新增 SAE:${stats.newSAEs} 例 **下周重点** ${stats.upcomingVisits.map(v => `- ${v.patientId}: ${v.visitName} (${v.dueDate})`).join('\n')} `; return report; } } ``` - [ ] **T10.5** 配置周报 Skill ```json { "skillType": "weekly_report", "config": { "schedule": "0 9 * * 1", "recipients": ["admin_group"], "sections": ["enrollment", "data_quality", "ae_summary", "upcoming_visits"] } } ``` **验收标准**: - [ ] 每周一自动生成周报 - [ ] 周报通过企业微信发送给管理员 - [ ] 周报内容完整、格式美观 --- #### Day 18-19:高级质控工具扩展 **目标**:新增方案偏离、AE评估、伦理检查工具 ##### 任务清单 - [ ] **T11.1** 新增 `check_visit_window` 工具(方案偏离检测) ```typescript { name: "check_visit_window", description: "检查访视是否在方案允许的时间窗口内", parameters: { record_id: { type: "string" }, visit_id: { type: "string" }, actual_date: { type: "string", format: "date" } }, handler: async (args) => { const baseline = await this.getBaselineDate(args.record_id); const window = await this.getVisitWindow(args.visit_id); const actualDays = this.daysBetween(baseline, args.actual_date); const inWindow = actualDays >= window.minDays && actualDays <= window.maxDays; return { inWindow, expectedRange: `Day ${window.minDays} - Day ${window.maxDays}`, actualDay: actualDays, deviation: inWindow ? 0 : Math.min( Math.abs(actualDays - window.minDays), Math.abs(actualDays - window.maxDays) ) }; } } ``` - [ ] **T11.2** 新增 `assess_ae_causality` 工具(AE因果关系评估) ```typescript { name: "assess_ae_causality", description: "评估不良事件与研究药物的因果关系", parameters: { record_id: { type: "string" }, ae_id: { type: "string" } }, handler: async (args) => { const ae = await this.getAEDetails(args.record_id, args.ae_id); const drugInfo = await this.getDrugExposure(args.record_id); // 使用 SoftRuleEngine 评估 const assessment = await this.softEngine.runWithRetry( `根据以下信息评估AE与研究药物的因果关系: AE信息:${JSON.stringify(ae)} 用药信息:${JSON.stringify(drugInfo)} 请给出:肯定相关/可能相关/可能无关/肯定无关/无法评估`, { ae, drugInfo } ); return assessment; } } ``` - [ ] **T11.3** 新增 `check_ethics_compliance` 工具(伦理合规检查) ```typescript { name: "check_ethics_compliance", description: "检查是否符合伦理要求", parameters: { record_id: { type: "string" }, check_type: { type: "string", enum: ["informed_consent", "age_requirement", "vulnerable_population"] } }, handler: async (args) => { const rules = { informed_consent: { logic: { "<=": [{ "var": "icf_date" }, { "var": "enrollment_date" }] }, message: "入组日期早于知情同意签署日期" }, age_requirement: { logic: { ">=": [{ "var": "age" }, 18] }, message: "未成年受试者需要法定监护人签署同意书" } }; const data = await this.getRecordData(args.record_id); return this.hardEngine.run([rules[args.check_type]], data); } } ``` - [ ] **T11.4** 更新 ToolsService 工具列表 **验收标准**: - [ ] 访视超窗能被正确检测 - [ ] AE 因果关系能给出评估结论 - [ ] 伦理违规能被识别 --- ### Phase 5:智能化增强 - 双脑架构(Week 4 后半 - Week 5) > **目标**:实现 LLM 意图路由 + ReAct 多步推理 + 追问机制,让 Agent "懂人话" > > **优先级调整说明**:智能化交互比视觉识别更影响用户留存,优先实现 #### Day 20-21:意图路由层实现 **目标**:用 LLM 替代正则匹配,实现智能意图识别 ##### 任务清单 - [ ] **T12.1** 创建 `IntentService.ts` ``` backend/src/modules/iit-manager/services/IntentService.ts ``` - [ ] **T12.2** 实现 LLM 驱动的意图识别 ```typescript export class IntentService { private llm; async detect(message: string, history: Message[]): Promise { const prompt = ` 你是一个临床研究助手的"分诊台"。请分析用户输入,返回 JSON。 用户输入: "${message}" 分类标准: 1. QC_TASK: 明确的质控、检查、录入指令(如"检查P001的入排标准") 2. QA_QUERY: 模糊的查询、分析、统计问题(如"查下那个发烧的病人是谁") 3. PROTOCOL_QA: 关于研究方案的问题(如"访视窗口是多少天") 4. UNCLEAR: 指代不清,缺少关键信息(如"他怎么样了?") 返回格式: { "type": "QC_TASK" | "QA_QUERY" | "PROTOCOL_QA" | "UNCLEAR", "confidence": 0.0-1.0, "entities": { "record_id": "...", "visit": "..." }, "missing_info": "如果 UNCLEAR,说明缺什么信息", "clarification_question": "如果 UNCLEAR,生成追问句" }`; const response = await this.llm.chat([ { role: 'system', content: prompt }, ...history.slice(-3), { role: 'user', content: message } ]); return JSON.parse(response.content); } } ``` - [ ] **T12.3** 实现降级策略(LLM 不可用时回退关键词匹配) ```typescript async detectWithFallback(message: string, history: Message[]): Promise { try { return await this.detect(message, history); } catch (error) { logger.warn('[IntentService] LLM 不可用,回退到关键词匹配'); return this.keywordFallback(message); } } private keywordFallback(message: string): IntentResult { if (/质控|检查|校验|QC|入排/.test(message)) { return { type: 'QC_TASK', confidence: 0.6, entities: {} }; } return { type: 'QA_QUERY', confidence: 0.5, entities: {} }; } ``` - [ ] **T12.4** 集成到 ChatService 路由层 **验收标准**: - [ ] "查下那个发烧的病人" → 识别为 QA_QUERY - [ ] "对 P001 进行入排质控" → 识别为 QC_TASK - [ ] "他怎么样了" → 识别为 UNCLEAR,生成追问句 - [ ] LLM 服务中断时自动降级 --- #### Day 22-23:ReAct Agent 实现 **目标**:创建多步推理引擎,支持循环思考和工具调用 ##### 任务清单 - [ ] **T13.1** 创建 `ReActEngine.ts` ``` backend/src/modules/iit-manager/engines/ReActEngine.ts ``` - [ ] **T13.2** 实现 ReAct 循环(思考→行动→观察→再思考) ```typescript export class ReActEngine { private maxIterations = 5; // 防止死循环 private maxTokens = 4000; // Token 预算限制 private tokenCounter = 0; // 工具白名单:ReAct 只能调用只读工具 private readonly READONLY_TOOLS = [ 'read_clinical_data', 'search_protocol', 'get_project_stats', 'check_visit_window' ]; async run(query: string, context: AgentContext): Promise { const systemPrompt = `你是一个临床研究智能助手。你可以使用以下工具回答问题: ${this.formatToolDescriptions(this.READONLY_TOOLS)} 请按照 ReAct 模式思考: 1. 思考:分析问题,决定下一步 2. 行动:调用工具获取信息 3. 观察:查看工具返回结果 4. 重复以上步骤,直到能回答用户问题 注意:你只能查询数据,不能修改数据。如果用户需要修改操作,请引导他们使用正式的质控流程。`; let messages: Message[] = [ { role: 'system', content: systemPrompt }, { role: 'user', content: query } ]; const trace: TraceItem[] = []; for (let i = 0; i < this.maxIterations; i++) { // Token 预算检查 if (this.tokenCounter > this.maxTokens) { return { success: false, content: '抱歉,这个问题比较复杂,请尝试更具体的描述。', trace }; } const response = await this.llm.chat(messages, { tools: this.getReadonlyToolDefinitions() }); this.tokenCounter += response.usage?.total_tokens || 0; trace.push({ iteration: i, response: response.content }); // AI 决定结束 if (!response.toolCalls || response.toolCalls.length === 0) { return { success: true, content: response.content, trace }; } // 执行工具调用 let errorCount = 0; for (const toolCall of response.toolCalls) { // 安全检查:只允许只读工具 if (!this.READONLY_TOOLS.includes(toolCall.name)) { messages.push({ role: 'tool', toolCallId: toolCall.id, content: `错误:工具 ${toolCall.name} 不在允许列表中。你只能使用只读工具。` }); errorCount++; continue; } try { const result = await this.tools.executeTool(toolCall.name, toolCall.args); messages.push({ role: 'tool', toolCallId: toolCall.id, content: JSON.stringify(result) }); } catch (error) { errorCount++; messages.push({ role: 'tool', toolCallId: toolCall.id, content: `工具调用失败: ${error.message}` }); } } // 幻觉熔断:连续 2 次工具调用全部失败 if (errorCount >= 2) { return { success: false, content: '抱歉,我遇到了一些技术问题,无法获取相关信息。请稍后重试或联系管理员。', trace }; } } return { success: false, content: '抱歉,我无法在有限步骤内完成这个查询。请尝试更具体的问题。', trace }; } } ``` - [ ] **T13.3** 实现 trace 日志记录(调试用) ```typescript private async saveTrace(userId: string, query: string, trace: TraceItem[]) { await prisma.iitAgentTrace.create({ data: { userId, query, trace: JSON.stringify(trace), createdAt: new Date() } }); } ``` - [ ] **T13.4** 编写单元测试 **验收标准**: - [ ] "最近入组的女性患者平均年龄" → 自动调用工具查询并计算 - [ ] 连续工具失败时触发熔断 - [ ] Token 超预算时优雅终止 - [ ] 尝试调用写工具时被拦截 --- #### Day 24:追问机制与上下文增强 **目标**:信息不全时主动追问,增强上下文记忆 ##### 任务清单 - [ ] **T14.1** 实现追问机制 ```typescript // ChatService 中的追问逻辑 async handleMessage(userId: string, message: string): Promise { const history = this.sessionMemory.getHistory(userId); const intent = await this.intentService.detect(message, history); // 信息不全,主动追问 if (intent.type === 'UNCLEAR') { const clarification = intent.clarification_question || `请问您能具体说明一下吗?例如:${this.getSuggestions(intent)}`; this.sessionMemory.addMessage(userId, 'assistant', clarification); return clarification; } // 根据意图路由 if (intent.type === 'QC_TASK') { return this.sopEngine.run(intent); } else { return this.reactEngine.run(message, { history, intent }); } } ``` - [ ] **T14.2** 增强 SessionMemory,支持实体记忆 ```typescript export class SessionMemory { // 新增:记住对话中提到的实体 private entityMemory: Map = new Map(); addEntityContext(userId: string, entities: Record) { const existing = this.entityMemory.get(userId) || {}; this.entityMemory.set(userId, { ...existing, ...entities }); } resolveReference(userId: string, reference: string): string | null { const context = this.entityMemory.get(userId); if (!context) return null; // 解析 "他"、"这个患者" 等指代 if (['他', '她', '这个患者', '那个病人'].includes(reference)) { return context.lastMentionedPatient; } return null; } } ``` - [ ] **T14.3** 实现指代消解 ```typescript // 在处理消息前,先解析指代 private resolveReferences(userId: string, message: string): string { const pronouns = ['他', '她', '这个患者', '那个病人']; let resolved = message; for (const pronoun of pronouns) { if (message.includes(pronoun)) { const actual = this.sessionMemory.resolveReference(userId, pronoun); if (actual) { resolved = resolved.replace(pronoun, actual); } } } return resolved; } ``` **验收标准**: - [ ] "他怎么样了" → 回复 "请问您指的是哪位患者?" - [ ] 如果上文提到 P001,"他怎么样了" → 自动解析为 P001 - [ ] 对话上下文在会话内保持连贯 --- #### Day 25:集成测试与优化 **目标**:完成双脑架构的完整测试 ##### 测试场景(Phase 5) | 场景 | 输入 | 期望输出 | |------|------|----------| | **场景6:模糊查询** | "查下最近入组的病人" | ReAct 自动查询并返回列表 | | **场景7:多步推理** | "最近入组的女性平均年龄" | 多步工具调用 + 计算结果 | | **场景8:追问** | "他怎么样了" | "请问您指的是哪位患者?" | | **场景9:指代消解** | (上文提到P001) "他的入排状态" | 自动识别为 P001 | | **场景10:写操作拦截** | (ReAct中) 尝试修改数据 | 被拦截并引导到 SOP 流程 | | **场景11:熔断** | 连续工具失败 | 优雅终止并提示 | ##### 任务清单 - [ ] **T15.1** 编写 Phase 5 测试脚本 - [ ] **T15.2** 验证意图识别准确率(目标 > 85%) - [ ] **T15.3** 验证 ReAct 多步推理成功率 - [ ] **T15.4** 验证追问机制用户体验 **验收标准**: - [ ] 11 个测试场景全部通过 - [ ] 意图识别准确率 > 85% - [ ] ReAct 平均迭代次数 < 3 - [ ] 用户反馈"不再觉得像傻子" --- ### Phase 6:视觉能力(Week 6) > **目标**:支持拍照上传 → 识别 → 自动录入 REDCap #### Day 26-27:视觉能力集成 **目标**:支持拍照上传 → 识别 → 自动录入 REDCap ##### 任务清单 - [ ] **T16.1** 创建 `VisionService.ts` ``` backend/src/modules/iit-manager/services/VisionService.ts ``` - [ ] **T16.2** 集成视觉大模型(推荐 Qwen-VL / GPT-4V) ```typescript export class VisionService { private vlmAdapter: VLMAdapter; async extractFromImage(imageUrl: string, projectId: string): Promise { // 1. 调用视觉模型识别内容 const rawText = await this.vlmAdapter.recognize(imageUrl); // 2. 结构化提取 const structured = await this.structureData(rawText, projectId); // 3. 匹配表单 const formMatch = await this.matchForm(structured, projectId); return { rawText, structured, formMatch }; } } ``` - [ ] **T16.3** 创建表单模板表 `iit_form_templates` ```prisma 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") } ``` - [ ] **T16.4** 扩展 `RedcapAdapter.writeRecord()` 写入能力 - [ ] **T16.5** ChatService 增加图片消息路由 **验收标准**: - [ ] 上传化验单图片能识别内容 - [ ] 自动匹配到正确的 REDCap 表单 - [ ] 高置信度时自动录入,低置信度时人工确认 --- #### Day 28:最终集成测试 **目标**:完成全部场景测试 ##### 测试场景(全量) | 场景 | 输入 | 期望输出 | |------|------|----------| | **场景12:拍照识别** | 上传化验单图片 | 识别内容,匹配表单,自动录入 | | **场景13:访视超窗** | V3 访视超出窗口期 5 天 | 检测到方案偏离 | | **场景14:AE评估** | SAE 事件数据 | 给出因果关系评估 | | **场景15:伦理违规** | ICF 日期晚于入组日期 | 识别伦理违规 | | **场景16:周报生成** | 触发定时任务 | 生成并发送周报 | ##### 任务清单 - [ ] **T17.1** 编写全量测试脚本 - [ ] **T17.2** 验证视觉识别准确率(目标 > 85%) - [ ] **T17.3** 性能优化(图片处理 < 10s) - [ ] **T17.4** 更新文档和部署指南 **验收标准**: - [ ] 16 个测试场景全部通过 - [ ] 图片识别准确率 > 85% - [ ] 定时任务连续运行 7 天无故障 --- ## 4. 风险与应对 ### 4.1 基础架构风险 | 风险 | 影响 | 应对措施 | |------|------|----------| | JSON Logic 表达能力不足 | 复杂规则无法配置 | 支持 `function_name` 模式,调用预定义函数 | | LLM 响应慢 | 用户体验差 | 硬规则先行,减少 LLM 调用 | | 字段映射字典不全 | 工具调用失败 | 自我修正回路 + 日志记录 + 运营补充 | | REDCap 不可用 | 流程中断 | 增加 `on_error` 分支,友好提示 | ### 4.2 双脑架构风险 (Phase 5) | 风险 | 影响 | 应对措施 | |------|------|----------| | 意图识别错误 | 路由到错误分支 | 置信度阈值 + 低置信度时追问确认 | | ReAct 死循环 | 烧钱、用户等待 | 最大迭代次数 = 5,Token 预算 = 4000 | | ReAct 调用写工具 | 数据被误改 | **工具白名单**,只允许只读工具 | | LLM 幻觉 | 返回错误信息 | 连续 2 次工具失败触发熔断 | | LLM 服务中断 | 无法响应 | 降级到关键词匹配 + 友好提示 | | Token 成本失控 | 费用超预算 | Token 计数 + 单次查询预算限制 | ### 4.3 扩展能力风险 (Phase 4 & 6) | 风险 | 影响 | 应对措施 | |------|------|----------| | 视觉模型识别错误 | 录入错误数据 | 低置信度人工确认,高置信度才自动录入 | | 定时任务失败 | 周报未发送 | pg-boss 自动重试 + 失败告警 | | 图片处理超时 | 用户体验差 | 异步处理 + 进度提示 | --- ## 5. 成功标准 ### Phase 1-3 验收标准(核心质控) - [ ] 企业微信发送"质控 ID=001",3秒内收到回复 - [ ] 硬规则违规能自动识别并记录 - [ ] 软指令能正确调用工具并判断 - [ ] 字段名映射生效 - [ ] 工具失败能自动重试 - [ ] 违规记录可在后台查看 ### Phase 4 验收标准(定时任务与高级工具) - [ ] 访视超窗能被自动检测并记录 - [ ] AE 事件能给出因果关系评估 - [ ] 伦理违规能被识别并告警 - [ ] 每周一自动生成并发送周报 - [ ] 定时任务连续运行 7 天无故障 ### Phase 5 验收标准(双脑架构) - [ ] 自然语言意图识别准确率 > 85% - [ ] "查下最近入组的病人" → ReAct 自动查询返回 - [ ] "他怎么样了" → 主动追问 "请问您指的是哪位患者?" - [ ] 上文提到 P001 后,"他的状态" → 自动识别为 P001 - [ ] ReAct 尝试调用写工具 → 被拦截并引导到 SOP - [ ] LLM 服务中断 → 自动降级到关键词匹配 - [ ] 用户反馈:**"不再觉得 Agent 像个傻子"** ### Phase 6 验收标准(视觉能力) - [ ] 拍照上传化验单,自动识别并录入 REDCap - [ ] 图片识别准确率 > 85% - [ ] 低置信度时要求人工确认 ### 性能指标 | 指标 | 目标值 | |------|--------| | 硬规则执行时间 | < 100ms | | 软指令执行时间 | < 3s | | 端到端响应时间 | < 5s | | **意图识别时间** | < 1s | | **ReAct 平均迭代次数** | < 3 | | 图片识别+录入时间 | < 10s | | 视觉识别准确率 | > 85% | | **意图识别准确率** | > 85% | | 自我修正成功率 | > 80% | --- ## 6. 附录:文件路径清单 ``` backend/src/modules/iit-manager/ ├── services/ │ ├── ChatService.ts # 扩展路由逻辑(双脑路由) │ ├── IntentService.ts # 新建:LLM 意图识别 (Phase 5) │ ├── ToolsService.ts # 新建:统一工具管理 │ ├── SchedulerService.ts # 新建:定时任务调度 (Phase 4) │ ├── ReportService.ts # 新建:报告生成服务 (Phase 4) │ ├── VisionService.ts # 新建:视觉识别服务 (Phase 6) │ └── WechatService.ts # 已存在 ├── engines/ │ ├── HardRuleEngine.ts # 新建:JSON Logic 执行器 │ ├── SoftRuleEngine.ts # 新建:LLM 推理引擎 │ ├── SopEngine.ts # 新建:状态机调度器 │ └── ReActEngine.ts # 新建:多步推理引擎 (Phase 5) ├── agents/ │ └── SessionMemory.ts # 已存在,扩展实体记忆 (Phase 5) ├── adapters/ │ ├── RedcapAdapter.ts # 已存在,扩展 writeRecord() │ └── VLMAdapter.ts # 新建:视觉大模型适配器 (Phase 6) └── types/ └── index.ts # 扩展类型定义 ``` ### 数据库新增表 ``` iit_schema.iit_skills # Skill 配置存储 iit_schema.iit_field_mapping # 字段名映射 iit_schema.iit_agent_trace # ReAct 推理轨迹 (Phase 5) iit_schema.iit_form_templates # 表单模板 (Phase 6) ``` --- ## 7. 参考文档 1. [架构决策白皮书:极简主义的胜利](../00-系统设计/IIT%20Manager%20Agent%20架构决策白皮书:极简主义的胜利.md) 2. [V2.2 落地实施指南](../00-系统设计/IIT%20Manager%20Agent%20V2.2%20落地实施指南:极简架构版%20(融合%20Moltbot).md) 3. [V2.2 工具泛化与灵活性提升指南](../00-系统设计/IIT%20Manager%20Agent%20V2.2:工具泛化与灵活性提升指南.md) 4. [V2.3 健壮性设计与最佳实践](../00-系统设计/IIT%20Manager%20Agent%20V2.3:健壮性设计与最佳实践.md) 5. [V2.4 架构模式选型与 SOP 状态机推荐](../00-系统设计/IIT%20Manager%20Agent%20V2.4:架构模式选型与%20SOP%20状态机推荐.md) 6. [V2.6 智能化升级方案:双脑架构](../00-系统设计/IIT%20Manager%20Agent%20V2.6%20智能化升级方案:双脑架构.md) --- **文档维护人**:AI Agent **最后更新**:2026-02-02(V2.6 整合双脑架构)