跳到主要内容

为智能体编写工具:ACI 与 API 同等重要

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数工程师对待智能体工具的方式与编写 REST 接口或库函数如出一辙:清晰地暴露功能、记录参数、处理错误。这对人类来说是正确的直觉。但对于 AI 智能体(AI Agents)来说,这完全是错误的。

智能体使用的工具是以非确定性的方式被消耗的,它被逐个 Token 解析,并由一个对上周二使用过什么工具没有持久记忆的模型来选择。你编写的工具 Schema 并不是文档——它是运行时提示词(runtime prompt),在推理时被注入到模型的上下文中,塑造着智能体做出的每一个决策。每一个字段名称、每一段描述、每一个返回值的结构都是一个设计决策,具有可衡量的性能影响。这就是智能体-计算机接口(ACI,Agent-Computer Interface),它值得你像对待任何关键的面向用户的界面一样投入工程精力。

最小可行工具集是特性,而非妥协

我看到团队在构建智能体系统时最常见的错误是将每一个可用的 API 接口都封装成工具。这听起来很完整,很强大,但它却在悄无声息地降低性能。

智能体上下文中的每一个额外工具都会消耗注意力预算,并增加一个模糊的选择点。当智能体有 20 个工具,且其中 3 个看起来都能回答当前查询时,模型会将概率分布在这三个工具上。而当它只有 5 个工具且只有一个相关时,正确选择的确定性几乎是百分之百。更多的工具并不意味着更强的能力;它意味着更多的失效面。

设计测试很简单:如果你团队的高级工程师都无法毫不犹豫地明确说明在特定情况下应该使用哪个工具,那么就不能指望 AI 智能体做得更好。工具分类中的模糊性就是智能体行为中的模糊性。

从覆盖最高影响力工作流的 3 到 5 个工具开始。进行彻底测试。仅当评估数据表明存在工作流缺口时才进行扩展。在实践中,最大的收益往往不是来自增加工具,而是来自整合工具。一个能够通过一次调用返回姓名、状态、近期交易和公开备注的 get_customer_context 工具,其表现优于三个独立的 get_customer_by_idlist_transactionslist_notes 工具——因为它减少了智能体必须做出的连续决策数量,而连续失败的影响是乘积式的。

这一点比大多数团队意识到的更为重要。如果每个工具调用的准确率为 90%,那么一个三步链条的准确率为 73%。一个七步链条则降至 48%。工具集的架构——即完成一项任务需要多少次连续调用——是一个头等的可靠性变量。

工具描述是高风险的提示词

对待每一个工具描述都要像是在入职一个从未见过你代码库的初级开发人员。将隐性逻辑显性化。明确什么时候该用这个工具,什么时候不该用,每个参数代表什么,期望什么格式,以及这个工具与旁边类似的工具有何不同。

search_contacts 的描述不应只写:“搜索联系人。”它应该写成类似这样:“通过姓名、电子邮件或公司搜索联系人。当你需要查找特定人员时使用此工具。返回最多 10 条匹配记录。请勿使用此工具检索所有联系人进行批量分析——为此请使用 export_contacts_csv。如果用户提供了公司名称,请将其作为 company 参数传递,而不是包含在 name 查询中。”

这种程度的细致对于人类读者来说可能显得冗余。但对于模型来说,它消除了整类调用错误。对工具描述的改进——即使是微小的改进——也能在不更改任何代码的情况下产生可衡量的准确性提升。

两种模式特别有用:

负向引导:明确指出何时不要使用某个工具。如果没有它,即使有更合适的工具,模型也会尝试使用看起来合理的工具。

嵌入示例:对于具有非显式调用模式的工具,在描述中包含一个加工好的示例。单个具体的输入输出对可以解决段落文字无法解决的歧义。

返回值是上下文预算,而不只是数据

工具返回值被逐个 Token 消耗,并永久占据模型的上下文窗口。你返回的每一个对智能体下一步决策没有贡献的字段都是一种没有收益的成本——它挤占了任务剩余部分的推理能力。

返回所有内容并让模型决定什么是相关的这种直觉是错误的。模型无法丢弃已经处理过的 Token。设计返回值是为了让智能体理解,而不是为了开发者的完整性。

避免使用原始 UUID 和神秘的内部标识符。工具结果中返回的 UUID 消耗了 Token 却没有任何语义内容——模型无法对 f47ac10b-58cc-4372-a567-0e02b2c3d479 进行推理。一个人类可读的名称、状态字符串或自然语言描述能为模型提供推理的依据。

实现具有合理默认值的分页。一个在没有过滤器的情况下调用时返回 500 条记录的工具,在任何实际数据集上都会耗尽上下文。默认返回 10 或 20 条结果,支持 limit 参数,并包含一条截断消息,引导智能体进行更有针对性的后续查询,而不是仅仅说“存在更多结果”。

对于任何可能返回大量响应的工具,值得实现的一种模式是:带有 concise(简洁)和 detailed(详细)等枚举值的 response_format 参数。多步工作流中的智能体通常只需要中间步骤的高级信息;concise 格式可以在不浪费上下文在那些它不会使用的字段上的情况下提供这些信息。

