跳转至

为 Agent 编写高效工具——借助 Agent 自身

原文链接: English Original

Engineering at Anthropic

发布于 2025年9月11日

Agent 的效能取决于我们提供给它们的工具。我们将分享如何编写高质量的工具和评估方法,以及如何利用 Claude 优化自身的工具来提升性能。

Model Context Protocol(MCP)可以赋予 LLM agent 潜在数百种工具来解决真实世界任务。但我们如何让这些工具发挥最大效能?

在本文中,我们将介绍在各种 agentic AI 系统中提升性能的最有效技术。

我们首先介绍如何: - 构建和测试工具原型 - 使用 agent 创建和运行全面的工具评估 - 与 Claude Code 等 agent 协作,自动提升工具性能

最后,我们将分享在此过程中总结出的编写高质量工具的关键原则: - 选择合适实现的工具(以及不实现的工具) - 通过命名空间(namespacing)定义清晰的功能边界 - 从工具返回有意义的上下文给 agent - 优化工具响应的 token 效率 - 对工具描述和规格进行 prompt engineering

构建评估可以让你系统地衡量工具的性能。你可以使用 Claude Code 针对此评估自动优化你的工具。

什么是工具?

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

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

工具是一种新型软件,它反映的是确定性系统与非确定性 agent 之间的契约。当用户问"我今天需要带伞吗?"时,agent 可能会调用天气工具,根据常识回答,甚至先询问一个关于位置的澄清问题。有时,agent 可能会产生幻觉,甚至无法掌握如何使用工具。

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

我们的目标是通过使用工具来追求各种成功策略,扩大 agent 在解决广泛任务方面的有效范围。幸运的是,根据我们的经验,对 agent 最"符合人体工程学"的工具最终对人类来说也出奇地直观易懂。

如何编写工具

在本节中,我们将介绍如何与 agent 协作来编写和改进你提供给它们的工具。首先,快速构建工具原型并在本地进行测试。然后,运行全面的评估来衡量后续的变更。与 agent 协作,你可以重复评估和改进工具的过程,直到你的 agent 在真实世界任务上取得良好的性能。

构建原型

在不亲自动手的情况下,很难预判 agent 会觉得哪些工具好用,哪些不好用。首先快速构建工具原型。如果你使用 Claude Code 编写工具(可能一次性完成),最好给 Claude 提供你的工具将依赖的任何软件库、API 或 SDK(包括 MCP SDK)的文档。LLM 友好的文档通常可以在官方文档网站上的平面 llms.txt 文件中找到(这是我们的 API 文档的例子)。

将你的工具包装在本地 MCP server 或 Desktop 扩展(DXT)中,可以让你在 Claude Code 或 Claude Desktop 应用中连接和测试你的工具。

要将本地 MCP server 连接到 Claude Code,运行 claude mcp add [args...]

要将本地 MCP server 或 DXT 连接到 Claude Desktop 应用,分别导航到 Settings > Developer 或 Settings > Extensions。

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

亲自测试工具以发现任何粗糙之处。收集用户的反馈,建立对你期望工具支持的使用场景和提示的直觉。

运行评估

接下来,你需要通过运行评估来衡量 Claude 使用工具的效果。首先,基于真实世界使用生成大量评估任务。我们建议与 agent 协作来帮助分析结果并确定如何改进工具。在我们的工具评估 cookbook 中查看这个端到端的过程。

生成评估任务

使用你的早期原型,Claude Code 可以快速探索你的工具并创建数十个提示和响应对。提示应受到真实世界使用的启发,并基于现实的数据源和服务(例如,内部知识库和微服务)。我们建议避免过于简单或肤浅的"沙盒"环境,它们不会以足够的复杂性对你的工具进行压力测试。优秀的评估任务可能需要多次工具调用——可能多达数十次。

以下是一些强任务的示例: - 与 Jane 安排下周的会议讨论我们最新的 Acme Corp 项目。附上上次项目规划会议的记录,并预订一个会议室。 - 客户 ID 9182 报告称他们因一次购买尝试被扣款三次。查找所有相关日志条目,并确定是否有其他客户受到同一问题的影响。 - 客户 Sarah Chen 刚提交了取消请求。准备一个挽留方案。确定:(1) 她们离开的原因,(2) 什么样的挽留方案最有吸引力,以及 (3) 在提出方案前我们应该注意的风险因素。

