跳到正文
原文
Anthropic:Engineering·· 2025-09-11精选AI 评分61

Writing effective tools for agents — with agents

Writing effective tools for agents — with agentsSep 11, 2025

文章要点
  • 1Anthropic官方工程指南总结为智能体编写高效工具的技巧,提炼自内部工具实践
  • 2指南提出先搭原型、再用智能体跑评估、让Claude Code自动分析记录优化工具的迭代路径
  • 3编写原则含只针对高影响工作流建工具、名称命名空间化、返回高信噪比上下文与token效率
  • 4官方留出测试集显示评估驱动的工具优化仍可带来超越专家手写实现的性能提升(官方口径)
决策要点

这篇指南的实质是指出工具是面向非确定性智能体的新型软件契约,不能沿用传统API开发思路,要靠评估驱动、智能体参与的迭代来打磨质量。

  • 影响:企业自建智能体应用时,工具数量与响应token直接影响token成本和任务准确率;把现有API简单包装成工具容易拖累表现,需围绕高影响工作流做整合;接入第三方MCP工具时,命名与描述质量可作为选型参考。
  • 参考:自建智能体应用的团队可考虑先基于真实业务任务搭小规模评估集,再据评估结果迭代工具描述;值得按功能命名空间盘点现有与第三方MCP工具,合并多步链式操作为单一工具;可参考官方默认响应上限估算token成本。
  • 依据:结论来自Anthropic官方工程博客,基于其内部Slack、Asana等工具的评估和留出测试集,属厂商自身方法论;SWE-bench Verified等结果为官方口径,暂无独立验证。
正文 · AI 翻译

模型上下文协议(MCP)可以让 LLM 智能体配备可能多达数百个工具来解决现实世界的任务。但我们如何让这些工具发挥最大效用呢?

在这篇文章中,我们将介绍我们在各类智能体 AI 系统中提升性能的最有效技术1。

我们首先介绍你可以如何:

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

最后,我们将分享在此过程中总结出的编写高质量工具的关键原则:

  • 选择要实现(以及不实现)的正确工具
  • 对工具进行命名空间划分,以定义清晰的功能边界
  • 从工具向智能体返回有意义的上下文
  • 优化工具响应以提高 token 效率
  • 对工具描述和规范进行提示工程
This is an image depicting how an engineer might use Claude Code to evaluate the efficacy of agentic tools.
构建评估让你能够系统地衡量工具的性能。你可以使用 Claude Code 针对该评估自动优化你的工具。

什么是工具?

在计算中,确定性系统在给定相同输入时每次都会产生相同的输出,而非确定性系统——比如智能体——即使起始条件相同,也可能生成不同的响应。

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

工具是一种新型软件,它体现的是确定性系统与非确定性智能体之间的契约。当用户问“我今天需要带伞吗?”时,智能体可能会调用天气工具、根据一般知识回答,甚至可能先提出一个关于位置的澄清性问题。有时,智能体可能会产生幻觉,甚至无法理解如何使用工具。

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

我们的目标是扩大智能体的有效作用范围,使其能够运用工具、采取多种成功策略来解决广泛的任务。幸运的是,根据我们的经验,对智能体而言最“符合人体工学”的工具,最终对人类来说也出奇地直观易懂。

如何编写工具

在本节中,我们将介绍如何与智能体协作,编写并改进你提供给它们的工具。首先快速搭建一个工具原型并在本地进行测试。接着,运行一次全面评估来衡量后续的改动。与智能体协同工作,你可以反复进行评估和改进工具的过程,直到你的智能体在现实世界任务中取得出色表现。

构建原型

如果不亲自上手体验,很难预测哪些工具会让智能体觉得好用、哪些不好用。不妨先为你的工具快速搭建一个原型。如果你正在使用 Claude Code 来编写工具(甚至可能一次性完成),最好向 Claude 提供你的工具所依赖的任何软件库、API 或 SDK 的文档(可能包括 MCP SDK)。对 LLM 友好的文档通常可以在官方文档站点上以纯文本 llms.txt 文件的形式找到(这是我们的 API)。

将你的工具封装在本地 MCP 服务器或 Desktop 扩展(DXT)中,就能在 Claude Code 或 Claude Desktop 应用中连接并测试你的工具。

要将本地 MCP 服务器连接到 Claude Code,请运行 claude mcp add <name> <command> [args...]。

要将本地 MCP 服务器或 DXT 连接到 Claude Desktop 应用,请分别前往 Settings > Developer 或 Settings > Extensions。

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

亲自测试这些工具,找出不够完善之处。收集用户的反馈,以便对你期望工具支持的用例和提示建立直觉。

