原文: English original · Anthropic/OpenAI 官方

和 agents 一起,为 agents 编写有效工具

发布于 2025 年 9 月 11 日

Agents 的能力,很大程度上取决于我们给它们配备的工具。本文分享如何编写高质量工具与评测,以及如何用 Claude 优化它自己的工具,从而提升性能。

Model Context Protocol (MCP) 可以让 LLM agents 获得数百个潜在工具,用来解决真实世界任务。但我们该如何让这些工具尽可能有效?

本文会介绍我们在多种 agentic AI 系统1中提升性能时最有效的一些方法。

我们会先说明你可以如何:

  • 构建并测试工具原型
  • 为工具创建并运行面向 agents 的全面评测
  • 与 Claude Code 这样的 agents 协作,自动提升工具性能

最后,我们会总结一路上识别出的高质量工具编写原则:

  • 选择应该实现,以及不应该实现的正确工具
  • 通过 namespacing 为功能定义清晰边界
  • 从工具向 agents 返回有意义的上下文
  • 优化工具响应,提高 token 效率
  • 对工具描述和 spec 做 prompt engineering

构建评测后,你可以系统性衡量工具性能。也可以使用 Claude Code,根据这套评测自动优化工具。

什么是工具?

在计算领域,确定性系统在输入相同的情况下,每次都会产生相同输出;而非确定性系统,比如 agents,即使起始条件相同,也可能生成不同响应。

传统软件开发,本质上是在确定性系统之间建立契约。比如 getWeather(“NYC”) 这样的函数调用,每次被调用时,都会以完全相同的方式获取纽约市天气。

工具是一种新的软件形态,体现的是确定性系统与非确定性 agents 之间的契约。当用户问“我今天要带伞吗?”时,agent 可能会调用天气工具,可能根据通用知识回答,也可能先追问用户所在位置。偶尔,agent 还可能产生幻觉,甚至没有理解该如何使用某个工具。

这意味着,为 agents 编写软件时,我们需要从根本上重新思考方法:不能像为其他开发者或系统编写函数和 API 那样编写工具和 MCP servers,而要为 agents 设计它们。

我们的目标,是扩大 agents 能够有效解决各类任务的范围:通过工具,让 agents 可以采用多种成功策略。好消息是,根据我们的经验,对 agents 最“顺手”的工具,往往也出乎意料地容易被人类理解。

如何编写工具

本节介绍如何与 agents 协作,编写并改进你提供给它们的工具。先快速搭建一个工具原型,并在本地测试。接着运行全面评测,衡量后续变更的效果。与 agents 一起工作时,你可以反复评测和改进工具,直到 agents 在真实世界任务上达到强劲表现。

构建原型

如果不亲自动手,很难提前判断哪些工具会让 agents 用起来顺手,哪些不会。你可以先快速搭建一个工具原型。如果你用 Claude Code 编写工具,甚至希望 one-shot 完成,最好给 Claude 提供这些工具依赖的软件库、API 或 SDK 文档,其中也可能包括 MCP SDK

适合 LLM 阅读的文档通常可以在官方文档站点的扁平 llms.txt 文件中找到,比如我们的 API 文档

把工具封装进 local MCP serverDesktop extension (DXT),就可以在 Claude Code 或 Claude Desktop app 中连接并测试这些工具。

要把 local MCP server 连接到 Claude Code,运行 claude mcp add <name> <command> [args...]

要把 local MCP server 或 DXT 连接到 Claude Desktop app,分别进入 Settings > DeveloperSettings > Extensions

也可以把工具直接传入 Anthropic API 调用,用于程序化测试。

你应该亲自测试工具,找出粗糙之处。也要收集用户反馈,建立对预期用例和 prompts 的直觉,理解这些工具应该支持什么。

运行评测

接下来,你需要运行评测,衡量 Claude 使用这些工具的效果。可以先生成大量评测任务,让这些任务扎根于真实用途。我们建议与一个 agent 协作,帮助分析结果并判断如何改进工具。你可以在我们的 tool evaluation cookbook 中看到这一流程的端到端示例。

我们内部 Slack 工具在留出测试集上的表现

生成评测任务

有了早期原型后,Claude Code 可以快速探索你的工具,并创建数十组 prompt 与响应配对。Prompts 应该受到真实世界用途启发,并基于真实的数据源和服务,例如内部知识库和微服务。我们建议避免过于简单或表层化的“沙盒”环境,因为它们无法用足够复杂的情形对工具进行压力测试。强评测任务可能需要多次工具调用,甚至可能需要几十次。