以下是一些较弱的任务示例: - 与 jane@acme.corp 安排下周的会议。 - 在支付日志中搜索 purchase_complete 和 customer_id=9182。 - 查找客户 ID 45892 的取消请求。

每个评估提示都应配有一个可验证的响应或结果。你的验证器可以简单到标准答案与采样响应之间的精确字符串比较,也可以高级到让 Claude 来评判响应。避免过于严格的验证器,它们可能因格式、标点或有效替代措辞等虚假差异而拒绝正确响应。

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

运行评估

我们建议通过直接 LLM API 调用以程序化方式运行评估。使用简单的 agentic 循环(包装交替 LLM API 调用和工具调用的 while 循环):每个评估任务一个循环。每个评估 agent 应被赋予一个单独的任务提示和你的工具。

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

如果你使用 Claude 运行评估,你可以开启 interleaved thinking 以获得类似功能的"开箱即用"体验。这将帮助你探究为什么 agent 会或不会调用某些工具,并突出工具描述和规格中需要改进的具体领域。

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

分析结果

Agent 是你发现问题的得力合作伙伴,它们可以提供从矛盾的工具描述到低效的工具实现和令人困惑的工具 schema 等各方面的反馈。但请记住,agent 在反馈和响应中省略的内容往往比包含的内容更重要。LLM 并不总是说它们所想的。

观察你的 agent 在哪些地方卡住或困惑。阅读评估 agent 的推理和反馈(或 CoT)以识别粗糙之处。查看原始转录(包括工具调用和工具响应),以捕获 agent 的 CoT 中未明确描述的任何行为。仔细阅读字里行间;请记住,你的评估 agent 不一定知道正确的答案和策略。

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

与 Agent 协作

你甚至可以让 agent 分析你的结果并为你改进工具。只需将评估 agent 的转录拼接起来并粘贴到 Claude Code 中。Claude 是分析转录和一次性重构大量工具的专家——例如,确保在引入新变更时工具实现和描述保持自洽。

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

我们依靠留出测试集来确保我们没有对"训练"评估过拟合。这些测试集显示,即使在"专家"工具实现取得的效果之上,我们仍能获得额外的性能提升——无论这些工具是由我们的研究人员手动编写的,还是由 Claude 生成的。

在下一节中,我们将分享在此过程中的一些发现。

编写高效工具的原则

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

为 Agent 选择合适的工具

更多的工具并不总是带来更好的结果。我们观察到的常见错误是工具仅仅包装了现有的软件功能或 API 端点——无论这些工具是否适合 agent。这是因为 agent 具有与传统软件不同的"可操作性"(affordances)——即它们感知可以使用这些工具执行的潜在操作的方式不同。

LLM agent 的"上下文"有限(即它们一次能处理的信息量有限),而计算机内存既便宜又充裕。考虑在地址簿中搜索联系人的任务。传统软件程序可以高效地逐个存储和处理联系人列表,在移动到下一个之前检查每一个。

然而,如果一个 LLM agent 使用一个返回所有联系人的工具,然后必须逐个 token 地阅读每一个,它就在用不相关的信息浪费有限的上下文空间(想象一下通过从上到下阅读每一页来在地址簿中搜索联系人——即通过暴力搜索)。对 agent 和人类来说,更好、更自然的方法是先跳到相关页面(也许是按字母顺序找到它)。

我们建议构建少量针对特定高影响工作流的精心设计的工具,这些工具应与你的评估任务匹配,并从此处逐步扩展。在地址簿的例子中,你可能选择实现 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 工具,它可以一次性编译客户的所有近期和相关信息。

确保你构建的每个工具都有清晰、独特的用途。工具应使 agent 能够以类似于人类在访问相同底层资源时的方式细分和解决任务,同时减少本应被中间输出消耗的上下文。

过多的工具或功能重叠的工具也可能分散 agent 追求高效策略的注意力。仔细、有选择地规划你构建(或不构建)的工具可以真正产生回报。

工具命名空间

