为 AI 智能体打造高效工具——让 AI 智能体来帮忙

来自 Anthropic 工程团队

模型上下文协议(Model Context Protocol, MCP)可以让 AI 智能体(AI Agent)拥有数百种工具,去解决真实世界里的各种任务。但问题是,我们如何让这些工具发挥出最大的效用呢?

在这篇文章里,我们将分享一些我们总结出来的,能有效提升各种 AI 智能体系统性能的独家秘诀 1。

首先,我们会一步步教你如何:

  • 为你的工具构建并测试原型

  • 为你的工具创建并运行一套全面的智能体评估体系

  • 与像 Claude Code 这样的智能体协作,自动提升你的工具性能

最后,我们会总结一路走来发现的几条核心原则,帮你写出高质量的工具:

  • 选择哪些工具该做(哪些不该做)

  • 使用命名空间为工具的功能划分清晰的界限

  • 让工具为智能体返回有意义的上下文信息

  • 优化工具的响应,以节省 token

  • 通过提示词工程优化工具的描述和规格

这张图片描绘了一位工程师如何使用 Claude Code 来评估智能体工具的效能。

建立一套评估体系,你就能系统地衡量工具的性能。你可以利用 Claude Code 自动针对这套评估体系来优化你的工具。

什么是“工具”?

在计算机科学里,“确定性系统”对于相同的输入,总会产生相同的输出。而像 AI 智能体这样的非确定性系统,即使初始条件完全一样,也可能生成五花八门的响应。

我们传统上编写软件,其实是在确定性系统之间建立一种“契约”。比如,一个函数调用 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 桌面应用,分别导航到 设置 > 开发者设置 > 扩展程序

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

亲自测试这些工具,找出那些不顺手的地方。同时,收集用户的反馈,让你对工具的预期使用场景和提示词有个直观的感受。

运行评估

接下来,你需要通过运行评估来衡量 Claude 使用你工具的效果如何。首先,要生成大量基于真实世界使用场景的评估任务。我们建议你与智能体协作,让它帮助分析结果,并判断如何改进你的工具。你可以在我们的 工具评估指南 中看到这个端到端的过程。

这张图表衡量了人工编写的 Slack MCP 服务器与 Claude 优化后的版本在测试集上的准确率。

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

生成评估任务

有了早期的原型,Claude Code 就能快速探索你的工具,并创建出几十个提示词和响应的配对。这些提示词应该源于真实世界的使用场景,并基于现实的数据源和服务(比如,内部知识库和微服务)。我们建议你避免使用那些过于简单或肤浅的“沙盒”环境,因为它们无法用足够的复杂度来对你的工具进行压力测试。一个好的评估任务可能需要多次、甚至几十次工具调用。

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

  • 下周和 Jane 安排一个会议,讨论我们最新的 Acme 公司项目。附上我们上次项目规划会议的纪要,并预订一间会议室。

  • 客户 ID 9182 报告说,他们一次购物尝试被扣了三次款。找出所有相关的日志条目,并确定是否有其他客户受到了同样问题的影响。

  • 客户 Sarah Chen 刚刚提交了取消服务的请求。为她准备一个挽留方案。需要确定:(1) 他们离开的原因,(2) 哪种挽留方案最有吸引力,以及 (3) 在提出方案前,我们需要注意哪些风险因素。

而这些则是一些比较弱的任务:

  • 下周和 jane@acme.corp 安排一个会议。

  • 在支付日志中搜索 purchase_completecustomer_id=9182

  • 通过客户 ID 45892 查找取消服务的请求。

每个评估提示词都应该配有一个可验证的响应或结果。你的验证器可以很简单,比如精确比较标准答案和模型生成的响应是否完全一致;也可以很高级,比如让 Claude 来评判响应的质量。要避免使用过于严格的验证器,它可能会因为一些无关紧要的差异(如格式、标点符号或有效的替代说法)而拒绝正确的响应。

对于每一个提示词-响应对,你还可以选择性地指定你期望智能体在解决任务时调用的工具。这可以用来衡量智能体在评估过程中是否成功理解了每个工具的用途。但是,因为解决任务的正确路径可能不止一条,所以要尽量避免过度指定或对某种特定策略产生过拟合(overfitting)。

运行评估

我们建议你通过直接调用大语言模型 API 来以程序化的方式运行评估。为每个评估任务都使用简单的智能体循环(while 循环,包裹着交替进行的大语言模型 API 调用和工具调用)。每个评估智能体都应该只被赋予一个任务提示词和你的工具集。

在评估智能体的系统提示词中,我们建议你不仅要指示智能体输出结构化的响应块(用于验证),还要输出推理过程和反馈块。指示智能体在输出工具调用和响应块之前输出这些内容,可能会触发模型的思维链(Chain-of-Thought, CoT)行为,从而提高大语言模型的有效智能。

如果你用 Claude 来运行评估,你可以开启交错思考功能,它能“开箱即用”地实现类似的效果。这能帮你探究智能体为什么会(或不会)调用某些工具,并精准定位工具描述和规格中有待改进的地方。

