Tool Engineering:如何设计 Agent 能稳定调用的工具

接入一堆 MCP、API 或浏览器工具后,很多人会期待 Agent 立刻变强。现实里,它可能变得更犹豫:同一件事有五个近似工具,不知道该选哪个;一次调用返回几十页无关数据;工具失败后也不知道该重试、换参数还是停下来问人。

工具不是能力的数量表。对 Agent 来说,工具是它理解并行动的接口;接口设计得模糊,模型再强也会在选择、参数和副作用上犯错。

一、从“给我全部数据”开始反思

下面这个工具看似省事:

get_database()

它的实际问题很多:返回量不可控、权限边界不清、调用者不知道应从哪里找答案,也无法安全重试。

更接近 Agent 需要的接口是:

{
"name": "search_orders",
"input": {
"date_range": "2026-07-01..2026-07-31",
"status": "paid",
"customer_id": "optional",
"fields": ["id", "amount", "created_at"],
"limit": 50,
"cursor": null
}
}

它明确了任务对象、过滤条件、返回字段、分页和范围。Agent 不必在海量数据里猜,也更容易把结果作为下一步推理的证据。

二、设计工具时优先检查七件事

维度 推荐做法 读者可直接检查的问题
命名 动词 + 明确领域对象 search_ordersquery 清楚吗?
边界 一个工具只做一件事 是否同时搜索、修改、发送?
参数 类型、默认值、限制可见 是否会无意请求全量数据?
返回 字段稳定、支持分页 Agent 能否只拿需要的字段?
错误 可分类、有恢复提示 超时、无权限、参数错是否能区分?
副作用 读/写/删除显式标识 调用前能否知道是否会改变外部状态?
幂等性 重试语义清楚 重发一次会不会重复扣费或重复创建?

工具设计的核心不是“把所有后端能力暴露出来”,而是让 Agent 在一次调用前就能大致预测:会发生什么、会返回什么、失败后怎么办。

三、读工具和写工具必须分开

最容易造成风险的设计,是让一个名字看似查询的工具顺手修改数据。

我建议至少在命名和权限上区分:

Read  : get_invoice, search_orders, preview_campaign
Write : create_invoice_draft, update_order_note
Risky : delete_invoice, send_campaign, deploy_release

写工具最好提供 dry_run、草稿或预览入口。高风险工具还应要求确认令牌、审批 ID 或由外层 Harness 限制调用。

例如,先让 Agent 调用:

{ "name": "preview_campaign", "input": { "audience": "inactive_30d" } }

只有人确认受众、内容和数量后,才允许调用发送工具。这比在 Prompt 中写十次“慎重发送”可靠得多。

四、返回结果也需要为推理而设计

好的返回不只带结果,还带足以判断下一步的信息:

{
"items": [{"id": "o_1024", "amount": 128, "created_at": "2026-07-18"}],
"next_cursor": "cursor_x",
"total_estimate": 324,
"applied_filters": {"status": "paid"},
"generated_at": "2026-07-19T08:00:00Z"
}

next_cursor 防止 Agent 误以为已经拿到全量;applied_filters 能帮它发现参数是否被服务端忽略;时间戳让后续结论可追溯。

相反,不要默认返回整个对象、完整日志或未脱敏数据。它们会占用上下文,也会扩大安全风险。

五、工具多了之后,先做选择再做调用

当一个 Agent 面前有几十个工具时,最好的改进通常不是继续增加描述,而是先缩小候选集合:

任务:检查某客户本月退款
→ 候选:search_refunds、get_customer、export_finance_report
→ 选择:search_refunds
→ 只在需要客户资料时再加载 get_customer

把工具按领域、读写风险或任务阶段做路由,能减少误选,也能降低每次推理需要理解的 schema 数量。

对大量确定性中间处理,例如过滤、去重、聚合和格式校验,也可以由程序先完成,再把小而结构化的结果交给模型做语义判断。不要让模型为了找三条记录而阅读三万条原始数据。

六、给工具做一组小型 contract tests

工具的质量不能只靠“手动点过一次”。至少为高频或高风险工具准备一些固定 case:

search_orders
✓ 合法日期 + 小字段集:返回 items 和分页信息
✓ limit 超过上限:返回明确参数错误
✓ 无权限租户:返回 permission_denied,不泄露存在性
✓ 空结果:返回空数组,不伪造成功数据

send_campaign
✓ dry_run:不产生外部副作用
✓ 缺少 approval_id:明确拒绝
✓ 重复 request_id:不重复发送

它们既能防止后端改动破坏 Agent,也能为未来模型或工具版本升级提供稳定证据。

AI 实现摘要

  • 要解决的问题:设计边界清晰、返回精简、副作用显式且可恢复的 Agent 工具,减少误选、参数错误和危险调用。
  • 适用版本与前置条件:适用于 MCP、HTTP API、数据库适配器、浏览器自动化等任何可供 Agent 调用的工具层。
  • 输入、输出与验收标准:输入为一个领域动作;输出为明确 schema、权限语义、错误分类和 contract tests。验收时应能预测调用副作用、参数限制和失败恢复方式。
  • 文件改动清单:可新增工具 schema、适配器、契约测试与工具目录;按实际平台组织。
  • 完整命令:无通用命令。为每个工具提供可在 CI 或本地执行的 contract test 命令。
  • 测试步骤与预期结果:覆盖合法输入、边界参数、空结果、权限拒绝、重复调用和 dry-run;预期返回结构稳定且不产生意外副作用。
  • 常见错误、回滚方法与安全边界:不要暴露全量数据库、密钥或隐含写入动作。高风险写操作必须最小权限、可审计,并支持幂等或明确的人工审批。