下面是一些强任务示例:

  • 安排下周与 Jane 开会,讨论我们最新的 Acme Corp 项目。附上我们上次项目规划会议的笔记,并预订一间会议室。
  • 客户 ID 9182 反馈说,一次购买尝试被扣了三次款。找出所有相关日志条目,并判断是否还有其他客户受到同一问题影响。
  • 客户 Sarah Chen 刚刚提交了取消请求。准备一份挽留方案。判断:(1) 她为什么要离开,(2) 哪种挽留方案最有吸引力,以及 (3) 在提出方案前我们应该注意哪些风险因素。

下面则是一些较弱的任务:

  • 安排下周与 jane@acme.corp 开会。
  • 在支付日志里搜索 purchase_completecustomer_id=9182
  • 按 Customer ID 45892 查找取消请求。

每个评测 prompt 都应该配有可验证的响应或结果。验证器可以很简单,比如把标准答案与采样响应做精确字符串比较;也可以更高级,比如请 Claude 判断响应。应避免过于严格的验证器,以免因为格式、标点或其他有效表述差异等偶然因素,拒绝本来正确的响应。

对每组 prompt-响应配对,你也可以选择指定期望 agent 在解决任务时调用哪些工具,以衡量 agents 在评测中是否成功理解了每个工具的用途。不过,因为正确解决任务可能存在多条有效路径,应该尽量避免对策略做过度指定或过拟合。

运行评测

我们建议用直接 LLM API 调用以程序化方式运行评测。使用简单的 agentic loops,也就是用 while 循环包装交替进行的 LLM API 调用和工具调用:每个评测任务对应一个循环。每个评测 agent 都应该获得一个单独的任务 prompt 和你的工具。

在评测 agents 的 system prompts 中,我们建议指示 agents 不仅输出结构化响应块用于验证,也输出推理块和反馈块。要求 agents 在工具调用和响应块之前输出这些内容,可能会触发 chain-of-thought (CoT) 行为,从而提高 LLMs 的有效智能。

如果你使用 Claude 运行评测,可以开启 interleaved thinking,用“开箱即用”的方式获得类似功能。这会帮助你探查 agents 为什么调用或不调用某些工具,并突出工具描述和 spec 中可以改进的具体区域。

除了顶层准确率,我们还建议收集其他指标,例如单次工具调用和任务的总运行时间、工具调用总数、token 总消耗,以及工具错误。跟踪工具调用有助于揭示 agents 采用的常见 workflows,也可能暴露出工具可以合并的机会。

我们内部 Asana 工具在留出测试集上的表现

分析结果

Agents 是很有帮助的合作伙伴,可以帮你发现问题,并对从相互矛盾的工具描述,到低效工具实现、令人困惑的工具模式等各种问题给出反馈。不过要记住,agents 在反馈和响应中省略了什么,往往比它们写了什么更重要。LLMs 并不总是说出它们真正所想

观察 agents 在哪里卡住或困惑。通读评测 agents 的推理和反馈,或 CoT,识别粗糙之处。审阅原始 transcripts,包括工具调用和工具响应,捕捉 agent 的 CoT 中没有明确描述的行为。要读出言外之意;记住,你的评测 agents 未必知道正确答案和正确策略。

分析工具调用指标。大量冗余工具调用可能说明需要调整分页或 token 限制参数;大量无效参数导致的工具错误,可能说明工具需要更清晰的描述或更好的示例。

当我们发布 Claude 的 web search tool 时,我们发现 Claude 会不必要地把 2025 追加到工具的 query 参数里,导致搜索结果偏移并降低性能。我们通过改进工具描述,把 Claude 引向了正确方向。

与 agents 协作

你甚至可以让 agents 为你分析结果并改进工具。只需把评测 agents 的 transcripts 拼接起来,粘贴进 Claude Code。Claude 很擅长分析 transcripts,也擅长一次性重构大量工具,例如在做出新变更时,确保工具实现和描述仍然自洽。

事实上,本文大多数建议都来自我们使用 Claude Code 反复优化内部工具实现的过程。我们的评测构建在内部 workspace 之上,复刻了内部 workflows 的复杂性,包括真实项目、文档和消息。

我们依靠留出测试集,确保自己没有过拟合“训练”评测。这些测试集表明,即便已经达到“专家”级工具实现,我们仍能提取额外性能提升,无论这些工具是研究人员手写的,还是 Claude 自己生成的。

下一节会分享我们从这一过程中学到的一些东西。

编写有效工具的原则

本节会把我们的经验提炼为几个编写有效工具的指导原则。

为 agents 选择正确的工具

