给 Agent 设计工具:描述比实现更重要

2026-07-28

数据截至 2026-07,规范与各项目能力以官方文档当前版本为准。

模型永远看不到你的工具是怎么实现的。它能看到的只有三样东西:工具名、工具描述、参数 schema。所以当 agent 反复调错工具、参数填得莫名其妙、或者该调的时候不调,第一个该改的地方几乎不是模型和提示词,而是这三样东西写得太随意——它们是喂给模型的提示词,不是给同事看的代码注释。

很常见的一个误解是:把工具当成普通的函数封装。函数写完了,描述顺手把 docstring 抄过来,参数名沿用代码里的 uidtsflag,觉得”反正能跑通”。技术上确实能跑通,调用链路一点问题没有。但模型做的是一件和调用函数完全不同的事——它要在几十个候选里判断”现在这一步该用哪个”,还要凭描述里的只言片语猜出每个参数填什么。描述含糊,它就只能靠猜。

一、模型眼里的工具只有一张说明书

不妨换个视角想:假如你新入职一家公司,桌上放着一份工具清单,每个条目只有名字、一句话说明和一张参数表,没有源码、没人可问,客户的请求进来你就得立刻选一个用。这时候什么样的清单能让你干得好?大概是:名字一看就知道干什么、说明里写清了什么情况用什么情况别用、参数表标明了格式和取值范围。

模型的处境和这个新人几乎一样,而且更极端——它连”去问一下同事”这个选项都没有。所以工具定义的质量,直接决定了 agent 行为的稳定性。实现层面的性能优化、缓存、重试,这些当然重要,但它们影响的是工具跑起来之后的事;描述影响的是”要不要跑、怎么跑”,是更前置的一环。

一个可以立刻做的自检:把你的工具定义(只保留名字、描述、参数 schema,去掉所有实现代码)复制出来,交给一个完全不了解这个项目的人,让他根据几个真实请求判断该调哪个、参数填什么。他卡住的地方,模型大概率也会卡住。

二、名字:用动词加对象,别塞内部术语

工具名是模型最先看到、也是成本最低的信号。几条实用做法:

  • 动词开头,明确这是一个动作:search_ordersorders 好,cancel_subscriptionsub_op 好。
  • 别用团队黑话和缩写get_wms_snapshot 里的 WMS,团队内部人人都懂,模型只能猜。要么展开,要么在描述里第一句解释清楚。
  • 同一批工具命名风格统一。混着用 fetchUserget_order_listQueryStock,会让模型在”这些是不是同一类东西”上产生不必要的犹豫。
  • 名字里体现关键差异。如果有两个查询工具,一个查实时一个查历史,那就叫 query_stock_realtimequery_stock_history,别叫 query_stockquery_stock2

名字改好通常几分钟的事,但对选错工具这类问题的改善往往立竿见影,性价比很高,值得优先做。

三、描述里该写的四件事

工具描述最容易写成一句废话:“查询订单信息。“这句话没有增加任何模型不知道的信息——名字里已经写了。一份能真正起作用的描述,至少要覆盖下面四件事:

  1. 这个工具具体做什么,返回什么。不是”查订单”,而是”按订单号查询单条订单的状态、金额和物流单号,只返回近 12 个月内的订单”。范围限制写进去,模型才不会拿它去查三年前的单子然后拿到空结果绕圈。
  2. 什么时候该用。给一两个典型场景:“用户询问某笔具体订单的进展时使用。”
  3. 什么时候不该用。这一条最常被漏掉,却最有价值:“如果用户没有提供订单号,先用 search_orders 按时间或商品名检索,不要凭空构造订单号调用本工具。”
  4. 和相邻工具的区别。当两个工具功能有重叠,就在各自描述里直接点名对方:“本工具只读;如需修改地址请使用 update_order_address。”

第 3 条和第 4 条是把”负面示例”和”边界”显式写出来,正好补上了模型最容易犯错的两类情况:该调别的却调了这个,以及缺少前置信息就硬调。

四、参数 schema 是第二份提示词

很多人把参数 schema 当成类型校验,其实它同时也是模型的填空指引。同样是一个”时间范围”参数,写成 start: string 和写成下面这样,效果差别很大:

{
  "start_date": {
    "type": "string",
    "description": "起始日期,格式 YYYY-MM-DD,例如 2026-07-01。若用户说“最近一周”,请自行换算成具体日期,不要传相对表述。",
    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
  }
}

几条经验:

  • 能用枚举就别用自由文本。状态、类型、渠道这类字段,把可选值直接列进 enum,模型不会再自创一个”已发货中”这种取值。
  • 每个参数都写 description,哪怕看起来很显然。尤其是单位(秒还是毫秒)、时区、是否含税这类隐含约定,不写就是让模型赌。
  • 必填与可选要分清,并在描述里说明可选参数不填时的默认行为。
  • 参数数量克制。一个工具挂十几个参数,模型填错的概率会明显上升;拆成两个职责更窄的工具,往往比堆参数更稳。
  • 别把结构化信息塞进一个大字符串。让模型拼一段 JSON 字符串再由你解析,等于把校验责任推给了最不擅长精确格式的一方。

五、返回值和报错也要为模型设计

工具跑完之后的返回内容会回到上下文里,成为模型下一步决策的依据。这块常见两个问题:

