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

Anthropic 分享如何用智能体编写高效的 Agent 工具

Writing effective tools for agents — with agents

AI 导读

Anthropic 工程团队发布文章,介绍为 LLM 智能体编写 MCP 工具的方法:先搭建原型,再用真实任务构建评估集,并借助 Claude Code 分析结果、自动优化工具。

推荐理由

Anthropic 工程团队给出为智能体设计 MCP 工具的完整方法,含评估流程与命名、返回结构等可迁移原则。

正文 · 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 来编写工具(甚至可以一次性完成),那么为工具所依赖的任何软件库、API 或 SDK(可能包括 MCP SDK)向 Claude 提供文档会很有帮助。对 LLM 友好的文档通常可以在官方文档站点上的扁平 llms.txt 文件中找到(这里是我们 API 的文档)。

将工具封装在 本地 MCP 服务器或 桌面扩展(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 使用你的工具的效果。先从生成大量基于真实世界用例的评估任务开始。我们建议与一个 agent 协作,帮助分析结果并确定如何改进你的工具。在我们的 工具评估 cookbook 中可以端到端地了解这一流程。

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) 在提出方案之前我们应该注意的任何风险因素。

以下是一些较弱的任务:

  • 安排下周与 [email protected] 的会议。
  • 在支付日志中搜索 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 工具的留出测试集性能

分析结果
智能体是你发现问题和提供反馈的有用伙伴,从矛盾的工具有描述到低效的工具实现以及令人困惑的工具 schema,它们都能提供反馈。然而,请记住,智能体在反馈和响应中省略的内容往往比包含的内容更重要。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.
工具截断和错误响应可以引导 agent 采用更节省 token 的工具使用行为(使用过滤器或分页),或者给出格式正确的工具输入示例。

对工具描述进行提示工程

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

在编写工具描述和规范时,想想你会如何向团队中新入职的成员描述你的工具。考虑你可能隐含带入的上下文——特殊的查询格式、小众术语的定义、底层资源之间的关系——并将其明确化。通过清晰描述(并用严格的数据模型强制执行)预期的输入和输出,避免歧义。特别是,输入参数应明确命名:与其使用名为 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