更多工具并不总是带来更好结果。我们观察到一个常见错误:工具只是简单包装现有软件功能或 API endpoints,而不管这些工具是否适合 agents。这是因为 agents 与传统软件有不同的“affordances”:也就是说,它们感知这些工具所支持潜在行动的方式不同。

LLM agents 的“context”有限,也就是一次能处理的信息量有限,而计算机内存便宜且充足。考虑在通讯录中查找联系人的任务。传统软件程序可以高效地逐个存储和处理联系人列表,检查完一个再继续下一个。

但如果一个 LLM agent 使用某个工具返回所有联系人,然后不得不逐个 token 阅读,它就在把有限的 context 空间浪费在无关信息上。想象一下,你通过从头到尾阅读通讯录每一页来查找联系人,也就是用暴力搜索。对 agents 和人类来说,更好也更自然的方法,是先跳到相关页面,比如按字母顺序找到对应位置。

我们建议构建少量经过深思熟虑、面向特定高影响 workflows 的工具,让它们匹配你的评测任务,再从这里逐步扩展。在通讯录案例中,你可能会选择实现 search_contactsmessage_contact 工具,而不是 list_contacts 工具。

工具可以整合功能,在幕后处理多个离散操作,或多次 API 调用。例如,工具可以用相关元数据丰富工具响应,也可以把经常串联出现的多步骤任务放进一次工具调用里处理。

下面是一些示例:

  • 不要实现 list_userslist_eventscreate_event 工具,可以考虑实现一个 schedule_event 工具,由它查找可用时间并安排事件。
  • 不要实现 read_logs 工具,可以考虑实现一个 search_logs 工具,只返回相关日志行和一些周边上下文。
  • 不要实现 get_customer_by_idlist_transactionslist_notes 工具,可以实现一个 get_customer_context 工具,一次性汇总该客户近期且相关的全部信息。

确保你构建的每个工具都有清晰、独立的目的。工具应该让 agents 能够像人类在访问同样底层资源时那样拆分并解决任务,同时减少原本会被中间输出消耗的 context。

工具太多或工具之间重叠,也会分散 agents 注意力,让它们无法采用高效策略。谨慎、有选择地规划你构建,以及不构建的工具,确实能带来回报。

为工具设置 namespace

你的 AI agents 可能会获得几十个 MCP servers 和数百个不同工具的访问权限,其中还包括其他开发者提供的工具。当工具功能重叠或用途模糊时,agents 可能会困惑,不知道该用哪个。

Namespacing,也就是把相关工具归在共同前缀下,可以帮助划清大量工具之间的边界;MCP clients 有时会默认这么做。例如,按服务为工具设置 namespace,如 asana_searchjira_search,以及按资源设置 namespace,如 asana_projects_searchasana_users_search,可以帮助 agents 在正确时间选择正确工具。

我们发现,在基于前缀和基于后缀的 namespacing 之间做选择,会对我们的工具使用评测产生不可忽视的影响。效果会因 LLM 而异,我们鼓励你根据自己的评测选择命名方案。

Agents 可能调用错误工具,可能用错误参数调用正确工具,可能调用工具太少,也可能错误处理工具响应。通过有选择地实现那些名称反映任务自然拆分方式的工具,你既能减少加载进 agent context 的工具数量和工具描述,也能把 agentic 计算从 agent context 转移回工具调用本身。这会降低 agent 整体犯错风险。

从工具返回有意义的上下文

同理,工具实现应该注意只向 agents 返回高信号信息。它们应该优先考虑上下文相关性,而不是灵活性,并避开低层技术标识符,例如 uuid256px_image_urlmime_typenameimage_urlfile_type 这样的字段,更有可能直接影响 agents 后续的行动和响应。

与隐晦标识符相比,agents 也更擅长处理自然语言名称、术语或标识符。我们发现,只是把任意字母数字 UUID 解析成语义更清楚、可解释性更强的语言,甚至解析成从 0 开始的 ID 方案,就能通过减少幻觉,显著提高 Claude 在检索任务中的精度。

在某些情况下,agents 可能需要灵活地同时处理自然语言和技术标识符输出,哪怕只是为了触发下游工具调用,例如 search_user(name=’jane’)send_message(id=12345)。你可以在工具中暴露一个简单的 response_format enum 参数,同时支持这两种方式,让 agent 控制工具返回 “concise” 还是 “detailed” 响应,见下图。

你也可以添加更多格式来获得更大灵活性,类似 GraphQL 那样精确选择想接收哪些信息。下面是一个用于控制工具响应详略程度的 ResponseFormat enum 示例:

enum ResponseFormat {
   DETAILED = "detailed",
   CONCISE = "concise"
}