运行评估

接下来,你需要通过运行评估来衡量 Claude 使用你的工具的效果。首先生成大量基于真实使用场景的评估任务。我们建议与一个智能体协作,帮助分析结果并确定如何改进你的工具。完整流程可参见我们的 工具评估手册。

This graph measures the test set accuracy of human-written vs. Claude-optimized Slack MCP servers.
我们内部 Slack 工具在留出测试集上的表现

生成评估任务

借助早期原型,Claude Code 可以快速探索你的工具并创建数十组提示与响应对。提示应源自真实使用场景,并基于真实的数据源和服务(例如内部知识库和微服务)。我们建议避免过于简单或浅显的“沙箱”环境,这类环境无法以足够的复杂度对你的工具进行压力测试。高质量的评估任务可能需要多次工具调用——甚至多达数十次。

以下是一些高质量任务的示例:

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

以下则是一些较弱的任务示例:

  • 下周与 jane@acme.corp 安排一次会议。
  • 在支付日志中搜索 purchase_complete 和 customer_id=9182。
  • 查找客户 ID 45892 的取消请求。

每条评估提示都应配有一个可验证的响应或结果。验证器可以简单到在标准答案与采样响应之间进行精确字符串比较,也可以复杂到让 Claude 来评判响应。避免使用过于严格的验证器,以免因格式、标点或合理的其他表述等无关差异而拒绝正确的响应。

对于每个提示-响应对,您还可以选择指定您期望智能体在解决任务时调用的工具,以衡量智能体在评估过程中是否成功掌握了每个工具的用途。不过,由于正确解决任务可能存在多条有效路径,请尽量避免过度指定或过度拟合特定策略。

运行评估

我们建议通过直接调用 LLM API 以编程方式运行评估。使用简单的智能体循环(while 循环,交替包装 LLM API 调用和工具调用):每个评估任务对应一个循环。每个评估智能体应被赋予单个任务提示和您的工具。

在评估智能体的系统提示中,我们建议指示智能体不仅输出结构化响应块(用于验证),还要输出推理和反馈块。指示智能体在工具调用和响应块之前输出这些内容,可以通过触发思维链(CoT)行为来提高 LLM 的有效智能。

如果您使用 Claude 运行评估,可以直接启用交错思考来获得类似的开箱即用功能。这将帮助您探究智能体为何调用或不调用某些工具,并突出工具描述和规范中有待改进的具体方面。

除了总体准确率之外,我们建议收集其他指标,例如单个工具调用和任务的总运行时间、工具调用总次数、token 总消耗量以及工具错误。跟踪工具调用有助于揭示智能体追求的常见工作流,并为整合工具提供一些机会。

This graph measures the test set accuracy of human-written vs. Claude-optimized Asana MCP servers.
我们内部 Asana 工具在留出测试集上的表现

分析结果
智能体是您发现问题和提供反馈的有用伙伴,涵盖从相互矛盾的工具描述到低效的工具实现以及令人困惑的工具架构等方方面面。不过,请记住,智能体在反馈和响应中遗漏的内容往往比它们包含的内容更重要。LLM 并不总是如实表达自己的想法。

观察您的智能体在哪里陷入困境或感到困惑。通读评估智能体的推理和反馈(或 CoT),以找出不完善之处。查看原始对话记录(包括工具调用和工具响应),以捕捉智能体 CoT 中未明确描述的任何行为。要领会言外之意;请记住,您的评估智能体不一定知道正确答案和策略。

分析您的工具调用指标。大量冗余的工具调用可能表明需要适当调整分页或 token 限制参数;大量因无效参数导致的工具错误可能表明工具需要更清晰的描述或更好的示例。当我们推出 Claude 的网页搜索工具时,我们发现 Claude 会不必要地将 2025 附加到该工具的 query 参数上,导致搜索结果出现偏差并降低性能(我们通过改进工具描述将 Claude 引向了正确的方向)。

与智能体协作

您甚至可以让智能体为您分析结果并改进工具。只需将评估智能体的对话记录拼接在一起,然后粘贴到 Claude Code 中。Claude 是分析对话记录和一次性重构大量工具的专家——例如,确保在做出新更改时,工具实现和描述保持自洽。

事实上,本文中的大部分建议都来自我们使用 Claude Code 反复优化内部工具实现的过程。我们的评估是在内部工作区的基础上构建的,反映了内部工作流程的复杂性,包括真实的项目、文档和消息。

我们依靠留出测试集来确保不会对“训练”评估过拟合。这些测试集表明,我们能够获得超越“专家”工具实现所达水平的额外性能提升——无论这些工具是由我们的研究人员手动编写的,还是由 Claude 自身生成的。

