工具是 Agent 的手,入参出参设计决定成功率
上一讲结束,我们留了个尾巴:Agent 的循环里,”行动”这一步要靠工具,可工具不是天上掉下来的——给 Agent 造什么手?手的形状怎么设计,它才用得顺手?
你在设计 Agent 工具时,最常见的做法是什么?把现有的 API 挨个包装一遍:有 list_users 接口就包个 list_users 工具,有 get_user 接口就包个 get_user 工具。直觉上这很合理——接口现成,包装省事。但这一讲咱们要说清楚:这恰恰是 Agent 工具设计里最常见的翻车姿势。
问题一:直接包装 API,为什么会翻车?
Anthropic 在工具设计指南里讲了一个特别形象的例子。假设我们要做一个通讯录 Agent,帮用户查联系人。如果按照”包装 API”的思路,会做出一个 list_contacts 工具——返回全部联系人,让 Agent 自己慢慢找。
问题来了:假如通讯录里有 1000 个联系人,这个工具会返回 1000 条记录,Agent 得把 1000 条逐个读进上下文,token 一个一个地过,才能找到那一个要找的人。
回想第 3 讲讲的内容:上下文是稀缺资源。1000 条联系人记录灌进来,预算烧掉一大截,注意力被稀释,后面的正经事反而干不好。正确的做法是 search_contacts——按名字搜索,只返回匹配的那几个。把”找”这件事放在工具里完成,而不是把数据全倒给 Agent 让它自己翻。
举个栗子:API 是给程序用的,程序的内存便宜,遍历一千条不算事;Agent 的”内存”是上下文窗口,贵得很。让 Agent 翻一千条记录,就像让你在一本没有目录的字典里查字——能查,但谁受得了。
这就是核心认知:Agent 用工具的方式,和传统软件不一样。官方有个词叫 affordance,可以理解为”这东西到底能怎么用”。软件遍历便宜、缓存随便、想造多少造多少;Agent 读一条信息就烧一份预算。所以工具不是 API 的包装,而是按 Agent 干活的方式重新设计的接口。
问题二:好工具的设计原则,是哪几条?
Anthropic 把工具叫做”确定性系统和非确定性 Agent 之间的契约”。契约写得好不好,直接决定 Agent 的成功率。四条原则:
第一条:按工作流合并,不按 API 拆分。设计调度工具时,不要做成 list_users + list_events + create_event 三个工具(Agent 要调三次,中间结果全过上下文),而是做一个 schedule_event——找空闲、定时间、建日程,一次完成。工具应该对应”人做这件事的自然步骤”,而不是数据库的表结构。
第二条:命名空间清晰,边界不打架。工具多了之后,名字就是路标:asana_search 和 jira_search 一眼就能分清。功能重叠、名字含糊的工具会让 Agent 犹豫——而一个犹豫不决的 Agent,比没有工具更糟。
第三条:返回高信号内容,别返回技术标识符。这一条反直觉但极其重要:返回 name、file_type 这样的人话,而不是 uuid、mime_type 这样的鬼话。Anthropic 实测发现,仅仅把 UUID 换成有语义的标识符,就显著减少了 Agent 的幻觉——模型处理自然语言名字,比处理 550e8400-e29b 这种串可靠得多。
第四条:省 token,错误信息要可操作。返回内容分页、过滤、截断,提供简洁/详细(concise/detailed)两档格式。报错别只甩一个”Error 403″,要告诉 Agent 怎么修。比如:”没有权限访问该项目,请先请求项目所有者授权,或换一个 project_id”。
差的工具设计 好的工具设计
list_contacts search_contacts(按名字搜)
read_logs search_logs(只回相关日志+上下文)
三个 API 各包一个 schedule_event(一次搞定)
返回 uuid 返回 name(人话)
"Error 403" "没有权限,请先找管理员开权限"
还有一条容易被忽视的:工具描述就是提示词。工具的描述文字是写进上下文、给模型读的——要像给新同事写工作简报一样写它:干什么用、什么时候用、什么时候别用、参数是什么、返回什么。Anthropic 在他们的多 Agent 系统里,仅仅重写了一遍工具描述,后续 Agent 的任务耗时就降了 40%。
40%,只是改了改说明书。描述是写给模型看的,不是写给人看的——这话咱们在 skill 课讲 description 时说过一次,这里又应验了。思想是通的。
问题三:怎么知道工具设计得好不好?
答案和第 2 讲的防幻觉一脉相承:靠实测,不靠感觉。把工具交给 Agent 跑真实任务,然后看它的调用轨迹:
调错工具 该用 search 用了 list——名字或描述有歧义
参数给错 该传名字传了 ID——参数设计不清晰
调用太少 该搜的不搜,硬编——工具能力没传达清楚
结果误读 返回了正确数据但理解错——返回格式不友好
每种翻车姿势都对应一个设计缺陷。看轨迹、找翻车、改设计、再跑一遍——这套”评估与迭代”的完整方法,第 9 讲会展开成体系,今天先建立意识:工具设计不是写完就完,是跑出来的。
落到 sdd-site-agent:工具清单怎么设计
回到贯穿项目。上一讲作业①里,咱们给四步循环列了工具清单初稿。用今天的四条原则体检一遍,sdd-site-agent 的工具应该是这样:
read_spec 按名字读某个规范(读文件,只读)
入参:规范名 出参:规范内容(截断保护)
write_artifact 写产出到指定目录(写需求/原型/方案/代码)
入参:类型+文件名+内容 出参:写入确认
run_check 跑验证命令(白名单内的命令才允许)
入参:命令名 出参:结果摘要+是否通过
注意三件事:一是数量克制,三个工具就够——多了反而让 Agent 犹豫;二是每个工具都有权限边界(read 只读、write 限定目录、run 限定白名单命令),这是第 10 讲安全内容的伏笔;三是”哪些该接 MCP”的加分题——MCP 是一个连接外部工具和服务的开放协议,接入了就能直接用别人造好的”手”——文件系统、数据库这类通用能力可以走 MCP 生态,业务专属的工具自己写。
实操演练(约 25 分钟)
必做部分 + 一步加餐。做完必做部分,本讲的核心手感就到手了。
检验一下
①sdd-site-agent 工具清单正式版:名称/入参/出参/权限边界,标注哪些走 MCP——第 7 讲讨论”skill 与工具分工”时,这份清单是座上宾。
tools.py里全有对应物:读文件、写文件、跑命令、加载 skill——而且每个工具的权限边界都在代码里卡死(_safe_path把读写限定在 workspace、命令白名单枚举)。先自己动手做,再对照着看。mini-agent 的完整代码,后续我会分享出来——但别等它,先把你的设计做出来。你如果想深挖一层,读这篇:Anthropic · Writing effective tools for agents
四条原则的完整版、通讯录例子的原文、”40%”的出处都在里面。它还有配套的评估 Cookbook 开源仓库,做工具评估时可以用。(沈剑注:接口文档写得烂,联调就是灾难——工具描述,就是 Agent 时代的接口文档。)
但还有一个没解决的问题:工具给了 Agent 手,可光有手不会干活——它还得知道”我们这个团队是怎么做事的”:需求文档按什么格式写、代码按什么规范出。这些 know-how(经验诀窍)放哪?——第 7 讲,我们讲 Skill 与知识沉淀。
知其然,知其所以然。思路比结论更重要。