本文由 Anthropic 工程师 Ken Aizawa 所写:Writing effective tools for agents — with agents。其中介绍了一系列为 AI 代理(agents)构建高效工具的最佳实践和核心原则。为非确定性的 AI 代理设计工具与为传统的确定性软件系统编写函数或 API 有着根本性的不同,需要采取一种以代理为中心、由评估驱动的迭代开发方法。
关键细节
1. 构建和优化工具的流程
文章提出了一个与 AI 代理协作、以评估为驱动的迭代流程:
- 构建原型: 快速搭建工具原型,并利用
Claude Code等 AI 代理辅助编写。可以通过本地MCP(Model Context Protocol) 服务器或桌面扩展进行测试。 - 运行综合评估:
- 生成任务: 与 AI 代理协作,生成大量源于真实世界、具有足够复杂度的评估任务。强任务可能需要多次、甚至数十次工具调用。
- 运行评估: 通过直接调用 LLM API,在简单的代理循环中运行评估。建议让代理输出推理过程(
CoT)以更好地理解其行为。 - 分析结果: 代理是发现问题的合作伙伴。通过分析其推理过程、原始交互记录以及调用指标(如冗余调用、错误率),可以发现工具的不足之处。
- 与代理协作改进: 将评估结果和记录直接输入给
Claude Code,让它分析问题并重构优化工具代码和描述,从而形成一个持续改进的闭环。
2. 编写高效工具的核心原则
选择合适的工具:
- 质量优于数量。避免简单地将每个 API 端点都包装成一个工具。
- 应构建少数几个针对高影响力工作流程的、经过深思熟虑的工具。例如,用一个
schedule_event工具整合查找空闲时间和创建会议等多个步骤。
命名空间(Namespacing):
- 当工具数量增多时,使用共同的前缀(如
asana_projects_search)对相关工具进行分组,可以帮助代理在不同工具间做出正确选择,避免混淆。
- 当工具数量增多时,使用共同的前缀(如
返回有意义的上下文:
- 工具返回的数据应优先考虑上下文相关性,而非技术细节。使用自然语言名称(
name)代替晦涩的标识符(uuid)。 - 提供多种响应格式(如
concise和detailed),让代理可以根据需要选择信息的详细程度,从而控制上下文的消耗。
- 工具返回的数据应优先考虑上下文相关性,而非技术细节。使用自然语言名称(
优化令牌(Token)效率:
- 对于可能返回大量数据的工具,应实现分页、过滤或截断等功能,并设置合理的默认值。
- 当发生截断或错误时,返回的提示信息应具有指导性,能够引导代理采取更高效的策略(如缩小搜索范围)或纠正输入格式。
精心设计工具描述(Prompt-engineering):
- 这是提升工具性能最有效的方法之一。工具描述应像对新员工解释一样清晰、明确、无歧义。
- 将专业术语、查询格式等隐性知识显性化。对工具描述的微小改进可以带来性能的显著提升,例如
Claude Sonnet 3.5在SWE-bench评估中的表现就得益于此。
原文:为智能体编写有效的工具——并与智能体协作
发布于 2025 年 9 月 11 日
智能体的效用取决于我们赋予它们的工具。我们将分享如何编写高质量的工具和评估,以及您如何能利用 Claude 来为其自身优化工具,从而提升性能。
模型上下文协议 (MCP) 可以为 LLM 智能体提供多达数百种工具,用以解决现实世界的任务。但是,我们该如何使这些工具发挥最大效用呢?
在这篇文章中,我们描述了在多种智能体 AI 系统1 中提升性能的最有效技术。
我们首先将介绍您如何能够:
- 构建并测试您的工具原型
- 创建并运行针对智能体使用工具的全面评估
- 与像 Claude Code 这样的智能体协作,自动提升您工具的性能
最后,我们将总结在此过程中提炼出的、编写高质量工具的关键原则:
- 选择合适的工具进行实现(以及不实现哪些)
- 对工具进行命名空间划分,以定义清晰的功能边界
- 从工具向智能体返回有意义的上下文
- 优化工具响应以提高令牌效率
- 对工具描述和规范进行提示工程
构建评估使您能够系统地衡量工具的性能。您可以使用 Claude Code 针对此评估自动优化您的工具。
什么是工具?
在计算中,确定性系统在给定相同输入时总是产生相同的输出,而非确定性系统——如智能体——即使在相同的起始条件下也可能生成不同的响应。
当我们传统地编写软件时,我们在确定性系统之间建立了一种契约。例如,像 getWeather(“NYC”) 这样的函数调用,每次被调用时总会以完全相同的方式获取纽约市的天气。
工具是一种新型软件,它反映了确定性系统与非确定性智能体之间的一种契约。当用户询问“我今天需要带伞吗?”,智能体可能会调用天气工具,也可能根据常识回答,甚至可能先询问一个关于地点的澄清问题。偶尔,智能体可能会产生幻觉,甚至无法理解如何使用某个工具。
这意味着在为智能体编写软件时,我们需要从根本上重新思考我们的方法:我们不能像为其他开发者或系统编写函数和 API 那样来编写工具和 MCP 服务器,我们需要为智能体设计它们。
我们的目标是,通过使用工具追求各种成功的策略,来扩大智能体能够有效解决各种任务的范围。幸运的是,根据我们的经验,那些对智能体最“符合人体工程学”的工具,最终对人类来说也惊人地直观易懂。
如何编写工具
在本节中,我们将描述您如何能与智能体协作,共同编写和改进您提供给它们的工具。首先,快速构建一个工具原型并在本地进行测试。接下来,运行一次全面的评估以衡量后续的变更。通过与智能体协同工作,您可以重复评估和改进工具的过程,直到您的智能体在真实世界的任务上达到强大的性能。
构建原型
在没有亲自动手的情况下,可能很难预测哪些工具智能体会觉得符合人体工程学,哪些不会。首先,快速构建一个您的工具原型。如果您正在使用 Claude Code 来编写工具(可能是一次性完成),向 Claude 提供您的工具将依赖的任何软件库、API 或 SDK(可能包括 MCP SDK)的文档会很有帮助。LLM 友好的文档通常可以在官方文档网站的扁平化 llms.txt 文件中找到(这是我们的 API 文档)。
将您的工具包装在本地 MCP 服务器或桌面扩展 (DXT) 中,将允许您在 Claude Code 或 Claude 桌面应用中连接和测试您的工具。
要将您的本地 MCP 服务器连接到 Claude Code,请运行 claude mcp add <name> <command> [args...]。
要将您的本地 MCP 服务器或 DXT 连接到 Claude 桌面应用,请分别导航至 Settings > Developer 或 Settings > Extensions。
工具也可以直接传入 Anthropic API 调用中,以进行程序化测试。
亲自测试这些工具,找出任何不顺畅的地方。从您的用户那里收集反馈,以便围绕您期望工具所支持的用例和提示建立直觉。
运行评估
接下来,您需要通过运行评估来衡量 Claude 使用您工具的情况。首先,基于真实世界的用途,生成大量的评估任务。我们建议与一个智能体协作,帮助分析您的结果并确定如何改进您的工具。在我们的工具评估指南中查看这端到端的过程。
我们内部 Slack 工具的留出测试集性能
生成评估任务
有了您的早期原型,Claude Code 可以快速探索您的工具,并创建数十个提示和响应对。提示应该受到真实世界用途的启发,并基于现实的数据源和服务(例如,内部知识库和微服务)。我们建议您避免使用过于简单化或肤浅的“沙盒”环境,这些环境无法以足够的复杂度对您的工具进行压力测试。高强度的评估任务可能需要多次工具调用——甚至可能是几十次。
以下是一些高强度任务的示例:
- 安排下周与 Jane 召开会议,讨论我们最新的 Acme Corp 项目。附上我们上次项目规划会议的纪要,并预订一间会议室。
- 客户 ID 9182 报告称,他们的一次购买尝试被收取了三次费用。找出所有相关的日志条目,并确定是否有其他客户受到同一问题的影响。
- 客户 Sarah Chen 刚刚提交了取消请求。准备一份挽留方案。确定:(1) 他们离开的原因,(2) 哪种挽留方案最具吸引力,以及 (3) 在提出方案前我们应该注意的任何风险因素。
以下是一些较弱任务的示例:
- 安排下周与 [email protected] 召开会议。
- 在支付日志中搜索
purchase_complete和customer_id=9182。 - 查找客户 ID 45892 的取消请求。
每个评估提示都应配有一个可验证的响应或结果。您的验证器可以像基准真相和采样响应之间的精确字符串比较一样简单,也可以像请求 Claude 来评判响应一样高级。避免使用过于严格的验证器,以免其因为格式、标点符号或有效的替代表述等虚假差异而拒绝正确的响应。
对于每个提示-响应对,您可以选择性地指定您期望智能体在解决任务时调用的工具,以衡量智能体在评估期间是否成功领会了每个工具的用途。但是,由于可能有多种有效路径来正确解决任务,请尽量避免过度指定或过拟合策略。
运行评估
我们建议通过直接的 LLM API 调用来以程序化方式运行您的评估。使用简单的智能体循环(在交替的 LLM API 和工具调用外包裹 while 循环):每个评估任务一个循环。每个评估智能体应被给予一个任务提示和您的工具。
在您的评估智能体的系统提示中,我们建议指导智能体不仅输出结构化的响应块(用于验证),还要输出推理和反馈块。指导智能体在工具调用和响应块之前输出这些内容,可能会通过触发思维链 (CoT) 行为来提高 LLM 的有效智能。
如果您使用 Claude 运行评估,您可以开启交错思考(interleaved thinking)功能,以获得“开箱即用”的类似功能。这将帮助您探究智能体为何调用或不调用某些工具,并突显工具描述和规范中需要改进的具体方面。
除了顶层准确性之外,我们建议收集其他指标,如单个工具调用和任务的总运行时间、工具调用总数、总令牌消耗量以及工具错误。跟踪工具调用可以帮助揭示智能体追求的常见工作流程,并为工具整合提供一些机会。
我们内部 Asana 工具的留出测试集性能
分析结果
智能体是您有益的合作伙伴,能帮助您发现问题并就各种事项提供反馈,从相互矛盾的工具描述到低效的工具实现,再到令人困惑的工具模式。但是,请记住,智能体在反馈和响应中省略的内容通常比它们包含的内容更重要。LLM 并不总是言如所想。
观察您的智能体在哪些地方遇到了困难或感到困惑。通读您的评估智能体的推理和反馈(或 CoT)以找出不顺畅的地方。审查原始的对话记录(包括工具调用和工具响应),以捕捉智能体 CoT 中未明确描述的任何行为。进行字里行间的解读;请记住,您的评估智能体不一定知道正确的答案和策略。
分析您的工具调用指标。大量的冗余工具调用可能表明需要对分页或令牌限制参数进行适当调整;因参数无效而产生的大量工具错误可能表明工具需要更清晰的描述或更好的示例。当我们推出 Claude 的网页搜索工具时,我们发现 Claude 会不必要地在工具的 query 参数后附加 2025,这会使搜索结果产生偏差并降低性能(我们通过改进工具描述将 Claude 引导到了正确的方向上)。
与智能体协作
您甚至可以让智能体分析您的结果并为您改进工具。只需将您评估智能体的对话记录连接起来,然后粘贴到 Claude Code 中。Claude 是分析对话记录和一次性重构大量工具的专家——例如,确保在进行新更改时,工具实现和描述保持自洽。
事实上,这篇文章中的大部分建议都来自于使用 Claude Code 反复优化我们内部工具实现的过程。我们的评估是在我们内部工作区的基础上创建的,反映了我们内部工作流程的复杂性,包括真实的项目、文档和消息。
我们依赖留出的测试集来确保我们不会对“训练”评估过拟合。这些测试集显示,即使超出了我们通过“专家”工具实现所取得的成果——无论这些工具是我们的研究人员手动编写的还是由 Claude 自己生成的——我们仍然可以获得额外的性能提升。
在下一节中,我们将分享我们从这个过程中学到的一些经验。
编写有效工具的原则
在本节中,我们将我们的经验提炼为几个编写有效工具的指导原则。
为智能体选择正确的工具
更多的工具并不总是带来更好的结果。我们观察到的一个常见错误是,工具仅仅是包装了现有的软件功能或 API 端点——而不管这些工具是否适合智能体。这是因为智能体相对于传统软件具有不同的“可供性”——也就是说,它们感知使用这些工具可以采取的潜在行动的方式不同。
LLM 智能体的“上下文”有限(即,它们一次可以处理的信息量有限),而计算机内存既便宜又充足。考虑在地址簿中搜索联系人的任务。传统软件程序可以高效地存储和处理联系人列表,逐个检查,然后再移至下一个。
然而,如果一个 LLM 智能体使用一个返回所有联系人的工具,然后必须逐个令牌地阅读每个联系人,它就是在将有限的上下文空间浪费在不相关的信息上(想象一下,通过从上到下阅读每一页来在地址簿中搜索联系人——也就是通过蛮力搜索)。对智能体(和人类)来说,更好、更自然的方法是首先跳转到相关的页面(也许是按字母顺序查找)。
我们建议构建一些针对特定高影响力工作流程的、经过深思熟虑的工具,这些工具应与您的评估任务相匹配,并以此为基础进行扩展。在地址簿的例子中,您可能会选择实现一个 Contactss 或 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 {
A_DETAILED = "detailed",
A_CONCISE = "concise"
}
这是一个详细工具响应的示例(206 个令牌):

这是一个简洁工具响应的示例(72 个令牌):
Slack 话题和话题回复通过唯一的 thread_ts 来识别,这是获取话题回复所必需的。thread_ts 和其他 ID(channel_id、user_id)可以从 “detailed”(详细)的工具响应中检索到,以启用需要这些 ID 的进一步工具调用。“concise”(简洁)的工具响应只返回话题内容,不包括 ID。在这个例子中,使用 “concise” 工具响应,我们大约节省了 ⅓ 的令牌。
即使是您的工具响应结构——例如 XML、JSON 或 Markdown——也可能对评估性能产生影响:没有一刀切的解决方案。这是因为 LLM 是基于下一个令牌预测进行训练的,并且倾向于在与其训练数据相匹配的格式上表现得更好。最优的响应结构将因任务和智能体而大相径庭。我们鼓励您根据自己的评估选择最佳的响应结构。
为令牌效率优化工具响应
优化上下文的质量很重要。但是优化工具响应中返回给智能体的上下文数量也同样重要。
我们建议对任何可能占用大量上下文的工具响应,实现分页、范围选择、过滤和/或截断的某种组合,并设置合理的默认参数值。对于 Claude Code,我们默认将工具响应限制在 25,000 个令牌。我们预计智能体的有效上下文长度会随着时间增长,但对上下文高效工具的需求将持续存在。
如果您选择截断响应,请确保用有用的指令来引导智能体。您可以直接鼓励智能体追求更具令牌效率的策略,比如在知识检索任务中,进行多次小规模、有针对性的搜索,而不是进行一次广泛的搜索。同样,如果工具调用引发了错误(例如,在输入验证期间),您可以通过提示工程来设计您的错误响应,以清晰地传达具体的、可操作的改进建议,而不是返回不透明的错误代码或追溯信息。
这是一个截断工具响应的示例:

这是一个无益错误响应的示例:

这是一个有益错误响应的示例:
工具截断和错误响应可以引导智能体采取更具令牌效率的工具使用行为(使用过滤器或分页),或提供正确格式化工具输入的示例。
对您的工具描述进行提示工程
现在我们来看一种改进工具的最有效方法:对您的工具描述和规范进行提示工程。因为这些会被加载到您的智能体上下文中,它们可以共同引导智能体采取有效的工具调用行为。
在编写工具描述和规范时,可以想象一下您将如何向团队中的新员工描述您的工具。考虑一下您可能会隐式带来的上下文——专门的查询格式、小众术语的定义、底层资源之间的关系——并使其明确化。通过清晰描述(并用严格的数据模型强制执行)预期的输入和输出来避免歧义。特别是,输入参数应该被明确命名:与其使用一个名为 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 本身之外的系统。