为智能体编写有效工具,并借助智能体来完成
智能体的效果取决于我们提供给它们的工具。我们分享如何编写高质量工具和评估,以及如何使用 Claude 为自己优化工具来提升性能。
来源:https://www.anthropic.com/engineering/writing-tools-for-agents
发布日期:2025-09-11
Model Context Protocol (MCP) 可以让 LLM 智能体拥有数百个潜在工具,用来解决真实世界任务。但我们该如何让这些工具发挥最大效果?
在本文中,我们会介绍在多种智能体式 AI 系统中提升性能最有效的技术1。
我们会先介绍你如何:
- 构建并测试工具原型
- 使用智能体创建并运行全面的工具评估
- 与 Claude Code 这样的智能体协作,自动提升工具性能
最后,我们会总结一路上识别出的编写高质量工具的关键原则:
- 选择正确的工具来实现(以及不实现)
- 对工具进行命名空间划分,以定义清晰的功能边界
- 从工具向智能体返回有意义的上下文
- 针对 token 效率优化工具响应
- 对工具描述和规格进行提示工程

构建评估可以让你系统性地衡量工具性能。你可以使用 Claude Code 根据该评估自动优化工具。
什么是工具?
在计算机领域,确定性系统在给定相同输入时每次都会产生相同输出,而非确定性系统,例如智能体,即使起始条件相同,也可能生成不同响应。
当我们传统地编写软件时,我们是在确定性系统之间建立契约。例如,像 getWeather(“NYC”) 这样的函数调用,每次被调用时都会以完全相同的方式获取纽约市天气。
工具是一种新型软件,它反映的是确定性系统与非确定性智能体之间的契约。当用户问 "Should I bring an umbrella today?,” 时,智能体可能会调用天气工具,可能会基于常识回答,也可能先询问位置澄清问题。偶尔,智能体可能会幻觉,甚至无法理解如何使用某个工具。
这意味着,为智能体编写软件时,我们需要从根本上重新思考方法:不能像为其他开发者或系统编写函数和 API 那样编写工具和 MCP servers,而需要为智能体设计它们。
我们的目标是扩大智能体可以有效解决任务的范围,让它们能够使用工具追求多种成功策略。幸运的是,根据我们的经验,对智能体最顺手的工具,最终对人类来说也往往出人意料地直观。
如何编写工具
在本节中,我们会介绍如何与智能体协作,既编写工具,也改进你提供给它们的工具。首先快速搭建工具原型,并在本地测试。然后运行全面评估,衡量后续改动效果。与智能体协作时,你可以重复评估和改进工具的过程,直到智能体在真实世界任务上达到强表现。
构建原型
如果不亲自上手,很难预判哪些工具对智能体来说好用,哪些不好用。先快速搭建工具原型。如果你使用 Claude Code 编写工具(甚至可能一次性完成),为 Claude 提供工具所依赖的软件库、API 或 SDK 文档会有帮助,其中也可能包括 MCP SDK。适合 LLM 阅读的文档通常可以在官方文档站点上的扁平 llms.txt 文件中找到(这里是我们的 API 文档)。
将工具封装在本地 MCP 服务器或 Desktop extension(DXT)中,可以让你在 Claude Code 或 Claude Desktop app 中连接并测试工具。
要把本地 MCP 服务器连接到 Claude Code,请运行 claude mcp add <name> <command> [args...]。
要把本地 MCP 服务器或 DXT 连接到 Claude Desktop app,请分别进入 Settings > Developer 或 Settings > Extensions。
工具也可以直接传入 Anthropic API 调用,以进行程序化测试。
亲自测试工具,识别任何粗糙之处。收集用户反馈,围绕你希望工具支持的用例和提示词建立直觉。
运行评估
接下来,你需要运行评估,衡量 Claude 使用工具的效果。先生成大量基于真实世界用法的评估任务。我们建议与智能体协作,帮助分析结果并判断如何改进工具。可以在我们的工具评估 cookbook 中端到端查看这一过程。

