获取开发者通讯
产品更新、操作指南、社区聚焦等更多内容。每月发送至您的收件箱。
模型上下文协议(MCP)可以为 LLM 智能体提供可能多达数百个工具,以解决现实世界的任务。但我们如何让这些工具发挥最大效用?
在本文中,我们描述了在各种智能体 AI 系统1中提升性能的最有效技术。
我们首先介绍如何:
最后,我们总结了在此过程中发现的高质量工具编写关键原则:
在计算领域,确定性系统在给定相同输入时每次产生相同的输出,而非确定性系统——如智能体——即使在相同的起始条件下也可能产生不同的响应。
当我们传统地编写软件时,我们是在确定性系统之间建立一种契约。例如,像 getWeather("NYC")
这样的函数调用,每次被调用时都会以完全相同的方式获取纽约市的天气。
工具是一种新型软件,它反映了确定性系统与非确定性智能体之间的契约。当用户问“我今天应该带伞吗?”,智能体可能会调用天气工具、根据常识回答,甚至先询问关于位置的澄清问题。有时,智能体可能会产生幻觉,甚至无法理解如何使用某个工具。
这意味着在为智能体编写软件时,我们需要从根本上重新思考我们的方法:不是像为其他开发者或系统编写函数和 API 那样编写工具和 MCP 服务器,而是需要为智能体设计它们。
我们的目标是通过使用工具追求各种成功策略,扩大智能体在解决广泛任务中能够有效发挥作用的范围。幸运的是,根据我们的经验,对智能体来说最“符合人体工程学”的工具,最终对人类来说也出乎意料地直观易懂。
在本节中,我们描述如何与智能体协作,既编写也改进你提供给它们的工具。首先搭建工具的快速原型并在本地测试。接下来,运行全面的评估来衡量后续的变更。与智能体一起工作,你可以重复评估和改进工具的过程,直到你的智能体在现实世界任务中达到强劲的性能。
如果不亲自动手,很难预判哪些工具智能体会觉得符合人体工程学,哪些不会。首先搭建工具的快速原型。如果你使用 Claude Code 来编写工具(可能是一次性完成),为 Claude 提供你的工具所依赖的任何软件库、API 或 SDK(可能包括 MCP SDK)的文档会很有帮助。对 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 使用您的工具的效果。首先,生成大量基于真实世界用途的评估任务。我们建议与代理合作,帮助分析您的结果并确定如何改进您的工具。在我们的工具评估 cookbook中查看这个过程的端到端示例。
生成评估任务
有了您的早期原型,Claude Code 可以快速探索您的工具并创建数十个提示和响应对。提示应受真实世界用途启发,并基于现实的数据源和服务(例如,内部知识库和微服务)。我们建议您避免过于简单或肤浅的“沙盒”环境,这些环境没有以足够的复杂性对您的工具进行压力测试。强大的评估任务可能需要多次工具调用——可能数十次。
以下是一些强大任务的示例:
以下是一些较弱任务的示例:
purchase_complete
和 customer_id=9182
。每个评估提示都应与可验证的响应或结果配对。您的验证器可以简单到对真实值和采样响应进行精确字符串比较,也可以高级到让 Claude 来评判响应。避免过于严格的验证器,因为格式、标点或有效的替代措辞等虚假差异而拒绝正确的响应。
对于每个提示-响应对,您还可以可选地指定您期望代理在解决任务时调用的工具,以衡量代理在评估期间是否成功掌握了每个工具的目的。然而,由于解决任务可能有多种有效路径,请尽量避免过度指定或过度拟合策略。
运行评估
我们建议使用直接 LLM API 调用以程序化方式运行您的评估。使用简单的代理循环(while
循环包裹交替的 LLM API 和工具调用):每个评估任务一个循环。每个评估代理应被给予单个任务提示和您的工具。
在您的评估代理的系统提示中,我们建议指示代理不仅输出结构化响应块(用于验证),还输出推理和反馈块。指示代理在工具调用和响应块之前输出这些内容,可能通过触发思维链(CoT)行为来增加 LLM 的有效智能。
如果您使用 Claude 运行评估,您可以开启交错思考以获得类似的功能“现成可用”。这将帮助您探究代理为什么调用或不调用某些工具,并突出工具描述和规格中的具体改进领域。
除了顶层准确率之外,我们建议收集其他指标,例如单个工具调用和任务的总运行时间、工具调用的总次数、总令牌消耗以及工具错误。跟踪工具调用有助于揭示智能体所追求的常见工作流程,并为工具整合提供一些机会。
分析结果
智能体是您发现问题的得力伙伴,并能就各种问题提供反馈,从相互矛盾的工具描述到低效的工具实现以及令人困惑的工具模式。然而,请记住,智能体在反馈和响应中省略的内容往往比包含的内容更重要。LLM 并不总是言为心声。
观察您的智能体在哪里卡住或困惑。阅读评估智能体的推理和反馈(或思维链)以识别粗糙之处。查看原始记录(包括工具调用和工具响应)以捕捉智能体思维链中未明确描述的任何行为。读懂言外之意;记住,您的评估智能体不一定知道正确答案和策略。
分析您的工具调用指标。大量冗余的工具调用可能表明需要对分页或令牌限制参数进行一些合理调整;大量因无效参数导致的工具错误可能表明工具可以使用更清晰的描述或更好的示例。当我们推出 Claude 的网络搜索工具时,我们发现 Claude 不必要地在工具的 query 参数后附加 2025,这使搜索结果产生偏差并降低了性能(我们通过改进工具描述将 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):
以下是一个简洁的工具响应示例(72 个 token):
thread_ts
这是获取线程回复所必需的。thread_ts
和其他 ID(channel_id
、user_id
)可以从 “detailed”
工具响应中获取,以便支持需要这些信息的后续工具调用。“concise”
工具响应只返回线程内容,不包含 ID。在此示例中,使用 “concise”
工具响应时,我们只用了约 ⅓ 的 token。即便是工具响应的结构——例如 XML、JSON 或 Markdown——也会影响评估性能:没有放之四海而皆准的解决方案。这是因为 LLM 是基于下一 token 预测训练的,往往在与其训练数据匹配的格式上表现更好。最佳响应结构因任务和智能体而异。我们鼓励你根据自己的评估来选择最佳响应结构。
优化上下文质量很重要。但优化工具响应中返回给智能体的上下文数量同样重要。
我们建议对任何可能占用大量上下文的工具响应,实施分页、范围选择、过滤和/或截断的某种组合,并设置合理的默认参数值。对于 Claude Code,我们默认将工具响应限制在 25,000 个 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 本身之外。
产品更新、操作指南、社区聚焦等。每月发送到你的收件箱。