这里的 Token 效率提升可能是惊人的。在结果返回给模型之前,数据处理发生在执行沙箱内部的代码执行环境中,生产系统在每个任务的 Token 消耗上已经实现了 90% 以上的降幅。

Schema 设计即性能工程

附加到每个工具的 JSON schema 在每次 API 调用时都会被注入到模型的系统上下文中。它的质量不仅仅是文档层面的问题 —— 而是性能层面的问题。

枚举(Enums)是实践中最被低估的 schema 特性。当一个参数具有有限的有效值集合时,将其表达为枚举可以完全防止模型生成无效值。这是 Agent 领域的 Poka-yoke(防错机制)—— 通过使无效状态在结构上无法表示来防止错误。将它们用于状态字段、格式选择、操作类型,以及任何具有定义值集的内容。

当工具与文件系统交互时,要求使用绝对路径而不是相对路径。相对路径是常见的模型错误;绝对路径要求通过单一的 schema 约束消除了这一整类错误。

从带类型的函数签名自动生成 schema —— 例如使用 Pydantic 的 Field() 注解和 model_json_schema() —— 远优于手动维护的 JSON。手动 schema 会偏离实现,导致不一致,并且无法从类型系统验证中获益。只有当 schema 是从代码生成而不是与代码并列编写时,它才成为单一事实来源。

关于命名:在服务于同一领域的工具中使用一致的命名空间。如果你有多个搜索工具,采用 asana_searchjira_search 模式 —— 或者更细粒度的 asana_projects_searchasana_tasks_search —— 可以让 Agent 通过推理分类法而不是记忆单个语义来导航大型工具集。

错误消息即修正契机

当 Agent 的工具调用失败时,错误响应会直接返回到模型的上下文中。这不仅仅是一个日志事件 —— 它是模型决定如何恢复的唯一输入。错误消息的质量决定了 Agent 是能成功自我修复,还是进入一个消耗 Token 却无法收敛的重试循环。

{"error": "invalid input"} 这样的通用错误是毫无用处的。模型无法获得关于哪里出错了或如何修复的信号。有用的错误消息会指明具体的无效参数,解释接收到的内容,并建议正确的形式。如果日期参数验证失败,错误消息应说明预期的格式、接收到的内容,并提供有效值的示例。

区别处理以下三类错误:

结构性错误 —— 格式错误的参数、错误的类型、缺失的必填字段 —— 应向模型返回详细且可操作的反馈,以便在上下文中进行修正。

瞬态运行时错误 —— 速率限制、超时、临时 API 停机 —— 应触发带有抖动(jitter)的指数退避,直到达到合理的上限。务必限制重试次数;不受限制的重试循环将耗尽时间和 Token 预算。

永久性错误 —— 无效凭证、未找到资源、授权失败 —— 不应重试。它们应该上报,交由人工监督,或导致 Agent 重新制定其方法。

结构性错误反馈循环对于迭代式的 Agent 任务尤为重要。接收到精准错误消息的 Agent 可以在紧接着的下一步中重新正确发起调用。而接收到模糊错误的 Agent 要么盲目重试,要么放弃任务。

以正确的方式评估工具设计

评估是发现工具描述模糊、返回值冗余或工具集存在重复重叠的方法。单一工具、单次调用的测试无法暴露这些问题。在生产环境中至关重要的故障模式往往出现在多步工作流中。

使用针对真实数据、需要三到五次连续工具调用的评估任务。不仅要衡量最终任务是否正确完成,还要衡量调用了哪些工具、顺序如何、调用了多少次以及总 Token 消耗是多少。记录分析(Transcript analysis)中的模式可以告诉你综合准确率得分无法反映的信息:

  • Agent 总是混淆两个相似工具的使用:描述边界问题
  • 在单个任务中重复调用同一个工具:分页参数或响应范围问题
  • 尽管整体性能很高,但在某个工具上的准确率较低:特定于该工具的 schema 清晰度问题

这里的原则是迭代:编写描述、运行评估、分析记录、优化描述、重新评估。单个工具的性能固然重要,但在真实的多步基准测试中端到端的任务完成情况才是反映生产行为的指标。

ACI 值得拥有独立的工程学科

你为 Agent 构建工具的方式决定了整个 Agent 系统的可靠性上限。你无法通过更好的 Prompt 或更强大的模型来补偿设计拙劣的工具集。浪费在无关返回字段上的上下文预算、由于模糊的工具描述而损失的准确性、由长序列链导致的可靠性下降 —— 这些都是架构属性,必须在架构层面予以解决。

与人类界面设计的类比具有启发性。几十年来我们了解到,最好的 API 不一定是对人类最好的界面 —— 交互模型、功能可见性(affordances)、错误恢复路径都需要针对实际用户的操作方式进行设计。AI Agent 是新的用户。你编写的工具就是界面。而该界面的质量,细化到每个字段名称和描述语句,决定了系统是在真实世界中运行,还是仅能用于演示。


正在构建 Agent 系统?ACI 才是核心所在。

References:Let's stay in touch and Follow me for more thoughts and updates