docs(iit): Add IIT Manager Agent V2.9 development plan with multi-agent architecture

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>
This commit is contained in:
2026-02-05 22:33:26 +08:00
parent 4b9b90ffb8
commit 0c590854b5
27 changed files with 7279 additions and 7 deletions

View File

@@ -0,0 +1,162 @@
# **IIT Manager Agent V2.3:健壮性设计与最佳实践**
**核心目标:** 在极简架构下,解决 LLM 调用工具时的幻觉、参数错误和无结果问题。
**适用场景:** 2人团队Node.js Service Class 架构。
## **1\. 核心风险分析LLM 会犯什么错?**
在让 Agent 调用 read\_clinical\_data 等工具时,通常会发生以下三类错误:
| 错误类型 | 场景举例 | 后果 |
| :---- | :---- | :---- |
| **参数幻觉** | LLM 调用 read\_data(id="P001", fields=\["gender"\]),但 REDCap 里字段名叫 sex。 | API 返回空或报错,用户觉得 AI 很蠢。 |
| **意图漂移** | 用户问:“今天天气怎么样?” LLM 试图去 REDCap 查天气。 | 工具调用失败,浪费 Token。 |
| **格式错误** | LLM 返回的 JSON 少了一个括号,或者参数类型不对(字符串给了数字)。 | 程序 Crash前端报错。 |
## **2\. 解决方案:三层防御体系 (The Defense Layer)**
不需要 MCP Server我们在 Service Class 里加三层防御即可。
### **第一层:模糊映射 (The Translator)**
**解决:** 字段名对不上的问题。
**原理:** 别指望 LLM 能记住 REDCap 几千个变量名。我们在代码里做一个“模糊翻译器”。
// backend/src/modules/iit-manager/services/ToolsService.ts
class ToolsService {
// 1\. 定义常用字段映射字典
private fieldMapping \= {
"gender": "sex",
"sex": "sex",
"性别": "sex",
"age": "age\_calculated",
"年龄": "age\_calculated",
"history": "medical\_history\_desc",
"病史": "medical\_history\_desc"
};
async executeTool(name: string, args: any) {
if (name \=== 'read\_clinical\_data') {
// 🛡️ 自动纠错逻辑
const correctedFields \= args.fields.map(f \=\> {
// 如果字典里有,就替换;没有就保留原样
return this.fieldMapping\[f.toLowerCase()\] || f;
});
console.log(\`\[Auto-Fix\] ${args.fields} \-\> ${correctedFields}\`);
return this.redcapAdapter.exportRecords({
...args,
fields: correctedFields
});
}
}
}
### **第二层:容错重试 (The Self-Correction Loop)**
**解决:** LLM 调用失败直接报错给用户的问题。
**原理:** 当工具报错时,**不要直接抛给用户**,而是把错误信息喂回给 LLM让它重试。这是 Agent 能够“甚至比人更聪明”的关键。
// backend/src/modules/iit-manager/agents/QcAgent.ts
async function runAgentLoop(prompt: string, maxRetries \= 3\) {
let history \= \[{ role: 'user', content: prompt }\];
for (let i \= 0; i \< maxRetries; i++) {
// 1\. LLM 思考
const response \= await llm.chat(history);
// 2\. 如果没有调用工具,直接返回结果
if (\!response.hasToolCall) return response.content;
// 3\. 尝试执行工具
try {
const result \= await toolsService.execute(response.toolName, response.args);
// 4\. ✅ 成功:把结果喂给 LLM继续思考
history.push({ role: 'tool', content: JSON.stringify(result) });
} catch (error) {
// 5\. ❌ 失败:触发自我修正机制
console.warn(\`\[Agent Error\] 工具调用失败: ${error.message}\`);
// 关键步骤:告诉 LLM 它错了,让它重试
history.push({
role: 'user',
content: \`系统报错:${error.message}。请检查你的参数(例如字段名是否存在),然后重试。\`
});
// 循环继续LLM 会在下一次迭代中修正参数
}
}
return "抱歉,系统尝试多次后仍然无法获取数据,请联系管理员。";
}
### **第三层:空结果兜底 (The Fallback)**
**解决:** 查不到数据时体验不好的问题。
**原理:** 如果 REDCap 返回空,工具层要返回一段“人话”,而不是 null。
// ToolsService.ts
async execute(name: string, args: any) {
// ...
const data \= await this.redcapAdapter.exportRecords(...);
if (\!data || data.length \=== 0\) {
// 🛡️ 友好的空结果返回
return {
status: "empty",
message: \`未找到 ID 为 ${args.record\_id} 的患者数据。请确认 ID 是否正确。\`
};
}
return data;
}
## **3\. 最佳实践:如何应对未知问题?**
### **3.1 限制工具的“射程”**
不要给 LLM 一个 sql\_query 工具让它随便查库。
**最佳实践**:只提供 read\_clinical\_data(record\_id, fields)。
* 如果用户问“天气怎么样”LLM 发现没有 get\_weather 工具,它自己就会回答:“抱歉,我无法查询天气,我只能查询临床数据。”(这是 LLM 的自带能力)。
### **3.2 System Prompt 的“紧箍咒”**
在 qc\_config.json 的 soft\_instructions 或者全局 System Prompt 中,明确边界。
你是一个临床研究助手。
1\. 你只能回答与【肺癌研究】相关的问题。
2\. 如果用户问无关问题(如天气、股票),请礼貌拒绝。
3\. 在调用 \`read\_clinical\_data\` 时,请务必使用准确的英文变量名。如果不确定,请先调用 \`Youtube\` 查看字典。
### **3.3 调试与监控 (Admin Portal)**
你们已经有了 **运营管理端**。利用起来!
* 记录每一次 Agent 的思考过程Thinking Trace
* 如果你发现 Agent 总是把 age 拼成 agg就在 **第一层防御(映射字典)** 里加一行配置。
* 这就是\*\*“运营驱动开发”\*\*,比改代码快得多。
## **4\. 结论**
**极简方案Service Class的灵活性和健壮性完全够用。**
* **MCP Server** 只是把错误抛出来,它不会自动修错。
* **Service Class** 允许你在本地代码里直接写 try-catch 和 Retry Loop这对 2 人团队来说调试极其友好。
**行动指南:**
1. **不用担心**用户乱问Prompt 会拒绝。
2. **不用担心**参数传错,写一个简单的 Mapping 字典去拦截。
3. **不用担心**报错,实现 Self-Correction Loop出错把错误扔回给 AI让 AI 自己修。
**这就是目前 Agent 落地最务实、最抗造的模式。**