面向 Agent 的工具设计
面向 Agent 的工具设计 是本库对 Anthropic《Writing effective tools for agents – with agents》一文的归纳视角:工具不只是传统 API 的薄包装,而是 AI Agent(智能体)感知世界、选择动作和接收反馈的操作界面。
这不是一个单一标准或官方术语。它更接近 Agent-Computer Interface(智能体计算机接口)在工具层的工程清单:用少量高价值工具支撑真实工作流,用 Evals(评估)观察 Agent 实际怎么用工具,再把失败 trace 反向转化为工具命名、schema、描述、输出格式和错误反馈的改进。
工具不是 API 端点的直译
传统软件接口面对的是确定性调用方:函数名、参数和返回值可以默认由工程师理解。Agent 工具面对的是非确定性调用方:模型可能不用工具、用错工具、传错参数,或把工具结果理解偏。
因此,工具设计的目标不是“把所有后端能力暴露出来”,而是让 Agent 更容易走出合理策略。Anthropic 的建议可以压缩成三条:
- 少做通用枚举型工具,多做贴近真实任务的高层动作
- 避免一堆相似、重叠、边界模糊的工具同时进入上下文
- 把常见多步链路合并进工具内部,减少 Agent 在上下文里做机械胶水工作的机会
例如,与其提供 list_users、list_events、create_event 三个底层接口,不如提供一个 schedule_event,让工具在内部处理查可用时间、建日程和返回关键上下文。与其让 Agent 拉取全部日志再自己筛,不如提供 search_logs,只返回相关行和必要上下文。
评估驱动的工具迭代
面向 Agent 的工具设计必须从 eval 开始闭环,而不是凭接口作者的直觉判断“这个工具应该好用”。
一个实用流程是:
flowchart LR
P[快速原型] --> E[真实任务评估集]
E --> R[运行 Agent 工具调用]
R --> T[阅读 trace 与指标]
T --> I[改工具实现/描述/schema]
I --> E
评估任务应来自真实工作流,并且足够复杂,能够迫使 Agent 多次调用工具、组合信息、处理歧义。过于简单的 sandbox 任务通常只能证明工具“能被调用”,不能证明 Agent 在真实环境里会用对。
除了最终准确率,还应收集工具调用次数、工具错误、单次工具耗时、任务总耗时、token 消耗、是否调用了预期工具等指标。大量冗余调用可能说明分页或响应默认值不合适;大量参数错误通常指向工具描述、参数名或 schema 不清楚;Agent 没有调用某个关键工具,可能说明工具名和触发条件没有进入模型的策略空间。
文章中的示意图给了一个典型闭环:Claude Code 先根据需求写出 Gmail MCP server,再运行 Gmail eval;评估报告显示准确率、平均任务时长和失败点后,Claude Code 回到工具实现里修复 send_email 一类具体问题。右侧任务覆盖发邮件、搜索报告、总结 thread、删除垃圾邮件,说明一个好的工具 eval 不应只测单个 API 调用,而要覆盖多种真实动作意图。
两张 held-out test set 图显示,Claude 优化工具在 Anthropic 内部 Slack 与 Asana 工具上都带来提升:
| 工具集 | Human-written MCP server | Claude-optimized MCP server |
|---|---|---|
| Slack tools | 67.4% | 80.1% |
| Asana tools | 79.6% | 85.7% |
这些数字的重点不是“自动生成一定超过人工”,而是:工具描述、schema、输出格式和实现细节可以被 eval 驱动地优化,并且要用 held-out 集验证是否泛化。
名称、命名空间与工具边界
工具名是 Agent 选择动作时最早看到的信号。工具数量一多,命名边界就会变成 Context Engineering(上下文工程)问题:每个 schema 都占 token,每个相似名称都会增加选择分支。
命名空间的价值在于显式划边界。比如 asana_projects_search、asana_users_search 比多个裸 search 更容易让 Agent 判断工具属于哪个服务、处理哪类资源。前缀还是后缀更好没有通用答案,应由 eval 决定;不同模型和任务可能对命名模式敏感。
更深一层的原则是:工具集合应该反映人类会如何分解任务。清晰、少量、目的不同的工具,比大量 API 端点式工具更容易让 Agent 形成稳定策略。
工具响应也是界面
工具输出不是日志转储,而是给 Agent 的下一步观察。好的响应要在“可继续行动”和“节省上下文”之间取平衡。
常见规则:
- 返回语义字段优先于内部技术字段,例如
name、file_type、image_url通常比随机 UUID 更能帮助模型决策 - 需要下游调用的技术 ID 可以保留,但不要让它淹没内容本身
- 为响应提供
concise/detailed这类格式选项,让 Agent 在探索和执行阶段切换信息量 - 对大结果默认分页、过滤、范围选择或截断,并在截断信息里提示更精确的下一步查询方式
- 错误响应要告诉 Agent 参数哪里错、可用格式是什么,而不是只返回栈追踪或模糊错误码
这和 Function Calling(函数调用)的 schema 设计是一体两面:输入 schema 决定 Agent 如何发起动作,输出结构决定 Agent 如何理解观察。
文章图片里的 Slack 搜索示例展示了 responseFormat 的取舍:
detailed响应适合后续还要调用工具的阶段:除消息正文外,还返回 channel ID、user ID、timestamp、thread timestamp、文件名等可作为下游参数的字段。concise响应适合快速阅读大量候选信息:只保留频道/DM、发送者、消息正文和日期,去掉大部分机器字段。
Stripe 交易搜索的截断示例则说明:截断不应只是砍掉尾部。更好的返回会说明总命中数、当前只展示前几条,同时给出全局摘要和下一步 refinements,例如按 vendor 搜索、按金额范围过滤、请求下一页。这样 Agent 即使没拿到全量数据,也知道如何继续缩小范围。
错误响应同样应该面向 Agent。一个差的错误只返回 RESOURCE_NOT_FOUND、422、字段名和值;一个好的错误会把失败原因翻译成可行动说明:当前 userId 不存在或格式错误,合法 ID 长什么样,以及应该先调用 user_search() 解析用户 ID。后者把失败变成下一轮工具调用的路标。
Anthropic 后续提出的 MCP 代码执行式用法把“工具响应也是界面”推进到执行层:大型工具结果不一定要完整回填给模型,可以先在代码执行环境中筛选、聚合、join 或脱敏,再只打印少量样本和摘要。此时工具设计要同时服务两个调用方:模型需要能通过文件和函数签名理解工具接口,执行代码需要稳定、可组合、类型清晰的返回值。
用 Agent 改进工具
Anthropic 的一个实践要点是:可以让 Agent 参与改进自己的工具。把评估运行产生的 trace、工具调用、工具响应和失败样例交给 Claude Code 这类编码 Agent,它可以批量发现工具描述矛盾、schema 不一致、输出冗余和实现问题。
但这不等于让生成者自证成功。更稳的做法是让 Agent 提出修改,再用 held-out eval set 检查是否真的提升,避免只对训练任务过拟合。这个结构接近 Evaluator-Optimizer(评估器-优化器):优化器可以是 Agent,但是否保留修改必须由外部评估裁决。
与相关概念的关系
- Agent-Computer Interface(智能体计算机接口) — 本词条是 ACI 在工具命名、schema、响应和错误反馈上的具体化
- Evals(评估) — 工具是否有效必须用真实任务和 held-out 任务验证
- Context Engineering(上下文工程) — 工具定义和工具结果都在竞争有限上下文预算
- Model Context Protocol(模型上下文协议) — MCP 扩大工具生态后,更需要命名空间、延迟加载和工具描述治理
- Claude API Tools — Claude 工具层承载这些设计原则的 API 实现之一
- Function Calling(函数调用) — 自定义工具 schema 是工具设计原则的常见落点