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>
6.5 KiB
IIT Manager Agent V2.2:工具泛化与灵活性提升指南
核心观点: 灵活性来自“工具的设计粒度”,而不是“连接协议(MCP)”。
解决方案: 通过设计 3-5 个“瑞士军刀型”通用工具,替代 100 个“特种螺丝刀型”专用工具。
1. 直击灵魂:MCP Server 真的更灵活吗?
你担心 V2.1 方案(Service Class)不够灵活,让我们来做个对比:
| 维度 | MCP Server 方案 | V2.1 Service Class 方案 | 真相 |
|---|---|---|---|
| 新增工具 | 在 Server 进程里写代码 -> 重启 Server -> Agent 发现新工具 | 在 Service 类里写代码 -> 重启 Node.js -> Agent 发现新工具 | 工作量完全一样。都要写代码逻辑。 |
| 工具调用 | Agent 发 JSON -> 网络传输 -> MCP 执行 | Agent 发 JSON -> 内存调用 -> Service 执行 | V2.1 更快。没有网络开销。 |
| Agent 自主性 | LLM 看到的是 tool definitions (JSON) | LLM 看到的也是 tool definitions (JSON) | LLM 根本分不清你是 MCP 还是 Service。 |
结论:
- MCP 的灵活性在于“解耦”:比如你可以把 REDCap 工具给别人用,或者在运行时动态加载新的 Server。
- V2.1 的灵活性在于“敏捷”:代码都在一个工程里,改起来最快。对于 2 人团队,改代码 > 调协议。
2. 你的痛点:是不是要写很多工具?
你担心:“如果有 100 个检查点,我是不是要写 check_age, check_gender, check_bmi 一百个工具?”
绝对不需要! 这就是我说的**“工具泛化”**。
错误的设计(特种螺丝刀)
写一堆具体的工具,导致 Service 类无限膨胀:
- get_patient_age(id)
- get_patient_history(id)
- check_informed_consent(id)
- ...
正确的设计(瑞士军刀)
只写 3 个 通用工具,就能覆盖 99% 的场景。Agent 会通过参数来体现灵活性。
工具 1:read_clinical_data (全能查询器)
- 功能:读取 REDCap 里的任意数据。
- 参数:record_id (患者ID), fields (想查什么字段), event (哪个访视)。
- 灵活性:
- 查年龄?Agent 传 fields: ["age"]。
- 查病史?Agent 传 fields: ["medical_history"]。
- 你只需要写这一个函数,Agent 就可以查任何东西。
工具 2:eval_logic (逻辑计算器)
- 功能:处理复杂的数值计算或逻辑判断(利用 json-logic)。
- 场景:Agent 算不清 BMI,可以调这个工具帮它算。
工具 3:manage_issue (通用反馈器)
- 功能:包括提出质疑、发送提醒、记录日志。
- 参数:type (QUERY | NOTIFY | LOG), message (内容), severity (严重程度)。
3. 代码实现:如何实现“瑞士军刀”?
在你的 ToolsService.ts 中,只需要实现这几个通用方法。
// backend/src/modules/iit-manager/services/ToolsService.ts
export const UNIVERSAL_TOOL_DEFS = [
{
name: "read_clinical_data",
description: "通用数据查询工具。当需要检查患者的某项指标时使用。",
parameters: {
type: "object",
properties: {
record_id: { type: "string" },
// 关键:让 Agent 自己决定查什么字段
fields: {
type: "array",
items: { type: "string" },
description: "需要查询的REDCap变量名列表,如 ['age', 's_cr', 'ae_desc']"
}
},
required: ["record_id", "fields"]
}
},
{
name: "manage_issue",
description: "通用问题处理工具。用于提出质疑或发送通知。",
parameters: {
type: "object",
properties: {
record_id: { type: "string" },
action_type: { type: "string", enum: ["RAISE_QUERY", "SEND_WECHAT"] },
message: { type: "string" }
},
required: ["record_id", "action_type", "message"]
}
}
];
export class ToolsService {
constructor(private redcapAdapter: RedcapAdapter) {}
async execute(name: string, args: any) {
switch (name) {
case 'read_clinical_data':
// 一个函数,通过参数变化应对无限需求
return await this.redcapAdapter.exportRecords({
recordId: args.record_id,
fields: args.fields // <--- 动态字段
});
case 'manage\_issue':
if (args.action\_type \=== 'RAISE\_QUERY') {
return await this.saveShadowQuery(args);
} else {
return await this.sendWechat(args);
}
}
}
}
4. 场景演示:Agent 的自主性如何体现?
哪怕你只提供了 2 个工具,Agent 依然表现得像个专家,因为Skill (Prompt) 在指导它如何组合使用这些工具。
场景 A:检查肝功能
- Skill 配置: "instruction": "检查 ALT 和 AST 是否超过正常值 3 倍。"
- Agent 思考: "我要查肝功能。"
- Agent 行动: 调用 read_clinical_data(fields=['alt', 'ast'])。
- 系统响应: {"alt": 150, "ast": 40}
- Agent 判断: "ALT 150 > 40*3。违规。"
- Agent 行动: 调用 manage_issue(action_type='RAISE_QUERY', message='ALT异常')。
场景 B:检查入组年龄
- Skill 配置: "instruction": "确保患者年龄 > 18。"
- Agent 思考: "我要查年龄。"
- Agent 行动: 调用 read_clinical_data(fields=['age'])。
- 系统响应: {"age": 16}
- Agent 行动: 调用 manage_issue(action_type='RAISE_QUERY', message='年龄不合规')。
看到没有?
你没有写 check_liver 和 check_age 两个函数。
你只写了一个 read_clinical_data。
是 Agent 的大脑(Prompt) + 通用工具(Tool) 实现了无限的灵活性。
5. 总结
- MCP Server 不是灵活性的来源:它只是一个连接标准。如果你的工具设计得烂(粒度太细),用 MCP 也一样累。
- 通用参数是王道:不要写“查年龄”的工具,要写“查字段”的工具。让 Agent 填参数,这就是最大的灵活性。
- V2.1 极简版足够强:只要你的 ToolsService 按照“瑞士军刀”的思路去设计,2 个开发人员维护 100 个项目的逻辑完全没有压力。
行动建议:
按照本文档的 第 3 节,把你的 ToolsService 重构一下,只保留 3-5 个通用方法。然后去测试一下 Agent 是否能聪明地自己填参数。