除了顶层准确率,我们还建议收集其他指标,比如单个工具调用和任务的总运行时长、工具调用总数、token 消耗总量以及工具错误。跟踪工具调用可以帮助揭示智能体常用的工作流程,并为工具的整合提供一些机会。

这张图表衡量了人工编写的 Asana MCP 服务器与 Claude 优化后的版本在测试集上的准确率。

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

分析结果 智能体是你发现问题的好帮手,它们能就各种事情提供反馈,从自相矛盾的工具描述,到效率低下的工具实现,再到令人困惑的工具结构。但要记住,智能体在反馈和响应中省略了什么,往往比它们包含了什么更重要。大语言模型并不总是言如其意

观察你的智能体在哪些地方卡住了或感到困惑。仔细阅读评估智能体的推理和反馈(或思维链),找出那些不顺畅的地方。检查原始的交互记录(包括工具调用和工具响应),捕捉任何智能体在思维链中没有明确描述的行为。要学会读懂言外之意;记住,你的评估智能体不一定知道正确的答案和策略。

分析你的工具调用指标。大量的冗余工具调用可能意味着需要调整分页或 token 限制参数;大量的无效参数错误可能表明工具需要更清晰的描述或更好的示例。当初我们推出 Claude 的网页搜索工具时,就发现 Claude 会毫无必要地在工具的 query 参数后附加 2025,这影响了搜索结果,降低了性能(我们通过改进工具描述,成功地将 Claude 引导回了正确的方向)。

与智能体协作

你甚至可以让智能体来帮你分析结果和改进工具。只需将你评估智能体的交互记录拼接起来,然后粘贴到 Claude Code 中。Claude 是分析交互记录和一次性重构大量工具的专家——例如,当有新的改动时,确保工具的实现和描述保持自洽。

事实上,这篇文章中的大部分建议都来自于我们用 Claude Code 反复优化内部工具实现的过程。我们的评估是在我们内部的工作空间之上创建的,反映了我们内部工作流程的复杂性,包括真实的项目、文档和消息。

我们依靠留存测试集来确保我们没有对“训练”评估产生过拟合。这些测试集显示,即使是相较于我们用“专家”实现的工具(无论是研究员手动编写的还是 Claude 自己生成的),我们依然可以榨取出额外的性能提升。

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

编写高效工具的原则

在这一节中,我们将把我们的学习成果提炼成几条编写高效工具的指导原则。

为智能体选择合适的工具

工具并非越多越好。我们观察到的一个常见错误是,有些工具仅仅是对现有软件功能或 API 端点的简单封装——而不管这些工具是否适合智能体使用。这是因为智能体对工具的“可供性”(affordances)与传统软件不同——也就是说,它们感知可以利用这些工具采取行动的方式是不同的。

大语言模型智能体的“上下文”有限(即它们一次能处理的信息量是有限的),而计算机的内存则便宜又充足。想象一下在地址簿中搜索一个联系人的任务。传统的软件程序可以高效地存储和逐一处理联系人列表,检查完一个再移到下一个。

然而,如果一个大语言模型智能体使用了一个返回所有联系人的工具,然后必须逐字逐句地阅读每个联系人,它就是在浪费其有限的上下文空间来处理不相关的信息(想象一下,为了在你的地址簿里找一个联系人,你从第一页开始逐行往下读——这就是所谓的暴力搜索)。对智能体(和人类)来说,更好、更自然的方法是先跳到相关的页面(比如按字母顺序查找)。

我们建议,先针对特定的高价值工作流程,打造几个经过深思熟虑的工具,这些工具要与你的评估任务相匹配,然后再逐步扩展。在地址簿的例子中,你可能会选择实现一个 Contactss(搜索联系人)或 message_contact(给联系人发消息)的工具,而不是 list_contacts(列出所有联系人)的工具。

工具可以整合功能,在后台处理可能多个独立的操作(或 API 调用)。例如,工具可以用相关的元数据来丰富工具的响应,或者在一次工具调用中处理那些经常被链式调用的多步任务。

这里有一些例子:

  • 不要分别实现 list_userslist_eventscreate_event 这三个工具,可以考虑实现一个 schedule_event 工具,它能一步到位地查找空闲时间并安排活动。

  • 不要实现一个 read_logs 工具,可以考虑实现一个 search_logs 工具,它只返回相关的日志行和一些上下文。

  • 不要分别实现 get_customer_by_idlist_transactionslist_notes 这三个工具,可以实现一个 get_customer_context 工具,它能一次性汇编客户所有近期和相关的信息。

确保你构建的每个工具都有一个清晰、独特的目标。工具应该让智能体能够像人类一样,在拥有相同底层资源的情况下,对任务进行细分和解决,同时减少那些本会被中间输出消耗掉的上下文。

太多的工具或功能重叠的工具也会分散智能体的注意力,使其无法采用高效的策略。谨慎、有选择性地规划你构建(或不构建)的工具,真的能带来丰厚的回报。

为你的工具划分命名空间