下面是详细工具响应示例(206 tokens):

下面是简洁工具响应示例(72 tokens):

Slack threads 和 thread replies 由唯一的 thread_ts 标识,获取 thread replies 时必须使用它。thread_ts 和其他 IDs(channel_iduser_id)可以从 “detailed” 工具响应中取回,以支持需要这些信息的后续工具调用。“concise” 工具响应只返回 thread 内容,并排除 IDs。在这个例子中,使用 “concise” 工具响应时,我们只用了约三分之一 tokens。

即便是工具响应结构,比如 XML、JSON 或 Markdown,也可能影响评测表现:这里不存在放之四海而皆准的方案。这是因为 LLMs 基于 next-token prediction 训练,往往在匹配训练数据的格式上表现更好。最优响应结构会随任务和 agent 的不同而有很大差异。我们鼓励你根据自己的评测选择最佳响应结构。

优化工具响应,提高 token 效率

优化上下文质量很重要。但优化工具响应中返回给 agents 的上下文数量,同样重要。

我们建议对任何可能占用大量 context 的工具响应,实现分页、范围选择、过滤和/或截断的某种组合,并设置合理的默认参数值。对于 Claude Code,我们默认把工具响应限制在 25,000 tokens。我们预计 agents 的有效 context length 会随着时间增长,但对 context 高效工具的需求仍会存在。

如果你选择截断响应,一定要用有帮助的指令引导 agents。你可以直接鼓励 agents 采用更节省 tokens 的策略,例如在知识检索任务中进行多次小而有针对性的搜索,而不是一次宽泛搜索。同样,如果工具调用抛出错误,例如输入验证期间,你可以对错误响应做 prompt engineering,让它们清楚传达具体且可执行的改进建议,而不是返回不透明错误码或 tracebacks。

下面是截断工具响应的示例:

下面是无帮助错误响应的示例:

下面是有帮助错误响应的示例:

工具截断和错误响应可以把 agents 引向更节省 tokens 的 tool-use 行为,例如使用过滤器或分页,也可以给出正确格式化工具输入的示例。

对工具描述做 prompt engineering

现在我们来到改进工具最有效的方法之一:对工具描述和 spec 做 prompt engineering。因为这些内容会加载进 agents 的 context,它们可以共同引导 agents 采用有效的工具调用行为。

编写工具描述和 spec 时,可以想象你会如何向团队新成员介绍这个工具。考虑你可能会隐含带入的上下文:专门的查询格式、小众术语定义、底层资源之间的关系,并把它们明确写出来。通过清楚描述预期输入和输出,并用严格数据模型强制执行,来避免歧义。

尤其是,输入参数应该命名得没有歧义:与其命名为 user,不如命名为 user_id

有了评测,你就可以更有信心地衡量 prompt engineering 的影响。即便是对工具描述的小幅打磨,也可能带来显著改进。Claude Sonnet 3.5 在我们对工具描述做出精准打磨后,在 SWE-bench Verified 评测上达到 state-of-the-art 表现,大幅降低错误率并提高任务完成度。

你可以在我们的 Developer Guide 中找到工具定义的其他最佳实践。如果你正在为 Claude 构建工具,我们也建议阅读工具如何被动态加载进 Claude 的 system prompt。最后,如果你在为 MCP server 编写工具,tool annotations 有助于披露哪些工具需要 open-world access,或会做出破坏性变更。

展望

要为 agents 构建有效工具,我们需要把软件开发实践从可预测、确定性的模式,重新转向非确定性的模式。

通过本文描述的迭代式、评测驱动流程,我们识别出工具成功背后的一些稳定模式:有效工具会被有意且清晰地定义,会审慎使用 agent context,能够以多样 workflows 组合起来,并让 agents 能够直观地解决真实世界任务。

未来,我们预计 agents 与世界交互的具体机制会继续演进,从 MCP protocol 更新,到底层 LLMs 自身升级都会如此。只要采用系统化、评测驱动的方法来改进面向 agents 的工具,我们就能确保随着 agents 能力增强,它们使用的工具也会同步演进。

致谢

本文由 Ken Aizawa 撰写,并得到 Research(Barry Zhang、Zachary Witten、Daniel Jiang、Sami Al-Sheikh、Matt Bell、Maggie Vo)、MCP(Theodora Chu、John Welsh、David Soria Parra、Adam Jones)、Product Engineering(Santiago Seira)、Marketing(Molly Vorwerck)、Design(Drew Roper)和 Applied AI(Christian Ryan、Alexander Bricken)同事的宝贵贡献。


  1. 不包括训练底层 LLMs 本身。 ↩︎