我们内部 Slack 工具的留出测试集表现
生成评估任务
有了早期原型后,Claude Code 可以快速探索你的工具,并创建数十组提示词和响应对。提示词应受真实世界用法启发,并基于真实的数据源和服务(例如内部知识库和微服务)。我们建议避免过于简单或表面的「沙盒」环境,因为它们没有足够复杂度来压力测试你的工具。强评估任务可能需要多次工具调用,甚至可能达到几十次。
以下是一些强任务示例:
- 安排下周与 Jane 开会,讨论我们最新的 Acme Corp 项目。附上上一次项目规划会议的笔记,并预订会议室。
- 客户 ID 9182 报告他们在一次购买尝试中被扣款三次。找出所有相关日志条目,并判断是否有其他客户受到同一问题影响。
- 客户 Sarah Chen 刚刚提交取消请求。准备一个挽留方案。判断:(1)她为什么要离开,(2)什么挽留方案最有吸引力,(3)在提出方案前,我们应注意哪些风险因素。
下面是一些较弱的任务:
- 安排下周与 jane@acme.corp 开会。
- 搜索支付日志中的
purchase_complete和customer_id=9182。 - 根据 Customer ID 45892 找到取消请求。
每个评估提示词都应配有可验证的响应或结果。你的验证器可以很简单,例如在标准答案和采样响应之间做精确字符串比较;也可以很高级,例如让 Claude 来判断响应。避免过于严格的验证器,因为它们可能因格式、标点或有效替代表述等无关差异拒绝正确响应。
对于每个提示词-响应对,你也可以选择指定你期望智能体在解决任务时调用哪些工具,以衡量智能体在评估期间是否成功理解每个工具的用途。不过,由于正确解决任务可能存在多条有效路径,请尽量避免过度指定或过拟合某些策略。
运行评估
我们建议通过直接 LLM API 调用,以程序化方式运行评估。使用简单的智能体式循环(while 循环包裹交替的 LLM API 调用和工具调用):每个评估任务一个循环。每个评估智能体都应获得一个单独任务提示词和你的工具。
在评估智能体的系统提示词中,我们建议指示智能体不仅输出结构化响应块(用于验证),也输出推理和反馈块。指示智能体在工具调用和响应块之前输出这些内容,可能会通过触发 chain-of-thought(CoT)行为来提升 LLM 的有效智能。
如果你用 Claude 运行评估,可以开启 interleaved thinking 来获得类似的「开箱即用」功能。这会帮助你探查智能体为什么调用或不调用某些工具,并突出工具描述和规格中需要改进的具体方面。
除了顶层准确率,我们还建议收集其他指标,例如单个工具调用和任务的总运行时间、工具调用总次数、总 token 消耗和工具错误。跟踪工具调用可以揭示智能体追求的常见工作流,并为工具整合提供机会。

我们内部 Asana 工具的留出测试集表现
分析结果 智能体是很有用的伙伴,可以帮助发现问题并提供反馈,范围从矛盾的工具描述,到低效工具实现和令人困惑的工具 schema。不过要记住,智能体在反馈和响应中省略的内容,往往可能比它们包含的内容更重要。LLM 并不总是说出它们真正的意思。
观察智能体在哪里卡住或困惑。阅读评估智能体的推理和反馈(或 CoT),识别粗糙之处。审查原始 transcript(包括工具调用和工具响应),捕捉智能体 CoT 中没有明确描述的任何行为。读出言外之意;记住,你的评估智能体不一定知道正确答案和策略。
分析你的工具调用指标。大量冗余工具调用可能表明需要适当调整分页或 token limit 参数;大量无效参数导致的工具错误可能表明工具需要更清晰的描述或更好的示例。当我们发布 Claude 的网页搜索工具时,我们发现 Claude 会不必要地把 2025 附加到工具的 query 参数中,偏置搜索结果并降低性能(我们通过改进工具描述,把 Claude 引向正确方向)。
与智能体协作
你甚至可以让智能体帮你分析结果并改进工具。只需把评估智能体的 transcript 拼接起来,粘贴到 Claude Code 中。Claude 擅长分析 transcript,并一次性重构大量工具,例如确保在进行新改动时,工具实现和描述仍保持自洽。
事实上,本文中的大多数建议都来自我们用 Claude Code 反复优化内部工具实现的过程。我们的评估建立在内部 workspace 之上,反映了内部工作流的复杂性,包括真实项目、文档和消息。
我们依赖留出测试集,确保没有过拟合到「训练」评估。这些测试集显示,即使在「专家」工具实现之外,我们仍能获得额外性能提升,无论这些工具是由研究人员手动编写,还是由 Claude 自己生成。
下一节中,我们会分享从这个过程中学到的一些经验。
编写有效工具的原则
在本节中,我们将经验提炼为编写有效工具的一些指导原则。
为智能体选择正确工具
更多工具并不总是带来更好结果。我们观察到的一个常见错误是:工具只是包装现有软件功能或 API endpoint,不论这些工具是否适合智能体。这是因为智能体与传统软件有不同的「affordances」,也就是说,它们感知可用工具潜在动作的方式不同。
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-indexed ID 方案),就能通过减少幻觉显著提升 Claude 在检索任务中的精确度。
在某些情况下,智能体可能需要灵活地同时与自然语言和技术标识符输出交互,即便只是为了触发下游工具调用(例如 search_user(name=’jane’) → send_message(id=12345))。你可以通过在工具中暴露一个简单的 response_format enum 参数来同时支持二者,让智能体控制工具返回 “concise” 还是 “detailed” 响应(见下图)。
你可以添加更多格式以获得更大灵活性,类似 GraphQL 中可以精确选择想接收哪些信息。下面是一个用于控制工具响应详细程度的 ResponseFormat enum 示例:
enum ResponseFormat {
DETAILED = "detailed",
CONCISE = "concise"
}
复制
下面是详细工具响应示例(206 个 token):

