与智能体协作,为智能体编写高效工具

智能体的效能取决于我们提供给它们的工具。本文分享如何编写高质量的工具与评测,以及如何借助 Claude 让其为自身使用的工具进行优化,从而提升性能。

Model Context Protocol (MCP) 可以为 LLM 智能体赋予多达数百种工具,用于解决真实世界的任务。但如何让这些工具发挥最大效用?

在这篇文章中,我们总结了在各类智能体 AI 系统1中用以提升性能的最有效方法。

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

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

最后,我们给出一路上识别出的高质量工具编写的关键原则:

  • 选择该实现(或不该实现)哪些工具
  • 通过命名空间为工具划定清晰的功能边界
  • 让工具向智能体返回有意义的上下文
  • 为 token 效率优化工具响应
  • 对工具描述和规格进行提示工程
此图展示工程师如何使用 Claude Code 评估智能体工具的有效性。
构建评测能让你系统地衡量工具的表现。你可以使用 Claude Code 针对该评测自动优化你的工具。

什么是工具?

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

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

工具是一类新的软件,它体现的是确定性系统与非确定性智能体之间的契约。当用户询问“我今天需要带伞吗?”,智能体可能会调用天气工具,也可能凭借常识作答,或先提出一个关于位置的澄清问题。有时,智能体还可能产生幻觉,甚至不理解如何使用某个工具。

这意味着在为智能体编写软件时需要彻底重新思考:不再像为其他开发者或系统编写函数和 API 那样编写工具和 MCP 服务器,而是要专门为智能体设计它们。

我们的目标是通过工具,让智能体能够在更广泛的任务上发挥作用,采用多种成功策略。幸运的是,根据我们的经验,对智能体最“符合人体工学”的工具,往往也出乎意料地直观易于人类理解。

如何编写工具

本节介绍如何与智能体协作,既编写又改进你提供给它们的工具。先快速搭建工具原型并在本地测试;随后运行全面的评测来衡量后续改动。与智能体并肩工作,你可以反复评估和改进工具,直到智能体在真实任务中表现强劲。

构建原型

如果不亲自上手,很难预判智能体觉得哪些工具顺手、哪些不顺手。先快速搭建工具原型。如果你使用 Claude Code(甚至一次性)来编写工具,最好向 Claude 提供工具所依赖的软件库、API 或 SDK(包括可能的 MCP SDK)的文档。适合 LLM 的文档通常可以在官方文档站点的扁平 llms.txt 文件中找到(例如我们的 API 文档)。

将工具封装在本地 MCP 服务器桌面扩展(DXT)中,可以让你在 Claude Code 或 Claude 桌面应用里连接并测试这些工具。

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

要在 Claude 桌面应用中连接本地 MCP 服务器或 DXT,请分别前往 Settings > DeveloperSettings > Extensions

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

亲自测试工具,找出任何粗糙之处。收集用户反馈,培养对你希望工具支持的用例和提示的直觉。

运行评测

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

该图展示了人类编写与 Claude 优化的 Slack MCP 服务器在测试集上的准确率对比。
我们内部 Slack 工具在留出测试集上的表现

生成评测任务

借助早期原型,Claude Code 可以快速探索你的工具并创建数十个提示与响应对。提示应来源于真实世界的使用场景,并基于现实的数据源和服务(例如内部知识库与微服务)。我们建议避免过于简单或表面的“沙盒”环境,因为它们无法用足够的复杂度来压测你的工具。强健的评测任务可能需要多个工具调用——甚至可能是几十次。

以下是一些强任务示例:

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

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

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

每个评测提示都应配有可验证的回应或结果。验证器可以简单到将采样回应与基准答案做精确字符串比对,也可以复杂到让 Claude 充当评审。避免过于严格的验证器——它们可能因格式、标点或同义表达的差异而拒绝正确答案。

对于每个提示-回应对,你也可以(可选地)指定你预期智能体为完成任务会调用的工具,用来衡量智能体在评测中是否成功把握了各工具的用途。不过,由于完成任务往往存在多条有效路径,请尽量避免对策略进行过度规定或过拟合。

运行评测

我们建议用直接的 LLM API 调用以编程方式运行你的评测。使用简单的智能体循环(将 LLM API 调用和工具调用交替包裹在 while 循环中):每个评测任务一个循环。每个评测智能体应只被给予一个任务提示以及你的工具。

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

如果你用 Claude 运行评测,你可以开启交织式思考来获得类似的“开箱即用”能力。这将帮助你探查智能体为什么会(或不会)调用某些工具,并突出工具描述与规格中需要改进的具体部分。

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

该图展示了人类编写与 Claude 优化的 Asana MCP 服务器在测试集上的准确率对比。
我们内部 Asana 工具在留出测试集上的表现

分析结果
智能体可以帮助你发现问题并为方方面面提供反馈,从相互矛盾的工具描述到低效的工具实现、再到混淆的工具模式。然而要记住,智能体在反馈和响应中没有提到的内容,往往比提到的更重要。LLM 并不总是言出即所指

观察智能体在哪些地方卡住或困惑。通读评测智能体的推理与反馈(或 CoT),找出粗糙之处。审阅原始的对话记录(包括工具调用与工具响应),捕捉智能体在 CoT 中未明确描述的行为。读懂“行间之意”;记住你的评测智能体未必知道正确答案与策略。

分析你的工具调用指标。大量重复的工具调用可能表明需要对分页或 token 限制参数进行合理化设置;大量由于无效参数导致的工具错误,可能说明工具需要更清晰的描述或更好的示例。我们在发布 Claude 的网页搜索工具时发现,Claude 会不必要地在工具的 query 参数后附加 2025,从而使搜索结果产生偏差并降低性能(我们通过改进工具描述将 Claude 引导回正确方向)。