一是返回太多。把整个数据库记录原样吐回去,几十个字段里模型只需要三个,剩下的既占 token 又干扰判断。做法是在工具层做裁剪,只返回这一步真正需要的字段,需要详情时再提供一个单独的详情工具。

二是报错不可行动。返回 {"error": "invalid request"} 之后,模型除了原样重试没有别的选择,往往就陷进死循环。可行动的报错长这样:{"error": "order_id 格式不正确,应为 12 位数字,收到的是 'ORD-88'。请先用 search_orders 获取正确的订单号。"}——它告诉了模型错在哪、正确形态是什么、下一步该做什么。写清楚报错,很多看起来像”模型不听话”的问题会自己消失。

另外建议返回里带上一点状态信息,比如”共匹配 37 条,此处返回前 10 条”,模型才知道还有没有必要翻页。

六、先做减法,再考虑上框架

工具设计里有个反直觉的规律:工具越多,单个工具的描述质量要求越高,因为模型要做的是区分而不只是理解。五个工具时描述粗糙点还能凑合,三十个工具时描述里的模糊地带会被成倍放大。所以扩充工具集之前,先问一句:这几个能不能合并?那几个是不是根本没被调用过?

框架层面也有类似的提醒。在一份 2026 年的第三方实战对比里,作者明确提出:单个 agent 只调一两个工具时,OpenAI Agents SDK 或 Anthropic Claude Agent SDK 往往是更快的路径,可能根本不需要多智能体框架。这个判断值得放在设计之初考虑,避免为了一两个工具搭一整套编排系统。同一份对比还提到,就 token 开销而言,LangGraph 表现较好、AutoGen 开销最大——这是第三方口径的实测结论,不是各项目的官方说法,实际差异和你的工具设计、调用轮数关系很大。

七、框架帮得到的和帮不到的

把工具描述写好之后,编排层的选择才真正开始起作用。按第三方对比的口径,几个框架的定位有明显差异:LangGraph 是有向图模型,节点是函数或 LLM 调用、边定义控制流、状态以带类型的字典传递,控制力和生产成熟度都较强,并提供 checkpointing、streaming、human-in-the-loop 这类原语;CrewAI 是一队有明确角色的 agent,上手门槛最低,适合流程基本线性、要快速出原型的场景,它在 2025 年还加了 Flows 这种事件驱动的 pipeline 模式,面向更可预测的生产负载——不少较早的对比文章没覆盖这一点,别沿用”CrewAI 只能做原型”的旧结论。

AutoGen 这边需要单独说明:据第三方对比的说法,微软把重心转向了更大的 Agent Framework,AutoGen 的主要新功能开发已经停止,仍有 bug 修复和安全补丁。这不等于它不能用,存量项目也不必急着迁移,但新项目起步时值得把这条信息纳入考虑。

互操作方面,CrewAI 已加入 A2A 支持;OpenAgents 声称自己是唯一原生同时支持 MCP 与 A2A 的框架——“声称”两个字保留,这一条未做独立核实。

需要泼一盆冷水的是:这些框架谁都不会替你把工具描述写好。它们解决的是编排、状态、恢复、可观测性;模型选错工具、参数填错,换个框架依然会错。顺序应该是先把工具定义打磨到位,再选编排层。

八、怎么验证描述改得有没有效

改描述最怕的是凭感觉。几个能落地的验证方式:

  • 攒一个小回归集。二三十条真实请求,标注每条期望调用哪个工具、关键参数是什么,每次改完描述跑一遍,看选对率和参数正确率。规模不用大,但要覆盖容易混淆的成对工具。
  • 做消融对比。怀疑某句描述有用,就把它删掉再跑一遍回归集。有些自以为关键的说明,删了指标没变化;有些随手加的一句,删了掉一大截。
  • 读完整的调用轨迹,而不只看最终答案。答案对了不代表过程对,agent 可能试错三次才蒙对,这种在真实流量下很脆弱。
  • 把失败样本回灌进描述。模型犯了某个错,就在对应工具的描述里加一句针对性的边界说明,这是最高效的迭代循环。

诚实说说局限

上面这些做法能解决的,主要是”选错工具”和”参数填错”这两类问题,它们在实践中占比不小,但不是全部。有几件事描述再怎么写也解决不了:任务本身规划链条太长导致中途走偏,需要的是任务拆解和检查点;工具本身返回的数据就是错的,那属于数据源问题;模型能力不足以理解领域概念,那要靠提示词里的背景知识甚至微调。

另外,描述写得越细,占用的上下文就越多,工具集大的时候这部分开销不能忽略。实际做法通常是在”写清楚”和”别太长”之间找平衡,或者按场景动态裁剪暴露给模型的工具子集——但后者本身也会引入”该露的没露出来”的新风险,不是免费的。

还要说明的是,本文提到的框架差异来自第三方实战对比,各项目迭代很快,具体能力和 API 请以各自官方文档当前版本为准。

小结

给 agent 设计工具,重心在描述而不在实现。工具名用动词加对象、避开内部黑话;描述要覆盖做什么、何时用、何时别用、与相邻工具的区别这四件事;参数 schema 当作第二份提示词来写,能枚举就别自由文本;返回值做裁剪、报错写成可行动的指引。工具集先做减法,单 agent 少量工具时未必需要多智能体框架,而框架无论选哪个都不会替你把描述写好。最后用一个小回归集把每次修改的效果量化出来,别凭感觉迭代。

接下来看什么

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。