你的 AI agent 可能获得访问数十个 MCP server 和数百种不同工具的能力——包括其他开发者创建的工具。当工具在功能上重叠或目的模糊时,agent 可能会困惑于该使用哪些工具。

命名空间(将相关工具分组在共同前缀下)可以帮助在大量工具之间划定边界;MCP 客户端有时会默认执行此操作。例如,按服务命名空间化工具(如 asana_searchjira_search)和按资源命名空间化工具(如 asana_projects_searchasana_users_search),可以帮助 agent 在正确的时间选择正确的工具。

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

Agent 可能会调用错误的工具、用错误的参数调用正确的工具、调用太少的工具,或错误地处理工具响应。通过选择性地实现名称反映任务自然细分的工具,你同时减少了加载到 agent 上下文中的工具和工具描述的数量,并将 agentic 计算从 agent 的上下文卸载回工具调用本身。这降低了 agent 犯错的整体风险。

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

同样地,工具实现应注意只向 agent 返回高信号信息。它们应优先考虑上下文相关性而非灵活性,并避免使用低级技术标识符(例如:uuid256px_image_urlmime_type)。nameimage_urlfile_type 等字段更有可能直接为 agent 的下游操作和响应提供信息。

Agent 在处理自然语言名称、术语或标识符时,通常比处理晦涩的标识符更为成功。我们发现,仅仅将任意字母数字 UUID 解析为更具语义意义和可解释的语言(甚至 0 索引的 ID 方案),就能通过减少幻觉显著提高 Claude 在检索任务中的精确度。

在某些情况下,agent 可能需要与自然语言和技术标识符输出交互的灵活性,即使只是为了触发下游工具调用(例如,search_user(name='jane')send_message(id=12345))。你可以通过在工具中暴露一个简单的 response_format enum 参数来启用两者,允许 agent 控制工具返回"简洁"还是"详细"的响应。

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

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

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

优化工具响应的 token 效率

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

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

如果你选择截断响应,请确保使用有用的指令引导 agent。你可以直接鼓励 agent 追求更省 token 的策略,例如在知识检索任务中进行多次小而精准的搜索,而不是一次宽泛的搜索。同样,如果工具调用引发错误(例如,在输入验证期间),你可以对错误响应进行 prompt engineering,以清晰传达具体且可操作的改进建议,而不是不透明的错误代码或堆栈跟踪。

工具截断和错误响应可以引导 agent 采取更省 token 的工具使用行为(使用过滤器或分页),或提供正确格式化工具输入的示例。

工具描述的 Prompt Engineering

我们现在来到改进工具最有效的方法之一:对工具描述和规格进行 prompt engineering。因为这些内容被加载到 agent 的上下文中,它们可以集体引导 agent 采取有效的工具调用行为。

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

通过你的评估,你可以更有信心地衡量 prompt engineering 的影响。即使对工具描述的微小改进也能产生显著的性能提升。Claude Sonnet 3.5 在我们对工具描述进行精确改进后,在 SWE-bench Verified 评估上取得了最先进的性能,大幅降低了错误率并提升了任务完成率。

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

展望未来

要为 agent 构建高效工具,我们需要将软件开发实践从可预测的、确定性的模式重新定位为非确定性的模式。

通过本文描述的迭代式、评估驱动的过程,我们识别出了工具成功的一致模式:高效的工具是有意图地、清晰地定义的,审慎地使用 agent 上下文,可以在多样化的工作流中组合使用,并使 agent 能够直观地解决真实世界任务。

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

致谢

由 Ken Aizawa 撰写,Research(Barry Zhang、Zachary Witten、Daniel Jiang、Sami Al-Sheikh、Matt Bell、Maggie Vo)、MCP(Theodora Chu、John Welsh、David Soria Parra、Adam Jones)、Product Engineering(Santiago Seira)、Marketing(Molly Vorwerck)、Design(Drew Roper)和 Applied AI(Christian Ryan、Alexander Bricken)各部门同事提供了宝贵贡献。

了解更多

探索我们的课程。

订阅开发者通讯

产品更新、操作指南、社区聚焦等内容。每月发送到您的邮箱。

请提供您的电子邮件地址以接收我们的月度开发者通讯。您可以随时取消订阅。