Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/00-系统设计/IIT Manager Agent V2.3:健壮性设计与最佳实践.md
HaHafeng 0c590854b5 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>
2026-02-05 22:33:26 +08:00

162 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **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 落地最务实、最抗造的模式。**