工具是契约,不是 API 包装
面向任务语义设计工具,把 schema、风险、超时、幂等和输出裁剪写进契约,让模型选得对、错得起、恢复得了。
面向 Agent 的任务语义设计工具,而不是一对一包装现有 API。后端有 40 个 REST 端点,不代表 Agent 就该有 40 个工具:模型在 6 个任务语义清晰的工具里选对的概率,远高于在 40 个名字相近的端点里选对的概率。而且工具描述常驻上下文,工具越多,每个工具分到的注意力越少。
工具是模型与确定性系统之间的契约
所谓契约,是把模型从代码里推断不出来的东西显式声明出来:name、version、description、inputSchema、outputSchema、annotations(readOnly、destructive、idempotent、openWorld)、riskLevel、approvalPolicy、timeoutMs、retryPolicy、resultPolicy。缺任何一项,模型或 Runtime 就只能靠猜。
漏掉 idempotent,一次重试可能在生产环境造成重复扣款;漏掉 openWorld,模型不知道这个工具会访问公网,也就不知道返回值里可能混进不可信内容;漏掉 timeoutMs,Runtime 不知道该在什么时候接管。这些都不是文档问题,是运行时的分支条件。
readOnly 那一栏最容易被当成合规字段,其实它是运行时开关。感知工具不改外部世界,于是结果可以安全缓存(相同查询直接复用),多次调用可以放心并行(同时读五个文件、并发发起三个搜索)。执行工具没有这种自由,顺序和副作用都得严格控制 ai-agent-book。你少声明一次 readOnly,就等于主动放弃这两项收益。
描述决定选择准确率
差:search: 搜索数据
好:supplier.search:按归一化后的产品需求检索内部供应商记录。
在公开网络检索之前使用。最多返回 20 条候选,包含 ID、命中字段和来源证据。
只读,不会联系供应商。
好描述要回答七件事:做什么、何时用、何时不要用、输入字段的含义、返回什么、有什么副作用、失败后怎么恢复。前三条决定模型会不会选中它,后四条决定它能不能把参数填对、把结果用对。
「何时不要用」最常被省掉,而它恰恰是避免工具重叠的关键——两个描述都很泛的工具摆在一起,模型没有别的依据,只能猜。
schema 表达不了隐式约定。时间戳要秒还是毫秒、过滤条件怎么嵌套、空数组是「不过滤」还是「清空」——这类约定写在描述里比写在类型定义里有效。更省字的写法是给每个工具附 1–5 个真实调用示例;书里给的量级是,一些基准上工具调用准确率从约 72% 提到约 90% ai-agent-book。
参数会在链路里被静默改写
有一类失败模式只在真实链路上暴露。Cursor 某个版本的编辑工具接收 old_string 与 new_string 做精确匹配替换,而参数传递层会把中文弯引号(\u201c、\u201d)静默换成英文直引号。读取工具原样返回弯引号,模型照着传,工具回「未找到匹配」;模型看不见中间那次替换,只能反复重试、反复失败 ai-agent-book。写入方向更糟:本意写入弯引号,落盘成了直引号,再读回来发现内容「不对」,模型还以为自己写错了。
所以契约里要多写一项:参数从模型到执行会经过哪些改写——引号归一化、Unicode 规范化、空白折叠、路径分隔符、换行风格。这一项不能在 schema 层测出来:schema 测试全绿而链路仍在改你的字节,是最难查的一类缺陷,因为报错发生在离病因很远的地方。
输出必须裁剪,不然就是在烧上下文
输出要结构化、有界。禁止返回原始大 HTML、完整数据库行和无界日志;长日志、测试输出、进程列表和 Diff 要做确定性压缩,同时保留退出码、失败位置、关键错误、统计和 ArtifactRef。
Anthropic 用 16 个并行 Claude 编译 C 编译器时踩过这个坑:测试 harness 打印几千字节的无用输出,直接污染上下文窗口;agent 被丢进全新容器、没有任何上下文,又要花大量时间重新定位。他们的解法是重写 harness——每个测试最多打印几行,重要信息写进文件;日志要能被 grep,有错就写 ERROR 并把原因放在同一行;预计算汇总统计,避免每个 agent 重复算一遍。anthropic-c-compiler
错误要交给该处理它的一方
Error Contract 只有一条分界线:预期内的失败(参数不合法、目标不存在、配额不足)作为结构化错误数据返回给 Agent,让它自己决策;认证失败、权限不足、数据损坏、Runtime 缺陷和未知异常,由 Runtime 终止或中断执行,绝不把整段 exception 灌进上下文。
错误对象至少带 code、category、message、retryable、safeForModel、suggestedActions。safeForModel 是闸门,决定这条信息能不能进模型上下文。没有它,一次数据库栈回溯就能吃掉半个窗口的预算,而模型从中得不到任何可行动的信息。
工具也要写测试
每个工具至少覆盖八项 Tool Evals:正确选择工具、不该调用时不调用、参数正确率、对错误结果的恢复、Token 效率、描述变更后的回归、危险参数是否被 Guardrail 拦下、重试是否造成重复副作用。anthropic-evals
后两项是安全问题,不是质量问题。漏掉它们,你第一次发现缺口的地方会是生产事故。
代价与自检
代价是前期工作量:每个工具都要写清 schema、风险、超时和压缩逻辑,还要维护 evals。工具数量少、任务稳定的场景回报最高;一次性脚本和探索性原型不值得这么投入。
三个问题可以自查:你的工具里有没有一对一照搬 REST 端点的?它们的描述写了「何时不要用」吗?一个工具失败时,返回给模型的是结构化错误还是一整段栈?
