工业Agent工具设计2024年5大核心原则详细解析
工业 Agent 工具设计的 5 条核心原则
实际落地 AI Agent 时,多数团队会把重心放在 LLM 能力上,但真正卡脖子的往往是工具层。LLM 再强也只是推理引擎,真正完成操作的实体是工具。工具设计到位,Agent 才能精准执行;设计粗糙,LLM 要么选错工具,要么参数传错,要么拿到结果无法解析。
以下五条铁律出自 industrial-agent-long 项目的多轮实战迭代。
原则 1:描述必须具体,避免模糊
工具上的 @Tool 描述是 LLM 判断“何时调用此工具”的唯一依据。描述越精确,LLM 的选工具准确率越高。好比你对实习生说“去查资料”,他可能茫然;但你说“去第二个书柜第三层拿红色封面的《设备维修手册》”,他立刻行动。
// 不推荐 — LLM 无法确定触发时机
@Tool("查询设备信息")// 推荐 — 明确场景、输入、输出
@Tool("查询指定设备的当前告警信息。输入设备ID,返回该设备的所有活跃告警及严重级别。")
经验法则:描述必须包含三个维度——触发场景(查询告警)、输入参数(设备ID)、返回内容(活跃告警列表)。三者缺一不可。
原则 2:入参用最简类型
LLM 从自然语言中抽参,再填入 Function Calling 的 JSON 参数。参数类型越简单,抽参越稳定,出错率越低。让语言模型构造嵌套 Map 对象,结果大概率是乱填。
// 不推荐 — 复杂对象,LLM 极易填错字段
@Tool("...")
public String query(Map params) // 推荐 — 明确的简单类型
@Tool("...")
public String queryDeviceAlarms(String deviceId)// 也可接受 — 多个简单参数
@Tool("...")
public String queryHistoryData(String deviceId, String metric, int minutes)
推荐类型:String、int、double、boolean。枚举慎用,更稳妥的做法是使用 String 并在后端做转换——减少 LLM 犯错空间。
原则 3:返回值用 JSON,不用自然语言
工具返回的内容会作为上下文喂给 LLM 继续推理。JSON 结构清晰,LLM 能准确提取字段;自然语言充满歧义,模型可能凭感觉理解,丢失精度。
// 不推荐 — 自然语言,LLM 易误读
return "设备 CNC-001 当前有 2 个告警:温度过高(严重)和振动异常(中等)";// 推荐 — 结构化 JSON,LLM 能精准解析
return """
{
"deviceId": "CNC-001",
"status": "warning",
"activeAlarms": [
{"type": "温度过高", "severity": "HIGH", "timestamp": "..."},
{"type": "振动异常", "severity": "MEDIUM", "timestamp": "..."}
],
"totalCount": 2
}
""";
经验法则:工具返回 = 结构化数据。让 LLM 做它擅长的事(从 JSON 提取信息),而不是让它猜测自然语言中的隐含含义。
原则 4:工具要幂等
LLM 在一次对话中可能反复调用同一个工具。如果工具带有副作用,后果就是重复执行错误操作。必须保证:同一入参多次调用,不产生副作用。
// 危险 — 每次调用都创建工单
@Tool("创建维修工单")
public String createWorkOrder(String deviceId, String description) {
// LLM 调两次,就会生成两个完全相同的工单!
}// 安全 — 先查重,已存在则直接返回
@Tool("创建维修工单。如果该设备已有相同描述的未完成工单,返回已有工单。")
public String createWorkOrder(String deviceId, String description) {
WorkOrder existing = workOrderRepo.findByDeviceAndDescription(deviceId, description);
if (existing != null) {
return "{"action":"existing", "workOrder":" + existing.toJson() + "}";
}
// 真正创建逻辑……
}
高危工具类型:创建、删除、重启、调整参数。要么加入幂等检查,要么标注“需要人工确认”——别指望 LLM 自动记住“我已经执行过了”。
原则 5:错误也要用 JSON 返回
工具调用失败是常态——设备离线、数据库超时、参数不合法。此时如果直接抛异常,LLM 接收到的是一堆堆栈信息,那是开发者的语言,不是 LLM 的语言。LLM 需要从错误中恢复并做出合理决策。
// 不推荐 — 抛异常,LLM 得到的是技术错误详情
throw new RuntimeException("Connection refused to TDEngine");// 推荐 — 返回结构化错误信息
return """
{
"error": true,
"message": "无法连接时序数据库,数据查询失败",
"suggestion": "请稍后重试,或联系运维检查 TDEngine 服务状态",
"partialData": null
}
""";
LLM 收到这个返回,会向用户解释:“数据查询暂时失败,建议稍后重试或联系运维。”——而不是扔出一堆 Connection refused 堆栈,让用户完全摸不着头脑。
验证你的工具设计
每写完一个 Tool,用这 5 个问题自检:
- 描述是否包含了触发场景、输入参数、返回内容?
- 所有入参都是简单类型吗?
- 返回值是结构化的 JSON 吗?
- 相同入参多次调用是否没有副作用?
- 错误信息是为 LLM 设计的,还是为开发者设计的?
如果 5 个答案都是“是”,这个工具设计就达标了。只要有一个“否”,就别急着上线,改到合格为止。