与智能体协作

你甚至可以让智能体替你分析结果并改进工具。只需把评测智能体的所有对话记录拼接起来并粘贴到 Claude Code 中即可。Claude 擅长分析对话记录,并一次性重构大量工具——例如,确保在引入新变更后,工具实现与描述保持自洽。

事实上,本文的大部分建议都来自我们用 Claude Code 反复优化内部工具实现的过程。我们的评测构建在内部工作空间之上,反映了内部工作流的复杂性,包括真实的项目、文档与消息。

我们依赖留出测试集来确保不会对“训练用”的评测过拟合。这些测试集表明,即便超越我们用“专家级”工具实现所达到的水平,我们仍能进一步挖掘性能提升——无论这些工具是由研究人员手写,还是由 Claude 生成。

在下一节,我们将分享从这一过程里总结出的部分经验。

编写高效工具的原则

本节把我们的经验提炼为一些用于编写高效工具的指导性原则。

为智能体选择合适的工具

工具更多并不总意味着更好。我们常见的一个错误,是把现有软件功能或 API 端点直接“包一层”就当成工具——不管这些工具是否适合智能体使用。原因在于,相比传统软件,智能体具有不同的“供给性”(affordances)——也就是说,它们感知可采取行动的方式不同。

LLM 智能体的“上下文”是有限的(即一次能处理的信息量受限),而计算机内存却廉价而充裕。想象在通讯录中搜索联系人这一任务。传统程序可以高效地逐个存储并处理联系人,在前进之前检查每一项。

然而,如果 LLM 智能体使用的工具返回了所有联系人,然后不得不逐 token 阅读每一个条目,它就会把有限的上下文空间浪费在无关信息上(想象你在通讯录里逐页从上到下阅读,进行蛮力搜索)。更好且更自然的做法(对智能体和人类都一样)是先跳到相关页面(例如按字母顺序查找)。

我们建议先构建少量经过深思熟虑的工具,针对特定的高影响工作流,并与评测任务保持一致,然后逐步扩展。在通讯录的例子中,你可以考虑实现 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 工具,一次性汇总客户近期且相关的信息。

确保你构建的每个工具都有明确而独特的目标。工具应帮助智能体像人类在拥有同样资源时那样,将任务拆解并完成,同时减少中间输出本会消耗的上下文。

过多或功能重叠的工具也会分散智能体追求高效策略的注意力。对将要构建(或不构建)哪些工具进行谨慎、选择性的规划,能够带来丰厚回报。

为工具划分命名空间

你的 AI 智能体可能会获得数十个 MCP 服务器与数百个不同工具的访问权限——其中包括其他开发者编写的工具。当工具功能重叠或目的模糊时,智能体会难以判断该使用哪一个。

通过命名空间(按共同前缀将相关工具分组)可以帮助界定大量工具之间的边界;MCP 客户端有时会默认这样做。例如,按服务命名空间(如 asana_searchjira_search),以及按资源命名空间(如 asana_projects_searchasana_users_search),都能帮助智能体在正确的时间选择正确的工具。

我们发现,选择使用前缀式还是后缀式命名空间会对我们的工具使用评测产生非平凡的影响。效果因 LLM 而异,我们鼓励你根据自己的评测结果选择命名方案。

智能体可能会调用错误的工具,或以错误参数调用正确的工具,或调用次数过少,或错误处理工具响应。通过有选择地实现名称能够反映任务自然划分的工具,你既减少了加载到智能体上下文中的工具数量及其描述,又能把智能体的部分推理从上下文中转移回工具调用本身,从而降低整体出错风险。

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

同样地,工具实现应谨慎地只向智能体返回高信号信息。它们应优先考虑上下文相关性,而不是灵活性,并尽量避免低层级的技术标识符(例如 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):

该代码片段展示了一个简洁工具响应的示例。
Slack 主题与主题回复由唯一的 `thread_ts` 标识,获取主题回复需要它。`thread_ts` 及其他 ID(`channel_id`、`user_id`)可以从 `“detailed”` 工具响应中获取,从而支持需要这些 ID 的后续工具调用。`“concise”` 工具响应仅返回主题内容并省略 ID。在这个示例中,使用 `“concise”` 响应可将 token 使用量降至约 1/3。

即便是你的工具响应结构——例如 XML、JSON 或 Markdown——也会影响评测表现:不存在放之四海而皆准的方案。这是因为 LLM 以下一 token 预测为训练目标,通常在与其训练数据相匹配的格式上表现更好。最佳的响应结构会因任务与智能体而异。我们建议基于你的评测选择最合适的响应结构。

为 token 效率优化工具响应

优化上下文的质量很重要;同样重要的,是优化工具响应返还给智能体的上下文数量

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

如果你选择截断响应,请务必通过有用的指引来引导智能体。你可以直接鼓励智能体采取更节省 token 的策略,例如在知识检索任务中进行多次小而精准的搜索,而不是一次宽泛的全局搜索。同样,如果一次工具调用触发了错误(例如在输入验证期间),你可以对错误响应进行提示工程,清晰地传达具体且可执行的改进建议,而不是晦涩的错误码或回溯。

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

该图展示了一个截断的工具响应示例。

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

该图展示了一个无益的工具错误响应示例。

下面是一个有益的错误响应示例:

该图展示了一个有益的错误响应示例。
通过对截断与错误响应进行设计,可以引导智能体采用更节省 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 Academy 的课程系统学习 API 开发、Model Context Protocol 与 Claude Code。完成课程后可获得证书。

探索课程

订阅开发者通讯

产品更新、操作指南、社区亮点等等,每月发送到你的收件箱。

如果你希望收到我们的月度开发者通讯,请提供你的邮箱地址。你可以随时取消订阅。