下面是简洁工具响应示例(72 个 token):

Slack threads 和 thread replies 通过唯一的 thread_ts 标识,而获取 thread replies 需要它。thread_ts 和其他 ID(channel_id、user_id)可以从 “detailed” 工具响应中检索出来,以支持后续需要这些 ID 的工具调用。“concise” 工具响应只返回 thread 内容,并排除 ID。在这个示例中,使用 “concise” 工具响应大约只消耗 1/3 token。
即使是工具响应结构,例如 XML、JSON 或 Markdown,也会影响评估性能:没有一刀切的方案。这是因为 LLM 基于 next-token prediction 训练,通常在符合其训练数据的格式上表现更好。最佳响应结构会因任务和智能体而异。我们鼓励你基于自己的评估选择最佳响应结构。
针对 token 效率优化工具响应
优化上下文质量很重要。但优化工具响应返回给智能体的上下文数量同样重要。
我们建议对任何可能消耗大量上下文的工具响应,实现分页、范围选择、过滤和/或截断的某种组合,并设置合理默认参数值。对于 Claude Code,我们默认将工具响应限制为 25,000 个 token。我们预计智能体的有效上下文长度会随时间增长,但对上下文高效工具的需求仍会保留。
如果你选择截断响应,请确保用有帮助的指令引导智能体。你可以直接鼓励智能体采用更节省 token 的策略,例如在知识检索任务中进行许多小而精准的搜索,而不是一次宽泛搜索。类似地,如果工具调用抛出错误(例如在输入验证期间),你可以对错误响应进行提示工程,清楚传达具体且可执行的改进建议,而不是返回不透明错误码或 traceback。
下面是一个截断工具响应示例:

下面是一个没有帮助的错误响应示例:

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

工具截断和错误响应可以引导智能体采用更节省 token 的工具使用行为(使用过滤器或分页),或给出正确格式化工具输入的示例。
对工具描述进行提示工程
现在来到提升工具效果的最有效方法之一:对工具描述和规格进行提示工程。因为这些内容会被加载到智能体上下文中,所以它们可以共同引导智能体形成有效的工具调用行为。
编写工具描述和规格时,想想你会如何向团队新成员描述这个工具。考虑你可能隐含带入的上下文,例如专门查询格式、小众术语定义、底层资源之间的关系,并把它显式写出。通过清楚描述期望输入和输出,并用严格数据模型强制执行,来避免歧义。尤其是,输入参数应命名明确:不要使用名为 user 的参数,尝试使用名为 user_id 的参数。
借助评估,你可以更有信心地衡量提示工程的影响。即使是对工具描述的小幅改进,也可能带来显著提升。我们对工具描述进行精确改进后,Claude Sonnet 3.5 在 SWE-bench Verified 评估中达到最先进表现,大幅降低错误率并提升任务完成度。
你可以在我们的 Developer Guide 中找到更多工具定义最佳实践。如果你在为 Claude 构建工具,我们也建议阅读工具如何被动态加载到 Claude 的系统提示词中。最后,如果你为 MCP 服务器编写工具,tool annotations 有助于披露哪些工具需要外部世界访问权限,或会做出破坏性更改。
展望未来
要为智能体构建有效工具,我们需要将软件开发实践从可预测的确定性模式,转向非确定性模式。
通过本文描述的迭代式、评估驱动流程,我们识别出让工具成功的一致模式:有效工具有意且清晰地定义,审慎使用智能体上下文,可以在多样化工作流中组合,并让智能体直观地解决真实世界任务。
未来,我们预计智能体与世界交互的具体机制会继续演进,从 MCP 协议更新,到底层 LLM 本身升级。通过系统性的、评估驱动的方法来改进智能体工具,我们可以确保随着智能体能力增强,它们使用的工具也会同步演进。
致谢
作者: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)的同事们作出的宝贵贡献。
1 除了训练底层 LLM 本身之外。
想了解更多?
探索课程