你的 AI 智能体未来可能会接触到几十个 MCP 服务器和数百个不同的工具——包括其他开发者创建的工具。当工具功能重叠或用途模糊时,智能体可能会搞不清楚该用哪个。

命名空间(将相关的工具分组在共同的前缀下)可以帮助在众多工具之间划定界限;MCP 客户端有时会默认这样做。例如,按服务(如 asana_searchjira_search)和按资源(如 asana_projects_searchasana_users_search)对工具进行命名空间划分,可以帮助智能体在恰当的时候选择正确的工具。

我们发现,选择基于前缀还是后缀的命名空间方案,对我们的工具使用评估结果有不可忽视的影响。具体效果因大语言模型而异,我们鼓励你根据自己的评估结果来选择命名方案。

智能体可能会调用错误的工具,用错误的参数调用正确的工具,调用次数太少,或者错误地处理工具的响应。通过有选择性地实现那些名称能反映任务自然划分的工具,你不仅减少了加载到智能体上下文中的工具和工具描述的数量,还将智能体的计算负担从其上下文中转移回了工具调用本身。这降低了智能体犯错的整体风险。

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

同理,工具的实现也应注意只向智能体返回高价值的信息。它们应该优先考虑上下文的相关性而非灵活性,并避免使用低级别的技术标识符(例如:uuid256px_image_urlmime_type)。像 nameimage_urlfile_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):

这段代码片段展示了一个详细工具响应的例子。

这段代码片段展示了一个详细工具响应的例子。

这是一个简洁工具响应的例子(72 个 token):

这张图片展示了一个简洁工具响应的例子。

这张图片展示了一个简洁工具响应的例子。

甚至你的工具响应结构——例如 XML、JSON 或 Markdown——也会对评估性能产生影响:没有一种“放之四海而皆准”的解决方案。这是因为大语言模型是基于下一个 token 预测进行训练的,它们往往在处理与其训练数据格式相匹配的格式时表现更好。最佳的响应结构会因任务和智能体的不同而大相径庭。我们鼓励你根据自己的评估来选择最佳的响应结构。

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

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

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

如果你选择截断响应,请确保用有用的指令来引导智能体。你可以直接鼓励智能体采取更节省 token 的策略,比如在知识检索任务中进行多次小范围、有针对性的搜索,而不是一次大范围的搜索。同样,如果一个工具调用引发了错误(例如,在输入验证期间),你可以通过提示词工程来优化你的错误响应,使其能清晰地传达具体且可行的改进建议,而不是返回晦涩的错误代码或追溯信息。

这是一个被截断的工具响应的例子:

这张图片展示了一个被截断的工具响应的例子。

这张图片展示了一个被截断的工具响应的例子。

这是一个没有帮助的错误响应的例子:

这张图片展示了一个没有帮助的工具响应的例子。

这张图片展示了一个没有帮助的工具响应的例子。

这是一个有帮助的错误响应的例子:

这张图片展示了一个有帮助的工具响应的例子。

这张图片展示了一个有帮助的工具响应的例子。

通过提示词工程优化你的工具描述

现在我们来到了改进工具最有效的方法之一:通过提示词工程来优化你的工具描述和规格。因为这些内容会被加载到你的智能体上下文中,它们可以共同引导智能体采取有效的工具调用行为。

在编写工具描述和规格时,想象一下你会如何向团队里的一位新同事描述你的工具。思考一下你可能会默认带入的背景知识——特殊的查询格式、小众术语的定义、底层资源之间的关系——并把它们明确地写出来。通过清晰地描述(并用严格的数据模型强制执行)预期的输入和输出来避免歧义。特别是,输入参数应该被明确命名:与其用一个名为 user 的参数,不如用一个名为 user_id 的参数。

有了你的评估体系,你就可以更有信心地衡量你的提示词工程所带来的影响。即使是对工具描述的微小改进,也可能带来巨大的性能提升。在我们对工具描述进行了精确的优化之后,Claude Sonnet 3.5 在 SWE-bench Verified 评估中取得了最先进的性能,极大地降低了错误率并提高了任务完成率。

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

展望未来

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

通过本文中描述的迭代式、评估驱动的过程,我们已经发现了让工具成功的普遍模式:有效的工具目标明确、定义清晰,能明智地使用智能体上下文,可以被组合进多样化的工作流程中,并能让智能体直观地解决真实世界的任务。

在未来,我们预计智能体与世界交互的具体机制将会演进——从 MCP 协议的更新到底层大语言模型本身的升级。通过一个系统化的、评估驱动的方法来改进为智能体设计的工具,我们可以确保,随着智能体变得越来越强大,它们所使用的工具也能与时俱进。

致谢

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

1 此处不包括训练底层大语言模型本身。

一个带有复杂几何形状和精细表面纹理的环环相扣的拼图块

想了解更多?

通过 Anthropic 学院的课程,掌握 API 开发、模型上下文协议和 Claude Code。完成课程后可获得证书。


来源:https://www.anthropic.com/engineering/writing-tools-for-agents