在下一节中,我们将分享从这一过程中学到的一些经验。

编写高效工具的原则

在本节中,我们将学到的经验提炼为编写高效工具的几条指导原则。

为智能体选择合适的工具

更多的工具并不总会带来更好的结果。我们观察到的一个常见错误是,创建的工具仅仅是对现有软件功能或 API 端点的封装,而不管这些工具是否适合智能体。这是因为智能体与传统软件具有不同的“可供性”——也就是说,它们感知通过这些工具可以采取哪些潜在行动的方式有所不同

LLM 智能体的“上下文”是有限的(也就是说,它们一次能处理的信息量有限),而计算机内存则廉价且充裕。以在通讯录中搜索联系人为例。传统软件程序可以高效地逐个存储和处理联系人列表,在检查完每一个联系人后再继续处理下一个。

然而,如果 LLM 智能体使用一个返回所有联系人的工具,然后不得不逐个 token 地通读每一条记录,那就是在把有限的上下文空间浪费在无关信息上(想象一下,你通过从上到下阅读每一页来在通讯录中查找联系人——也就是暴力搜索)。更好、更自然的方法(无论对智能体还是人类而言)是先跳转到相关页面(比如按字母顺序查找)。

我们建议先针对特定的高影响工作流精心构建少量工具,使其与你的评估任务相匹配,然后再在此基础上逐步扩展。在通讯录的例子中,你可能会选择实现 search_contacts 或 message_contact 工具,而不是 list_contacts 工具。

工具可以整合功能,在底层处理潜在的 多个 离散操作(或 API 调用)。例如,工具可以在工具响应中补充相关元数据,或者在单次工具调用中处理经常串联的多步骤任务。

以下是一些示例:

  • 与其实现 list_users、list_events 和 create_event 工具,不如考虑实现一个 schedule_event 工具,用于查找可用时间并安排日程。
  • 与其实现 read_logs 工具,不如考虑实现一个 search_logs 工具,仅返回相关的日志行及一些上下文。
  • 与其实现 get_customer_by_id、list_transactions 和 list_notes 工具,不如实现一个 get_customer_context 工具,一次性汇总客户的全部近期 & 相关信息。

确保你构建的每个工具都有清晰、明确的目的。工具应当使智能体能够以与人类(在拥有相同底层资源的情况下)大致相同的方式来细分和解决任务,同时减少原本会被中间输出消耗的上下文。

过多的工具或功能重叠的工具也会分散智能体追求高效策略的注意力。审慎、有选择地规划你要构建(或不构建)的工具,确实能带来丰厚的回报。

为工具设置命名空间

你的 AI 智能体可能会访问数十个 MCP 服务器和数百种不同的工具——其中包括其他开发者开发的工具。当工具在功能上重叠或用途模糊时,智能体可能会搞不清该使用哪些工具。

命名空间化(将相关工具归入共同的前缀之下)有助于在大量工具之间划清边界;有些 MCP 客户端默认就会这样做。例如,按服务(如 asana_search、jira_search)和按资源(如 asana_projects_search、asana_users_search)为工具命名空间化,可以帮助智能体在合适的时机选择合适的工具。

我们发现,在前缀式和后缀式命名空间之间做出选择,会对我们的工具使用评估产生不可忽视的影响。这种影响因 LLM 而异,我们建议你根据自己的评估来选择命名方案。

智能体可能会调用错误的工具、以错误的参数调用正确的工具、调用过少的工具,或者错误地处理工具响应。通过有选择地实现那些名称能够体现任务自然划分的工具,你可以同时减少加载到智能体上下文中的工具和工具描述数量,并把智能体计算从上下文中卸载回工具调用本身。这降低了智能体整体出错的风险。

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

同样地,工具实现应注意只向智能体返回高信号的信息。它们应优先考虑上下文相关性而非灵活性,避免使用低层次的技术标识符(例如:uuid、256px_image_url、mime_type)。像 name、image_url 和 file_type 这样的字段更有可能直接影响智能体的下游操作和响应。

智能体在处理自然语言名称、术语或标识符时,也往往比处理晦涩难懂的标识符要顺利得多。我们发现,仅仅将任意的字母数字 UUID 解析为更具语义且易于理解的语言(甚至是 0 起始索引的 ID 方案),就能通过减少幻觉显著提高 Claude 在检索任务中的精确度。

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

你可以添加更多格式以获得更大的灵活性,类似于 GraphQL,你可以在其中精确选择想要接收的信息片段。以下是一个用于控制工具响应详细程度的 ResponseFormat 枚举示例:

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

