给 AI Agent 写工具函数的五个坑

举报
yd_222030558 发表于 2026/11/03 00:11:02 2026/11/03
【摘要】 工具描述、参数设计、幂等性、错误返回和上下文预算——写 Agent 工具时最容易出错的地方。

工具函数不是给人用的 API


给人写接口,可以靠文档、靠示例、靠沟通补足模糊之处。给 Agent 写工具,模型只能看到函数名、描述和参数 schema,看不到你的意图。描述写得含糊,模型就一定会用错,而且错得很自信。


下面五个坑,是实际把 Agent 接到生产流程里之后总结的。


坑一:描述写成了「标题」


反面例子:


name: query

description: 查询数据


模型看到这个只能猜:查什么数据?按什么条件?返回什么?


正面写法:


name: search_orders

description: 按条件查询订单列表。只返回最近 90 天的数据,最多 50 条。

  当用户询问"我的订单""买过什么""退款的单子"时使用。

  如果用户只给了模糊描述(比如"上次那个"),先用 list_recent_orders 获取候选,

  不要凭猜测直接调用本函数。

parameters:

  status: 可选,枚举 pending/paid/refunded,不传表示全部

  keyword: 可选,匹配订单号或商品名


三件事必须写清楚:做什么、什么时候用、什么时候不该用。其中「不该用」最容易被忽略,但恰恰是减少误调用的关键。


坑二:参数设计成万能对象


有的工具签名长这样:


{ "params": { "type": "object", "description": "查询参数" } }


把决策权全交给模型,等于让它自由发挥。它可能传一个嵌套三层的结构,也可能把日期写成「上周三」。


正确做法是把参数收敛成枚举、必填项和明确的格式约束:


{

  "date_from": { "type": "string", "description": "起始日期,格式 YYYY-MM-DD,例如 2026-10-01" },

  "status": { "type": "string", "enum": ["pending", "paid", "refunded"] }

}


有 enum 就用 enum。枚举把「模型猜」变成「模型选」,成功率差得非常远。日期这类有格式要求的,描述里必须给一个真实示例,光说「ISO 格式」不够。


坑三:忘了幂等


Agent 会重试。网络抖一下、超时一次,它可能就把同一个操作再执行一遍。如果你的工具是「提交订单」「发送邮件」「创建工单」,重复执行的后果是真实损失。


三个手段,按成本从低到高:


第一,读操作和写操作分成两个工具,名字上就区分开(get_order / create_order),别让一个工具既能读又能写。


第二,写操作接收一个 idempotency_key 参数,服务端按 key 去重。描述里明确告诉模型:同一个逻辑操作要复用同一个 key。


第三,危险操作加 dry_run 参数:


dry_run: 布尔,默认 true。为 true 时只返回将要执行的操作预览,不产生实际副作用。

  用户明确确认后再传 false 执行。


这条对 Agent 场景特别有效——模型先生成计划给用户看,确认了才动手,比事后再补救强得多。


坑四:错误信息只写了一句话


工具失败时返回 {"error": "failed"},模型就彻底失明了:它不知道是参数错了、权限不够、还是资源不存在,只能瞎猜着重试。


错误返回应该包含可执行的下一步:


{

  "error": "PERMISSION_DENIED",

  "message": "当前账号没有该仓库的写权限",

  "hint": "请换用有写权限的仓库,或先调用 list_writable_repos 查看可用列表"

}


关键在 hint:告诉模型接下来该干什么。有了这一条,模型能自己纠偏;没有这一条,它只会重试三次然后放弃,还给你一个「操作失败」的空洞结论。


另外建议把错误码做成有限枚举(NOT_FOUND / PERMISSION_DENIED / INVALID_ARGUMENT / RATE_LIMITED / UPSTREAM_ERROR),模型对不同错误码的处理策略可以完全不同——RATE_LIMITED 该等一会儿重试,INVALID_ARGUMENT 重试一万次也没用。


坑五:返回值塞了整个接口响应


顺手把上游 API 的原始 JSON 返回出去,几百个字段,其中 90% 是模型不需要的。后果是上下文被瞬间撑爆,后面几轮对话它就开始「忘事」。


工具返回应该为模型裁剪过:

· 列表接口默认只返回关键字段,最多 20 条,并给出总数;

· 大文本做截断,明确标注 truncated: true 和原始长度;

· 时间统一成带时区的 ISO 字符串,别混着时间戳和「3 天前」;

· 字段名保持稳定,模型会依赖这个稳定性。


还有个细节:返回结构里不要把「人类看的文案」和「机器用的数据」混在一起。模型容易把展示文案当成数据来源,导致后续解析错误。


最后:工具数量和粒度


工具不是越多越好。二十个语义重叠的工具,模型选择准确率会明显下降。宁可把同类操作合并成一个带 action 枚举的工具,也不要拆成一堆名字相近的小函数。


粒度上,一个工具对应一个「用户能说出口的动作」。用户会说「帮我查一下上周的订单」,不会说「帮我调用 search_orders 并传入 date_from」。工具设计应该贴着前者的语言习惯走。


写完之后找个不懂技术的人看一遍描述,问他「这个函数是干什么的、什么时候该用」。如果他答不上来,模型多半也答不上来。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。