# **IIT Manager Agent V2.2 落地实施指南:极简架构版 (融合 Moltbot)** **文档版本:** V2.2 (Moltbot Enhanced) **日期:** 2026-02-03 **适用对象:** 2人高效开发团队 **核心原则:** **Postgres-Only**, **No New Components**, **Service-First**, **Proactive & Personalized** **变更说明:** 在 V2.1 基础上,借鉴 Moltbot (Clawbot) 的主动性与记忆机制,增加了用户偏好存储、每日早报 Skill 和自我修正回路。 ## **1\. 核心架构:回归本质 (The Pragmatic Architecture)** 我们将“Brain-Hand-Tool”模型映射到现有的 Node.js \+ Postgres 技术栈上。 graph TD subgraph "Layer 3: 数字化大脑 (The Brain)" DB\[(Postgres DB)\] DB \--\>|加载 Skills & Preferences| Engine\[QcEngineService\] subgraph "混合双引擎" Engine \--\>|1. 执行 JSON Logic| Logic\[Engine A (硬规则)\] Engine \--\>|2. 组装 Prompt (含偏好)| LLM\[Engine B (软指令)\] end end subgraph "Layer 2: 伪 MCP 接口层 (The Hand)" LLM \--\>|3. 调用| Tools\[ToolsService (Class)\] Logic \--\>|3. 调用| Tools Tools \--\>|read\_data| Tool1\[RedcapAdapter\] Tools \--\>|search\_doc| Tool2\[VectorSearchService\] Tools \--\>|send\_msg| Tool3\[WechatService\] end subgraph "Layer 1: 基础设施 (The Tool)" Tool1 \--\> REDCap Tool2 \--\> pgvector Tool3 \--\> WeCom end ## **2\. 数据层设计:Skills 即数据 (Skills as Data)** 不再使用 OSS 存文件,直接使用 Postgres iit\_schema 存储结构化配置。**新增用户偏好表。** ### **2.1 数据库 Schema** // schema.prisma // 核心技能表 model IitSkill { id String @id @default(uuid()) projectId String // 绑定项目 ID (如 PID=16) formName String // 绑定表单 (如 demographics) 或 场景 (如 daily\_briefing) // 核心配置 (JSON 类型) // 包含 hard\_rules, soft\_instructions, schedule (cron表达式) config Json isActive Boolean @default(true) version Int @default(1) updatedAt DateTime @updatedAt @@unique(\[projectId, formName\]) @@map("iit\_skills") @@schema("iit\_schema") } // \[New\] 用户偏好表 (Moltbot 记忆机制) model IitUserPreference { id String @id @default(uuid()) userId String // 绑定企业微信 UserID projectId String // 绑定项目 // 偏好配置 (JSON) // 例如: { "report\_style": "concise", "notification\_time": "08:30" } preferences Json updatedAt DateTime @updatedAt @@unique(\[userId, projectId\]) @@map("iit\_user\_preferences") @@schema("iit\_schema") } ### **2.2 JSON 配置范例 (Skill)** **范例 1:质控 Skill** { "description": "人口学表单质控", "hard\_rules": \[ { "field": "age", "logic": { "\>=": \[{ "var": "age" }, 18\] }, "message": "年龄必须 \>= 18 岁" } \], "soft\_instructions": \[ { "instruction": "检查备注字段。如果包含'无法签署知情同意',请标记违规。", "tools": \["read\_clinical\_data"\] } \] } **范例 2:\[New\] 每日早报 Skill (Moltbot 主动性)** { "description": "每日项目进展早报", "schedule": "0 30 8 \* \* \*", // 每天 08:30 触发 (pg-boss) "soft\_instructions": \[ { "instruction": "请统计昨天的入组人数、待处理质疑数。生成一段简报发给 PI。注意参考用户的 report\_style 偏好。", "tools": \["get\_project\_stats", "send\_wechat\_msg"\] } \] } ## **3\. 服务层设计:伪 MCP 实现 (Service-First)** 不要引入 @modelcontextprotocol/sdk。创建一个标准的 Service 类来管理工具。 ### **3.1 ToolsService.ts 实现规范** // backend/src/modules/iit-manager/services/ToolsService.ts import { RedcapAdapter } from '../adapters/RedcapAdapter'; import { VectorSearchService } from '@/common/rag/vectorSearchService'; // 定义工具接口 (为了给 LLM 生成菜单) export const TOOL\_DEFINITIONS \= \[ { name: "read\_clinical\_data", description: "读取REDCap临床数据...", parameters: { ... } }, { name: "update\_user\_preference", // \[New\] 更新偏好工具 description: "更新用户的偏好设置,如报告风格、通知时间。", parameters: { type: "object", properties: { key: { type: "string", description: "偏好键名,如 report\_style" }, value: { type: "string", description: "偏好值,如 concise (简洁) 或 detailed (详细)" } } } } \]; export class ToolsService { constructor( private redcap: RedcapAdapter, private rag: VectorSearchService, private prisma: PrismaClient ) {} // 统一执行入口 (LLM 只认识这个) async executeTool(name: string, args: any) { switch (name) { case 'read\_clinical\_data': return this.redcap.exportRecords(args); case 'update\_user\_preference': // \[New\] 实现记忆更新 return this.updatePreference(args); case 'raise\_query': return this.savePendingAction(args); default: throw new Error(\`未知工具: ${name}\`); } } } ## **4\. 业务层设计:混合引擎调度 (含自我修正)** ### **4.1 执行逻辑 (The Pipeline)** // backend/src/modules/iit-manager/services/QcEngineService.ts export class QcEngineService { async runQualityCheck(projectId: string, formName: string, data: any, userId?: string) { // 1\. 加载 Skill 和 用户偏好 const skill \= await prisma.iitSkill.findUnique({...}); const userPref \= userId ? await prisma.iitUserPreference.findUnique({ where: { userId, projectId } }) : null; if (\!skill) return; // 2\. 运行 Engine A (硬规则) const engineA \= new HardRuleEngine(); const hardErrors \= engineA.run(skill.config.hard\_rules, data); if (hardErrors.length \> 0\) { await this.saveShadowState(hardErrors); return; } // 3\. 运行 Engine B (软指令) \- \[New\] 注入偏好 Context const engineB \= new SoftRuleEngine(this.llm, this.toolsService); // 将偏好注入 Prompt: "用户偏好简洁的报告,请不要废话。" const context \= { ...data, user\_preferences: userPref?.preferences }; // \[New\] 开启自我修正回路 (Self-Correction Loop) const softSuggestions \= await engineB.runWithRetry(skill.config.soft\_instructions, context, 3); if (softSuggestions) { await this.saveShadowState(softSuggestions); } } } ### **4.2 自我修正机制 (Self-Correction Loop)** 借鉴 Moltbot,当工具调用失败时,不报错,而是让 LLM 重试。 // SoftRuleEngine.ts (伪代码) async runWithRetry(instruction, context, maxRetries \= 3\) { let history \= \[...\]; for (let i \= 0; i \< maxRetries; i++) { const response \= await llm.chat(history); if (response.hasToolCall) { try { const result \= await tools.executeTool(response.toolName, response.args); history.push({ role: 'tool', content: result }); } catch (error) { // \[New\] 捕获错误,喂回给 LLM console.warn(\`Tool Error: ${error.message}\`); history.push({ role: 'user', content: \`工具调用失败: ${error.message}。请检查参数并重试。\` }); continue; // 让 LLM 重新思考 } } else { return response.content; } } } ## **5\. 实施路线图 (2人团队专属)** ### **✅ Week 1: 基础建设 (Engine A)** 1. 创建 iit\_skills 和 iit\_user\_preferences 表。 2. 引入 json-logic-js 库。 3. 实现 QcEngineService 的基础骨架,只跑硬规则。 ### **🚧 Week 2: AI 接入与主动性 (Engine B)** 1. 创建 ToolsService,实现基础工具。 2. 实现 SoftRuleEngine 的 **自我修正回路**。 3. **里程碑**:配置 daily\_briefing Skill,利用 pg-boss 定时触发,早上 8:30 收到测试推送。 ### **📋 Week 3: 界面与优化** 1. 开发 Admin 页面 (JSON Editor) 编辑 Skill。 2. 完善影子状态 (Shadow State) 审核界面。 ## **6\. 多轮对话与开放式问答支持** ### **6.1 核心策略:Intent Routing \+ General Skill** 不要把所有逻辑都写死在质控里。我们增加一个特殊的 Skill:general\_qa。 #### **A. 配置 general\_qa Skill** 在数据库插入一条 formName \= 'general\_chat' 的记录: { "description": "通用问答与查询助手", "soft\_instructions": \[ { "instruction": "你是本项目的智能助手。你可以回答关于项目进度、患者数据、方案细节的问题。请根据用户意图调用工具。", "tools": \["read\_clinical\_data", "search\_protocol", "get\_project\_stats", "update\_user\_preference"\] } \] } ### **6.2 代码实现:聊天入口 (ChatService.ts)** // backend/src/modules/iit-manager/services/ChatService.ts export class ChatService { constructor( private qcEngine: QcEngineService, private sessionMemory: SessionMemory ) {} async handleUserMessage(userId: string, projectId: string, message: string) { // 1\. 获取历史对话 & 用户偏好 const history \= await this.sessionMemory.get(userId); const userPref \= await prisma.iitUserPreference.findUnique({...}); // 2\. 加载通用 Skill const generalSkill \= await prisma.iitSkill.findUnique({ where: { projectId, formName: 'general\_chat' } }); // 3\. 构造 Prompt (包含 History \+ Skill \+ Preferences) const prompt \= \` ${generalSkill.config.soft\_instructions\[0\].instruction} \[User Preferences\]: ${JSON.stringify(userPref?.preferences || {})} 历史对话: ${history.map(h \=\> \`${h.role}: ${h.content}\`).join('\\n')} 用户当前问题: ${message} \`; // 4\. 调用 LLM (Engine B 逻辑复用,含自我修正) const response \= await this.qcEngine.runSoftAgent(prompt, generalSkill.config); // 5\. 更新记忆 await this.sessionMemory.add(userId, { role: 'user', content: message }); await this.sessionMemory.add(userId, { role: 'assistant', content: response }); return response; } } ## **7\. Moltbot 理念借鉴总结** | 借鉴点 | IIT Manager 落地实现 | 价值 | | :---- | :---- | :---- | | **主动性 (Proactivity)** | **每日早报 Skill**:利用 pg-boss 定时触发 daily\_briefing Skill,主动推送企微消息。 | 让用户感觉系统是活的,而不是被动的数据库。 | | **记忆 (Memory)** | **用户偏好表**:存储 report\_style, notification\_time 等,Prompt 动态注入。 | 提供千人千面的个性化体验。 | | **自我修正 (Self-Correction)** | **重试回路**:Engine B 在工具报错时,将错误信息回传给 LLM,允许其修正参数重试。 | 极大提升系统鲁棒性,减少人工运维。 | **结论:这就是 IIT Manager Agent 的最终形态。既有医疗的严谨(硬规则),又有个性化的温度(偏好记忆),还有极简的架构(Postgres-Only)。开干吧!**