以下是一个详细工具响应的示例(206 个 token):

This code snippet depicts an example of a detailed tool response.

以下是一个简洁工具响应的示例(72 个 token):

This code snippet depicts a concise tool response.
Slack 讨论串和讨论串回复由唯一的 thread_ts 标识,获取讨论串回复时需要用到它们。thread_ts 和其他 ID(channel_id、user_id)可以从 “detailed” 工具响应中获取,以支持后续需要这些 ID 的工具调用。“concise” 工具响应只返回讨论串内容,不包含 ID。在本例中,使用 “concise” 工具响应只消耗了约 ⅓ 的 token。

即使是工具响应的结构——例如 XML、JSON 或 Markdown——也会对评估性能产生影响:没有放之四海而皆准的解决方案。这是因为 LLM 基于下一个 token 预测进行训练,在与其训练数据相匹配的格式上往往表现更好。最优的响应结构会因任务和 agent 的不同而有很大差异。我们鼓励您根据自己的评估来选择最佳的响应结构。

针对 token 效率优化工具响应

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

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

如果您选择截断响应,请务必通过有用的指令来引导 agent。您可以直接鼓励 agent 采用更节省 token 的策略,例如在知识检索任务中进行多次小型且有针对性的搜索,而不是单次宽泛的搜索。同样,如果工具调用引发错误(例如在输入验证期间),您可以通过提示工程让错误响应清楚地传达具体且可操作的改进建议,而不是不透明的错误代码或堆栈跟踪。

以下是一个截断工具响应的示例:

This image depicts an example of a truncated tool response.

以下是一个无帮助的错误响应示例:

This image depicts an example of an unhelpful tool response.

以下是一个有帮助的错误响应示例:

This image depicts an example of a helpful error response.
工具截断和错误响应可以引导智能体采取更节省 token 的工具使用行为(例如使用过滤器或分页),或者提供格式正确的工具输入示例。

对你的工具描述进行提示词工程

现在我们来谈谈改进工具最有效的方法之一:对你的工具描述和规范进行提示词工程。由于这些内容会被加载到智能体的上下文中,它们可以共同引导智能体形成有效的工具调用行为。

在编写工具描述和规范时,想一想你会如何向团队中的新员工描述你的工具。考虑一下你可能会隐式带入的背景知识——专门的查询格式、小众术语的定义、底层资源之间的关系——并将它们明确写出来。通过清晰地描述(并用严格的数据模型加以约束)预期的输入和输出,避免歧义。尤其是,输入参数的命名应当毫无歧义:与其使用名为 user 的参数,不如尝试使用名为 user_id 的参数。

借助评估,你可以更有把握地衡量提示词工程带来的影响。即使是对工具描述的细微打磨,也可能带来显著的提升。在我们对工具描述进行了精确的改进之后,Claude Sonnet 3.5 在 SWE-bench Verified 评估中取得了最先进的性能,大幅降低了错误率并提高了任务完成率。

你可以在我们的开发者指南中找到其他关于工具定义的最佳实践。如果你正在为 Claude 构建工具,我们还建议阅读关于工具如何被动态加载到 Claude 的系统提示词中的内容。最后,如果你正在为 MCP 服务器编写工具,工具注解有助于说明哪些工具需要开放世界的访问权限,或者会进行破坏性更改。

展望未来

要为智能体构建高效的工具,我们需要将软件开发实践从可预测的确定性模式转向非确定性模式。

通过本文所描述的迭代式、评估驱动的过程,我们发现了工具取得成功的一致规律:高效的工具经过深思熟虑且定义清晰,审慎地使用智能体上下文,可以在多样化的工作流中组合使用,并能让智能体直观地解决真实世界的任务。

展望未来,我们预计智能体与世界交互的具体机制将不断演进——从 MCP 协议的更新到底层 LLM 本身的升级。通过系统化、评估驱动的方法来改进智能体工具,我们可以确保随着智能体能力的不断提升,它们所使用的工具也将同步演进。

致谢

本文由 Ken Aizawa 撰写,并得到了以下同事的宝贵贡献:研究团队(Barry Zhang、Zachary Witten、Daniel Jiang、Sami Al-Sheikh、Matt Bell、Maggie Vo)、MCP 团队(Theodora Chu、John Welsh、David Soria Parra、Adam Jones)、产品工程团队(Santiago Seira)、市场团队(Molly Vorwerck)、设计团队(Drew Roper)以及应用 AI 团队(Christian Ryan、Alexander Bricken)。

1指对底层 LLM 本身进行训练之外的改进。

来源:Anthropic:Engineering · anthropic.com