原文 | Writing effective tools for agents — with agents摘要:AI 智能体 (AI Agent) 的效能取决于我们为其提供的工具。我们将分享如何编写高质量的工具和评估方法,以及如何利用 Claude 来优化其自身的工具以提升性能。
编译 | 段小草 + Gemini 2.5 Pro 与 AI 智能体协作,为其编写高效工具
AI 智能体 (AI Agent) 的效能取决于我们为其提供的工具。我们将分享如何编写高质量的工具和评估方法,以及如何利用 Claude 来优化其自身的工具以提升性能。
模型上下文协议 (Model Context Protocol, MCP) 可以为大语言模型 (Large Language Model, LLM) 智能体提供数百种工具,以解决现实世界中的任务。但我们如何才能让这些工具发挥最大效用呢?
在这篇文章中,我们描述了在多种 AI 智能体系统中提升性能的有效技术。
我们首先将介绍如何:
构建和测试工具原型 与 AI 智能体一同创建并运行全面的工具评估 与 Claude Code 这样的 AI 智能体协作,自动提升工具的性能最后,我们将总结在此过程中发现的编写高质量工具的关键原则:
选择合适的工具进行实现 (以及不实现哪些工具) 为工具划分命名空间以明确功能边界 从工具向 AI 智能体返回有意义的上下文 优化工具响应的 Token 效率 对工具描述和规格进行提示词 (prompt) 工程在计算领域,确定性系统在给定相同输入时每次都会产生相同的输出,而非确定性系统——例如 AI 智能体——即使在起始条件相同的情况下也可能生成不同的响应。
当我们编写传统软件时,我们是在确定性系统之间建立一种契约。例如,像 getWeather(“NYC”) 这样的函数调用,每次被调用时都会以完全相同的方式获取纽约市的天气。工具是一种新型软件,它反映了确定性系统与非确定性 AI 智能体之间的契约。当用户问「我今天应该带伞吗?」,一个 AI 智能体可能会调用天气工具,根据通用知识回答,甚至可能先问一个澄清地点的问题。偶尔,AI 智能体可能会产生幻觉,甚至无法理解如何使用某个工具。
这意味着在为 AI 智能体编写软件时,我们需要从根本上重新思考我们的方法:我们不能像为其他开发者或系统编写函数和 API 那样编写工具和 MCP 服务器,而是需要为 AI 智能体量身设计。
我们的目标是通过使用工具来追求各种成功的策略,从而扩大 AI 智能体能够有效解决广泛任务的范围。幸运的是,根据我们的经验,对 AI 智能体而言最「符合人体工程学」的工具,最终往往也出乎意料地容易被人类理解。
如何编写工具在本节中,我们描述了如何与 AI 智能体协作来编写和改进你提供给它们的工具。首先,快速建立一个工具原型并在本地进行测试。接下来,运行全面的评估以衡量后续的改动。通过与 AI 智能体协同工作,你可以重复评估和改进工具的过程,直到你的 AI 智能体在现实世界的任务中取得优异的性能。
构建原型
如果不亲自动手,很难预料 AI 智能体会觉得哪些工具符合人体工程学,哪些不会。首先,快速建立一个工具原型。如果你正在使用 Claude Code 来编写工具 (可能是一次性生成),为 Claude 提供你的工具将依赖的任何软件库、API 或 SDK (软件开发工具包) 的文档会很有帮助 (其中可能包括 MCP SDK )。对大语言模型友好的文档通常可以在官方文档网站的扁平化 llms.txt 文件中找到 (这是我们的 API 文档 )。将你的工具封装在 本地 MCP 服务器 或 桌面扩展 (Desktop extension, DXT) 中,可以让你在 Claude Code 或 Claude 桌面应用中连接和测试你的工具。
要将你的本地 MCP 服务器连接到 Claude Code,请运行要将你的本地 MCP 服务器或 DXT 连接到 Claude 桌面应用,请分别导航至 Settings > Developer 或 Settings > Extensions 。工具也可以直接传递到 Anthropic API 调用中进行程序化测试。
亲自测试这些工具以发现任何不完善之处。收集用户的反馈,以便围绕你期望工具支持的用例和提示词建立直觉。
运行评估
接下来,你需要通过运行评估来衡量 Claude 使用你工具的效果。首先,生成大量基于现实世界应用的评估任务。我们建议与一个 AI 智能体协作,以帮助分析你的结果并确定如何改进你的工具。在我们的 工具评估 cookbook 中可以查看这一端到端的流程。
生成评估任务
利用你的早期原型,Claude Code 可以快速探索你的工具并创建数十个提示词和响应对。提示词应受现实世界应用的启发,并基于现实的数据源和服务 (例如,内部知识库和微服务)。我们建议你避免使用过于简单或肤浅的「沙盒」环境,因为它们无法以足够的复杂性对你的工具进行压力测试。一个好的评估任务可能需要多次工具调用——甚至可能多达数十次。
以下是一些优质任务的示例:
安排下周与 Jane 开会,讨论我们最新的 Acme Corp 项目。附上我们上次项目规划会议的纪要,并预订一间会议室。 客户 ID 9182 报告称,他们的一次购买尝试被收取了三次费用。查找所有相关的日志条目,并确定是否有其他客户受到同一问题的影响。 客户 Sarah Chen 刚刚提交了取消请求。准备一份挽留方案。确定:(1) 他们离开的原因,(2) 哪种挽留方案最具吸引力,以及 (3) 在提出方案前我们应该注意哪些风险因素。以下是一些较弱任务的示例:
安排下周与 jane@acme.corp 开会。 在支付日志中搜索 purchase_complete 和 customer_id=9182 。 通过客户 ID 45892 查找取消请求。每个评估提示词都应与一个可验证的响应或结果配对。你的验证器可以简单到只是基准真相与采样响应之间的精确字符串比较,也可以高级到让 Claude 来评判响应。避免使用过于严格的验证器,它们可能会因为格式、标点符号或有效的替代措辞等无关紧要的差异而拒绝正确的响应。
对于每个提示词-响应对,你还可以选择性地指定你期望 AI 智能体在解决任务时调用的工具,以衡量 AI 智能体在评估过程中是否成功掌握了每个工具的用途。然而,由于正确解决任务可能存在多种有效路径,请尽量避免对策略进行过度指定或过拟合。
运行评估
我们建议通过直接调用 LLM API 来以编程方式运行你的评估。使用简单的 AI 智能体循环 (包裹着交替的 LLM API 调用和工具调用的 while 循环):每个评估任务一个循环。每个评估智能体都应被给予一个任务提示词和你的工具。在你的评估智能体的系统提示词中,我们建议指示 AI 智能体不仅输出结构化的响应块 (用于验证),还要输出推理和反馈块。指示 AI 智能体在工具调用和响应块 之前 输出这些内容,可能会通过触发思维链 (chain-of-thought, CoT) 行为来提高大语言模型的有效智能。
如果你正在使用 Claude 运行评估,你可以开启 交错思考 (interleaved thinking) 功能以获得类似的「开箱即用」的功能。这将帮助你探究 AI 智能体调用或不调用某些工具的原因,并突出工具描述和规格中需要改进的具体方面。
除了顶层准确率,我们还建议收集其他指标,如单个工具调用和任务的总运行时间、总工具调用次数、总 Token 消耗量以及工具错误。跟踪工具调用有助于揭示 AI 智能体遵循的常见工作流程,并为工具的整合提供一些机会。
分析结果
智能体是你发现问题并提供反馈的得力伙伴,它们可以对从相互矛盾的工具描述到低效的工具实现和令人困惑的工具模式等所有方面提出意见。然而,请记住,AI 智能体在其反馈和响应中省略的内容往往比它们包含的内容更重要。大语言模型并不总是 言如其意 。
观察你的 AI 智能体在哪些地方感到困惑或不知所措。通读评估智能体的推理和反馈 (或 CoT),以发现不完善之处。审查原始的交互记录 (包括工具调用和工具响应),以捕捉任何未在 AI 智能体的 CoT 中明确描述的行为。要读懂言外之意;请记住,你的评估智能体不一定知道正确的答案和策略。
分析你的工具调用指标。大量的冗余工具调用可能表明需要调整分页或 Token 限制参数;大量因无效参数导致的工具错误可能表明工具需要更清晰的描述或更好的示例。当我们推出 Claude 的 网页搜索工具 时,我们发现 Claude 会不必要地将 2025 query 参数上,这导致搜索结果出现偏差并降低了性能 (我们通过改进工具描述将 Claude 引导到了正确的方向)。与 AI 智能体协作
你甚至可以让 AI 智能体为你分析结果并改进你的工具。只需将评估智能体的交互记录串联起来,然后粘贴到 Claude Code 中。Claude 是分析交互记录和一次性重构大量工具的专家——例如,在进行新更改时确保工具实现和描述保持自洽。
事实上,本文中的大部分建议都来自于我们使用 Claude Code 反复优化内部工具实现的经验。我们的评估是在我们的内部工作空间之上创建的,反映了我们内部工作流程的复杂性,包括真实的项目、文档和消息。
我们依靠留出测试集来确保我们没有对「训练」评估产生过拟合。这些测试集表明,即使是与「专家级」工具实现 (无论是我们的研究人员手动编写的还是由 Claude 自己生成的) 相比,我们仍然可以获得额外的性能提升。
在下一节中,我们将分享我们从这个过程中学到的一些经验。
编写高效工具的原则在本节中,我们将我们的学习成果提炼为编写高效工具的几个指导原则。
为 AI 智能体选择合适的工具
更多的工具并不总能带来更好的结果。我们观察到的一个常见错误是,工具仅仅是对现有软件功能或 API 端点的封装——而不管这些工具是否适合 AI 智能体。这是因为 AI 智能体与传统软件有不同的「功能可见性」——也就是说,它们感知可以利用这些工具采取的潜在行动的方式不同。
LLM 智能体的「上下文」是有限的 (即它们一次可以处理的信息量有限),而计算机内存则廉价且充足。考虑在地址簿中搜索联系人的任务。传统软件程序可以高效地存储和逐个处理联系人列表,检查完一个再移至下一个。
然而,如果一个 LLM 智能体使用一个返回所有联系人的工具,然后必须逐个 Token 地阅读每个联系人,它就在不相关的信息上浪费了其有限的上下文空间 (想象一下通过从上到下阅读每一页来在地址簿中查找联系人——即通过暴力搜索)。更好、更自然的方法 (对 AI 智能体和人类都适用) 是首先跳到相关的页面 (也许是按字母顺序查找)。
我们建议构建几个精心设计的工具,针对特定的高影响力工作流程,这些工作流程与你的评估任务相匹配,并以此为基础进行扩展。在地址簿的例子中,你可能会选择实现一个 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 智能体像人类一样,在可以使用相同底层资源的情况下,对任务进行细分和解决,同时减少本可能被中间输出消耗的上下文。
过多的工具或功能重叠的工具也可能分散 AI 智能体的注意力,使其无法采用高效的策略。仔细、有选择地规划你构建 (或不构建) 的工具可以带来真正的回报。
为你的工具划分命名空间
你的 AI 智能体可能会接触到数十个 MCP 服务器和数百种不同的工具——包括其他开发者开发的工具。当工具功能重叠或目的模糊时,AI 智能体可能会对使用哪个工具感到困惑。
命名空间 (Namespacing,即将相关工具分组到共同的前缀下) 可以帮助在大量工具之间划定边界;MCP 客户端有时会默认这样做。例如,按服务 (如 asana_search 、 jira_search ) 和按资源 (如 asana_projects_search 、 asana_users_search ) 为工具划分命名空间,可以帮助 AI 智能体在正确的时间选择正确的工具。我们发现,选择基于前缀还是后缀的命名空间对我们的工具使用评估有不可忽视的影响。具体影响因 LLM 而异,我们鼓励你根据自己的评估选择命名方案。
AI 智能体可能会调用错误的工具,用错误的参数调用正确的工具,调用过少的工具,或错误地处理工具响应。通过有选择地实现其名称能反映任务自然划分的工具,你既减少了加载到 AI 智能体上下文中的工具和工具描述的数量,又将 AI 智能体的计算从其上下文中卸载回工具调用本身。这降低了 AI 智能体犯错的总体风险。
同样地,工具的实现应注意只向 AI 智能体返回高信号信息。它们应优先考虑上下文相关性而非灵活性,并避免使用低级别的技术标识符 (例如: uuid 、 256px_image_url 、 mime_type )。像 name 、 image_url 和 file_type 这样的字段更有可能直接为 AI 智能体的下游行动和响应提供信息。与神秘的标识符相比,AI 智能体处理自然语言名称、术语或标识符的成功率要高得多。我们发现,仅仅将任意的字母数字 UUID 解析为更具语义意义和可解释性的语言 (甚至是一个从 0 开始的索引 ID 方案),就能通过减少幻觉显著提高 Claude 在检索任务中的精确度。
在某些情况下,AI 智能体可能需要灵活地与自然语言和技术标识符输出进行交互,哪怕只是为了触发下游的工具调用 (例如, search_user(name=’jane’) → send_message(id=12345) )。你可以在工具中暴露一个简单的 response_format 枚举参数来同时启用这两种方式,从而让你的 AI 智能体控制工具是返回 “concise” (简洁) 还是 “detailed” 的响应 (见下图)。你可以添加更多格式以获得更大的灵活性,类似于 GraphQL,你可以精确选择希望接收哪些信息。这是一个用于控制工具响应详细程度的 ResponseFormat 枚举示例:
enum ResponseFormat { DETAILED = "detailed", CONCISE = "concise"}这是一个详细工具响应的示例 (206 个 Token):
这是一个简洁工具响应的示例 (72 个 Token):
甚至你的工具响应结构——例如 XML、JSON 或 Markdown——也可能对评估性能产生影响:没有一种一刀切的解决方案。这是因为 LLM 是通过下一个 Token 预测来训练的,它们往往在处理与其训练数据相匹配的格式时表现更好。最佳的响应结构会因任务和 AI 智能体的不同而有很大差异。我们鼓励你根据自己的评估来选择最佳的响应结构。
优化工具响应的 Token 效率
对于任何可能占用大量上下文的工具响应,我们建议实现分页、范围选择、过滤和/或截断的某种组合,并设置合理的默认参数值。对于 Claude Code,我们默认将工具响应限制在 25,000 个 Token。我们预计 AI 智能体的有效上下文长度会随着时间的推移而增长,但对上下文高效工具的需求将持续存在。
如果你选择截断响应,请确保用有用的指令来引导 AI 智能体。你可以直接鼓励 AI 智能体采取更节省 Token 的策略,比如在知识检索任务中进行多次小范围、有针对性的搜索,而不是一次大范围的搜索。同样,如果一个工具调用引发了错误 (例如,在输入验证期间),你可以对你的错误响应进行提示词工程,以清晰地传达具体且可操作的改进建议,而不是返回晦涩的错误代码或追溯信息。
这是一个截断工具响应的示例:
这是一个无用错误响应的示例:
这是一个有用的错误响应的示例:
工具的截断和错误响应可以引导 AI 智能体采取更节省 Token 的工具使用行为 (使用过滤器或分页),或提供正确格式化工具输入的示例。
对你的工具描述进行提示词工程
现在我们来谈谈改进工具最有效的方法之一:对你的工具描述和规格进行提示词工程。因为这些内容会被加载到你的 AI 智能体的上下文中,它们可以共同引导 AI 智能体采取有效的工具调用行为。
在编写工具描述和规格时,可以想象一下你将如何向团队中的新成员描述你的工具。考虑你可能会隐式带来的上下文——专门的查询格式、小众术语的定义、底层资源之间的关系——并将其明确化。通过清晰地描述 (并用严格的数据模型强制执行) 预期的输入和输出来避免歧义。特别是,输入参数应该被明确命名:与其使用名为 user 的参数,不如尝试使用名为的参数。通过你的评估,你可以更有信心地衡量你的提示词工程的影响。即使是对工具描述的微小改进也能带来显著的提升。在我们对工具描述进行了精确的改进后,Claude Sonnet 3.5 在 SWE-bench Verified 评估中取得了最先进的性能,极大地降低了错误率并提高了任务完成率。
你可以在我们的 开发者指南 中找到关于工具定义的其他最佳实践。如果你正在为 Claude 构建工具,我们还建议你阅读关于工具是如何动态加载到 Claude 的 系统提示词 中的。最后,如果你正在为 MCP 服务器编写工具, 工具注解 (tool annotations) 有助于揭示哪些工具需要开放世界访问或会进行破坏性更改。
展望未来要为 AI 智能体构建有效的工具,我们需要将我们的软件开发实践从可预测的、确定性的模式重新定位到非确定性的模式。
通过本文中描述的迭代式、评估驱动的过程,我们发现了一些关于成功工具的一致模式:有效的工具被有意地、清晰地定义,明智地使用 AI 智能体上下文,可以组合在多样化的工作流程中,并使 AI 智能体能够直观地解决现实世界的任务。
在未来,我们预计 AI 智能体与世界互动的具体机制将会演变——从 MCP 协议的更新到底层 LLM 本身的升级。通过一种系统性的、评估驱动的方法来改进 AI 智能体的工具,我们可以确保随着 AI 智能体变得越来越强大,它们使用的工具也将随之共同进化。
来源:晚晚的星河日记一点号