为智能体设计工具

A18
概念 · 智能体 AI 详解

为智能体设计工具。

当智能体挑错工具、传进畸形参数、或者对着一个一直失败的调用死循环时,问题几乎总是出在你的工具上,而不是模型上——而且今天下午就能修好,不必碰提示词,也不必换模型。工具是一份写给这样一位读者的接口:他没有文档、两次调用之间不记事、还受严格的令牌预算约束;照着这位读者来设计,而不是把你手头已有的 API 直接暴露出去,是智能体工程里杠杆率最高的一项工作。

STEP 1

你的 API 不是工具。

最常见的生产事故很机械:把智能体指向现成的 REST API,每个端点生成一个工具,发布。它几乎能跑通,这才是它昂贵的地方。API 是为这样的开发者设计的:读过文档、能跨调用保持状态、还会写代码把响应缝起来。智能体一样都没有。

  • 响应太宽。一个典型端点返回四十个字段,而智能体只需要三个。每个用不上的字段,你不但这一步要付钱,循环后面的每一步都要再付一次,因为对话记录每次都会重发。请投影到任务真正需要的那几个字段。
  • 分页会渗进推理里。拿到游标的智能体会花掉若干轮去翻页,有时还会提前收手、用残缺数据作答。请在工具内部处理分页,返回的要么是完整结果,要么是一个显式、结构化的「已在 M 条中截断为 N 条」标记。
  • 模型不可能知道的标识符。一个要求内部 UUID 的工具,会逼智能体先做一次它只能靠猜摸索出来的查询。请接受人类可读的名称,由你自己去解析。
  • 一个端点很少等于一个任务。如果完成一个真实用户请求总是要按同样顺序调用同样的四次,那这条序列才是工具。把它作为一个工具发布。

工具设计的单位是任务,不是端点。一层处理分页、投影字段、把名称解析成 ID、并返回带类型对象的包装,不是什么便利层——它是「能收工的智能体」与「烧掉十二步去拼凑本该被直接递给它的上下文的智能体」之间的分水岭。

STEP 2

工具要更少,描述要写给一位能干的陌生人看。

工具定义就是提示词文本。它们在每一次调用中都占据上下文窗口,都在和真正的任务抢注意力,而一旦超过大约两三十个,模型的选择准确率就会开始明显下滑——不是因为它读不完,而是因为近似重复的工具制造了一个没有明确正确答案的选择题。

  • 重叠比缺失更糟。search_usersfind_user 保证每次调用都是抛硬币。要么合并,要么在各自描述的第一句话里把边界写得不容误认。
  • 描述才是该花笔墨的地方。说清这个工具做什么、什么时候该用它、什么时候该用、以及它返回什么。「搜索记录」不算描述。「按邮箱或公司域名查找客户;最多返回 20 条匹配,含账户状态。已经有 ID 时请改用 get_customer。」才算。
  • 为调用者命名,而不是为代码库命名。名称在选择上的权重高于任何其他字段,而一个内部服务名对模型毫无意义。
  • 约束写在 schema 里,别写在散文里。枚举、必填与格式由结构化输出机制强制执行;一句客客气气请求使用 ISO 日期的话,则没有任何东西来强制。机制参见工具调用
  • 给响应设预算。定下一个工具最多能返回多少令牌,并在工具边界处强制执行。截断时留一个智能体能据以行动的标记,大载荷则按引用返回——一个路径、一个 ID、或一段摘要加一条取回更多内容的途径。
STEP 3

报错是你唯一的反馈通道。

工具的报错信息不是一行日志。它是一段提示词,恰好在模型决定下一步做什么的那一刻送达,也是运行中的智能体得知自己错了的唯一途径。多数堆栈跟踪和多数 HTTP 状态码只告诉智能体「有东西失败了」,却完全不说「怎样才能成功」——这正是智能体会反复重试同一个失败调用的原因:你没给它别的招。

  • 说清下一步该怎么做。「日期格式无效。期望 YYYY-MM-DD,收到的是 'last Tuesday'。」下一轮就能纠正。「400 Bad Request」则会催生重试死循环。
  • 区分可重试与终止性失败。限流值得等一等;权限拒绝不值得。如果智能体分不出这两者,它就会一视同仁,而其中一种处理方式必定是错的。
  • 把失败当数据返回,而不是当异常抛出。「没有结果」是一个正当的结果,就该长成结果的样子;一个空列表加一句「搜索了什么」的说明,能让智能体继续推理,而不是去猜工具是不是坏了。
  • 写操作类工具要做成幂等的。在智能体系统里,重试是结构性的——来自模型、外壳、网络与队列。一个接受调用方提供的幂等键的写工具,能把四个重复来源收敛成一个安全结果;运营层面的深入讨论见幂等、重试与副作用安全
  • 在返回值里确认副作用。「已创建发票 INV-1042,金额 $240.00」让智能体可以核对,也让你的追踪能还原发生了什么。「OK」两样都做不到。

工具结果是不可信输入。工具取回的任何东西——一个网页、一条工单正文、一个文件——都可能夹带针对你智能体的指令,而一段体贴详尽的报错正是安放它们的好地方。请把数据与指令的边界保持显式;参见提示词注入

STEP 4

像迭代提示词那样迭代工具。

工具设计不是靠想就能想对的事。它要被度量,而度量很便宜:几十个真实任务,端到端跑一遍,把工具调用记录下来。你要找的东西比「任务是否成功」更细。

  • 选择准确率——它有没有挑对工具?系统性的挑错指向的是某个名称或某句开头,而不是模型。
  • 参数合法率——有多大比例的调用被你自己的 schema 打回?这个数字就是描述的缺陷率。
  • 每完成一个任务的调用次数——这个计数会暴露出「缺了一个合并版工具」,也会经由对话记录的平方级增长直接体现在账单上。
  • 报错后的恢复率——在失败的调用中,有多少条之后跟着的是一次纠正后的调用,而不是原样重来?这一项专门给你的报错信息打分。

然后去读对话记录。用错工具的智能体,通常会在动手之前一刻用大白话说出它为什么这么想——这是一个白送的、且只有靠阅读才能拿到的无可替代的信号。把每次修复都放回同一组任务里重跑;这就是把智能体评估对准你的接口,而不是对准模型。

在新增一个工具之前,先试着删掉两个。然后挑出表现最差的那个工具,把它的描述重写成写给一位从没见过你的系统、也无法提问的能干外包同事的说明,给它的返回加上上限,并让它的报错说清下一步该怎么做。重跑你那组任务。在多数智能体系统里,这一遍带来的成功率提升超过换一个更强的模型,而且与换模型不同的是,它还让系统更便宜。

延伸阅读:工具、动作与环境讲工具在根本上是什么,MCP 讲把工具分发出去的标准方式,上下文工程讲工具响应最终汇入的那门工程。