Features: - Add V2.9 enhancements: Cron Skill, User Profiling, Feedback Loop, Multi-Intent Handling - Create modular development plan documents (database, engines, services, memory, tasks) - Add V2.5/V2.6/V2.8/V2.9 design documents for architecture evolution - Add system design white papers and implementation guides Architecture: - Dual-Brain Architecture (SOP + ReAct engines) - Three-layer memory system (Flow Log, Hot Memory, History Book) - ProfilerService for personalized responses - SchedulerService with Cron Skill support Also includes: - Frontend nginx config updates - Backend test scripts for WeChat signature - Database backup files Co-authored-by: Cursor <cursoragent@cursor.com>
9.1 KiB
IIT Manager Agent V2.4:架构模式选型与 SOP 状态机推荐
核心议题: ReAct vs Planner vs State Machine —— 谁更适合医疗质控?
结论前置: 弃用纯 Planner,限制使用 ReAct,全面拥抱 SOP 状态机。
1. 深度解析:ReAct 与 Planner 适合我们吗?
1.1 ReAct (Reasoning + Acting)
- 原理:Agent 像人一样“自言自语”。
- Thought: "我需要查患者年龄。" -> Action: read_data -> Observation: "16岁" -> Thought: "太小了,报错。"
- 在 IIT 中的地位:它就是你的 Engine B。
- 你现有的 runAgentLoop 代码本质上就是一个 ReAct 循环。
- 优点:灵活,能处理突发情况(比如发现数据缺了,它知道先去查)。
- 缺点:容易陷入死循环(反复查同一个数据),或者在思考步骤中消耗大量 Token。
- 结论:保留使用,但必须加“紧箍咒”(最大步数限制)。
1.2 Planner (Query-Planner-Execute-Reflect)
- 原理:先写大纲,再干活。
- Plan: 1. 查总人数; 2. 算脱落率; 3. 写周报; 4. 反思哪里写得不好。
- 在 IIT 中的地位:仅适合“项目管理 Agent” (周报/统计)。
- 对于“数据质控”这种秒级响应的任务,Planner 太慢了(光生成计划就要 5-10 秒)。
- 缺点:对于 2 人团队,实现一个稳定的 Planner 很难(需要维护计划状态、断点恢复)。
- 结论:质控场景禁用,报表场景可选。
2. 终极推荐:SOP 状态机 (SOP-Driven State Machine)
为什么医疗行业(GCP)最看重 Protocol(方案)?因为临床研究本质上就是一个巨大的流程图。
我们应该让 Agent “照着流程图走”,而不是让它“只有个模糊目标自己瞎想”。
2.1 什么是 SOP 状态机架构?
把你的 Skills JSON 进化成一个有向图 (DAG) 或 流程图。
- 节点 (Node):一个具体的检查步骤(可以是硬规则,也可以是软指令)。
- 边 (Edge):下一步走哪里(通过了走 A,没通过走 B)。
2.2 为什么它既稳又活?
- 稳 (Stability):流程是写死的(先查年龄,再查病史,最后查合并用药)。Agent 不会乱跳步骤,不会漏查。
- 活 (Flexibility):每个节点内部可以用 AI(Engine B)来灵活判断。
3. 落地实施:如何改造 Skills JSON?
我们将 V2.1 的扁平配置升级为流程配置。
3.1 新的 Skill 结构 (qc_process.json)
{
"name": "肺癌入排质控流程",
"start_node": "check_age", // 入口
"nodes": {
// 节点 1: 硬规则 (CPU 执行)
"check_age": {
"type": "hard_rule",
"logic": { ">=": [{ "var": "age" }, 18] },
"on_pass": "check_history", // 通过了,去查病史
"on_fail": "end_with_error" // 没通过,直接结束
},
// 节点 2: 软指令 (AI 执行 \- ReAct 模式)
"check\_history": {
"type": "soft\_instruction",
"instruction": "检查病史描述,排除'间质性肺炎'。",
"tools": \["read\_clinical\_data"\],
"on\_pass": "check\_meds",
"on\_fail": "review\_required" // AI 觉得有问题,转人工复核
},
// 节点 3: 复杂逻辑 (AI 执行)
"check\_meds": {
"type": "soft\_instruction",
"instruction": "检查合并用药,排除靶向药。",
"on\_pass": "end\_success",
"on\_fail": "review\_required"
}
}
}
4. 代码实现:极简状态机引擎
不要引入 XState 这种复杂库,2 人团队自己写个 while 循环就够了。
// backend/src/modules/iit-manager/services/SopEngine.ts
class SopEngine {
async run(skillConfig: any, data: any) {
let currentNodeId = skillConfig.start_node;
let context = { ...data }; // 共享上下文
while (currentNodeId && currentNodeId \!== 'end') {
const node \= skillConfig.nodes\[currentNodeId\];
console.log(\`\[SOP\] Executing node: ${currentNodeId}\`);
let result;
if (node.type \=== 'hard\_rule') {
// 调用 Engine A (V2.1 的逻辑)
result \= this.runHardRule(node, context);
} else if (node.type \=== 'soft\_instruction') {
// 调用 Engine B (ReAct 模式)
result \= await this.runSoftAgent(node, context);
}
// 状态流转
if (result.passed) {
currentNodeId \= node.on\_pass;
} else {
if (node.on\_fail \=== 'end\_with\_error') {
await this.saveShadowQuery(result.message);
return;
}
currentNodeId \= node.on\_fail;
}
}
}
}
5. 架构对比总结表
| 架构模式 | 稳定性 | 灵活性 | 复杂度 | 适用场景 | 推荐指数 |
|---|---|---|---|---|---|
| ReAct (V2.1 Engine B) | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 中 | 单点模糊判断 (如: 这段话是不是病史) | ✅ 局部使用 |
| Planner | ⭐⭐ | ⭐⭐⭐⭐ | 高 | 复杂任务规划 (如: 生成全项目总结) | ❌ 质控不用 |
| SOP 状态机 (V2.4) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 低 | 临床试验全流程控制 (SOP 落地) | 👑 核心架构 |
6. 深度释疑:SOP 会导致僵化吗?(Flexibility Check)
针对你担心的“每个字段都要配流程”和“浪费 LLM 能力”的问题,我们需要纠正一个认知误区。
6.1 误区:SOP = 细粒度代码逻辑
- 错误做法:把 400 个变量写成 400 个节点。节点1: 查年龄 -> 节点2: 查性别 -> 节点3: 查身高...
- 后果:配置地狱,灵活性为零。
6.2 正解:SOP = 粗粒度业务阶段 (Phases)
我们通过 “粗颗粒度节点” 来充分释放 LLM 的能力。一个 SOP 可能只有 3 个节点,但涵盖了无数逻辑。
- 节点 A (基线硬扫描):
- 类型:硬规则(Hard Rule)
- 内容:一次性加载 50 条 JSON Logic 规则。
- 执行:CPU 毫秒级跑完所有数值校验(年龄、身高、体重、化验值范围)。
- 配置:这是一个列表,不是流程图,配置很简单。
- 节点 B (AI 综合研判):
- 类型:软指令(Soft Instruction / ReAct)
- Prompt:“请作为医学专家,阅读患者的‘现病史’、‘既往史’和‘手术史’。请综合判断是否存在:严重心血管疾病、未控制的高血压或活动性感染。如果有,请引用原文说明。”
- LLM 的灵活性:
- 在这个节点内部,LLM 是完全自由的。
- 它可以自己决定先看现病史还是既往史。
- 它可以自己判断“高血压二级”算不算“未控制”。
- 它依然在用 ReAct 调用工具,只是我们把它限制在了“检查病史”这个大阶段里,不让它跑去“检查知情同意书”。
6.3 实战推演:如何拆解一个 400 变量的项目?
假设你的项目有 10 个表,400 个变量。
| 数据类型 | 变量数量 | 举例 | 处理策略 | 节点归属 |
|---|---|---|---|---|
| 人口学/基线 | 20 个 | 年龄、性别、身高、体重 | Hard Rule | 节点 A (基线检查) |
| 实验室检查 | 300 个 | 血常规、生化、尿常规 | Hard Rule | 节点 A (基线检查) |
| 体格检查 | 50 个 | 心率、血压、体温 | Hard Rule | 节点 A (基线检查) |
| 既往病史 | 5 个 | 自由文本描述 | Soft Instruction | 节点 B (病史研判) |
| 合并用药 | 5 个 | 自由文本药名 | Soft Instruction | 节点 C (用药研判) |
| 不良事件 | 20 个 | 严重程度、转归情况 | Soft Instruction | 节点 D (安全监控) |
结论:
- 尽管有 400 个变量,SOP 流程图里其实只有 4 个节点。
- 你只需要写 3 条 AI 指令(针对节点 B, C, D)。
- 剩下的 370 个变量,全部用简单的 JSON 规则批量处理。
这不仅没有浪费 LLM 的能力,反而让它更专注(只处理那 30 个最难的变量),并帮你省下了巨额的 Token 费用。
7. 给 2 人团队的行动指南
- 宏观上用 SOP:
- 临床研究最讲究 SOP。用 JSON 定义好“先查A,再查B,最后查C”的流程。这能保证你的系统像瑞士钟表一样稳定。
- 这解决了“不知道 AI 会不会乱跑”的恐惧。
- 微观上用 ReAct:
- 在 SOP 的某个具体节点(比如“检查病史”节点)里,允许 AI 使用 ReAct 模式(思考-查库-判断)。
- 这保留了处理非结构化数据的灵活性。
- 实现路径:
- Phase 2.1: 先把之前的 hard_rules 列表改成简单的 nodes 结构(线性执行)。
- Phase 2.2: 在 nodes 里增加 on_pass / on_fail 跳转逻辑。
一句话总结:用 SOP (状态机) 管住 Agent 的腿(流程),用 ReAct 管住 Agent 的嘴(推理)。这就是既稳定又灵活的最佳实践。