为 AI 代理编写高效工具——与代理一起写¶
- 原文链接:https://www.anthropic.com/engineering/writing-tools-for-agents [65]
- 发布时间:2025-09-11
- 作者:Ken Aizawa
代理的能力取决于我们给它的工具。我们分享如何写好工具与评测,并用 Claude 自动优化工具表现。[65]
Model Context Protocol (MCP) 让 LLM 代理可以接入数百个工具完成真实任务。但如何让这些工具“对代理最有效”?[65]
本文总结了我们在多种代理系统中提升性能的有效方法。[65]
首先,我们会覆盖以下内容:[65]
- 构建并测试工具原型
- 用代理运行全面评测
- 与 Claude Code 合作自动提升工具表现
随后总结出高质量工具的关键原则:[65]
- 选择应当实现的工具(以及不应实现的工具)
- 用命名空间清晰划分工具边界
- 从工具返回有意义的上下文
- 优化工具响应的 token 效率
- 对工具描述与规格进行提示工程

图注:构建评测可系统衡量工具表现,并用 Claude Code 自动优化工具。[65]
什么是工具?¶
在计算中,确定性系统在相同输入下总是输出相同结果;而非确定性系统(如代理)即使起点相同也可能给出不同响应。[65]
传统软件开发是在确定性系统之间建立契约。例如 getWeather("NYC") 每次都会以同样方式获取纽约天气。[65]
工具是一类新的软件:它是确定性系统与非确定性代理之间的契约。当用户问“今天要带伞吗?”,代理可能调用天气工具、用常识回答,或先问地点。代理也可能幻觉或不会用工具。[65]
这要求我们重构开发思路:不要像为开发者写 API 那样写工具与 MCP servers,而要为代理设计工具。[65]
我们的目标是通过工具扩大代理解决问题的有效范围。幸运的是,最适合代理的工具,对人类来说也往往直观易用。[65]
如何编写工具¶
本节介绍如何与代理一起编写、改进工具。流程是:先快速搭原型并本地测试,再用全面评测衡量改动,与代理协作不断优化,直到在真实任务上表现稳健。[65]
构建原型¶
在未上手之前,很难预判代理会觉得哪些工具顺手。先搭一个原型并亲自测试。[65]
如果你用 Claude Code 写工具(甚至一发),建议提供它所需的库、API 或 SDK 文档(可能包含 MCP SDK)。LLM 友好的文档常见于官方站点的 llms.txt(例如我们的 API)。[65]
把工具包在 本地 MCP server 或 Desktop extension(DXT)里,就能在 Claude Code 或 Claude Desktop 中连接测试。[65]
- 将本地 MCP server 连接到 Claude Code:
claude mcp add <name> <command> [args...] - 将本地 MCP server 或 DXT 连接到 Claude Desktop:
Settings > Developer或Settings > Extensions
工具也可以直接传给 Anthropic API 做程序化测试。[65]
亲自测试工具,找出“手感不好”的地方;收集用户反馈,建立对工具使用场景与典型提示的直觉。[65]
运行评测¶
下一步是评估 Claude 对工具的使用质量。先生成大量贴近真实使用的评测任务,并与代理合作分析结果、改进工具。可参考我们的 tool evaluation cookbook。[65]

图注:内部 Slack 工具在留出测试集上的表现。[65]
生成评测任务¶
基于早期原型,Claude Code 可以快速探索工具并生成几十对 prompt/response。任务应来自真实场景,并基于真实数据与服务(如内部知识库、微服务)。避免过于简单的“沙盒”任务,无法充分压测复杂性。强任务往往需要多次工具调用,甚至几十次。[65]
强任务示例:[65]
- 为下周安排与 Jane 的会议讨论 Acme Corp 项目,附上上次项目规划会议笔记并预订会议室。
- 客户 ID 9182 报告一次购买被重复扣费三次。查找相关日志,判断是否影响其他客户。
- 客户 Sarah Chen 刚提交取消请求,请准备留存方案,确定:(1) 离开原因,(2) 最有说服力的留存 offer,(3) 可能风险。
弱任务示例:[65]
- 下周安排与 jane@acme.corp 的会议。
- 在支付日志中搜索
purchase_complete与customer_id=9182。 - 按客户 ID 45892 查取消请求。
每个评测 prompt 都应配有可验证的响应/结果。验证器可以是简单的字符串比对,也可以让 Claude 当裁判。避免过于严格的验证器(比如因格式、标点或等价表达而拒绝正确答案)。[65]
你也可以为每个任务指定“期望使用的工具”,衡量代理是否理解工具用途。但由于可能存在多条正确路径,不要过度指定或过拟合策略。[65]
运行评测¶
建议用 API 程序化运行评测:使用简单的代理循环(while 循环交替 LLM API 与工具调用),每个任务一个循环。评测代理只需一个任务提示与工具集。[65]
在评测代理的系统提示中,建议输出结构化的“结果块”,并输出 reasoning 与 feedback。让代理在工具调用前输出 reasoning/feedback,可能触发 CoT 行为并提升有效智能。[65]
如果使用 Claude,可打开 interleaved thinking,帮助你理解代理为何调用/不调用某些工具,并定位工具描述与规格的改进点。[65]
除了准确率,还建议追踪工具调用总耗时、任务耗时、调用次数、token 消耗、工具错误等指标。工具调用统计可揭示常见工作流,并提示合并工具的机会。[65]

图注:内部 Asana 工具在留出测试集上的表现。[65]
分析结果¶
代理是发现问题与反馈的好伙伴,但注意:它们“没说的”往往比说的更重要。LLM 并不总是 言出即心。[65]
观察代理在哪里卡住或困惑,阅读其 reasoning/feedback(或 CoT)找出粗糙点。再回看完整记录(含工具调用与响应)捕捉 CoT 未明确提到的行为。读出弦外之音:评测代理并不总知道正确答案与策略。[65]
分析工具调用指标:如果有大量冗余调用,可能需要调整分页或 token 限制;如果参数错误多,可能需要更清晰的描述或更好的示例。我们在发布 Claude 的 web search tool 时发现 Claude 会无意义地在查询参数里追加 2025,导致偏置与性能下降——我们通过改进工具描述引导其纠正。[65]
与代理协作¶
你也可以直接让代理帮你改工具:把评测代理的完整对话记录拼接后粘给 Claude Code。Claude 擅长批量分析记录并重构工具实现与描述,保持一致性。[65]
实际上,本文大部分建议来自我们用 Claude Code 反复优化内部工具实现。评测建立在内部工作流之上,涵盖真实项目、文档与消息。[65]
我们使用留出测试集以避免对“训练评测”过拟合。这些测试集显示,即便工具已由研究员手写或 Claude 生成,我们仍可通过优化提取额外性能提升。[65]
接下来我们分享从这个过程总结的原则。[65]
编写高效工具的原则¶
选择“正确”的工具¶
更多工具不一定更好。常见错误是把现有软件功能或 API 直接包成工具,不管是否适合代理。因为代理拥有不同的“可供性”(affordances),它们与传统软件的感知与操作方式不同。[65]
LLM 代理上下文有限,而计算机内存廉价充足。以通讯录为例:传统软件可以逐条遍历列表;但若代理调用一个返回全部联系人的工具,它需要逐条读 token——这浪费上下文。更自然的方式是先跳到相关页(如按字母查找)。[65]
我们建议针对高影响工作流构建少量“思考过的”工具,匹配评测任务,然后逐步扩展。例如通讯录场景,你可能该实现 search_contacts 或 message_contact,而不是 list_contacts。[65]
工具还可以合并功能:在内部串联多个操作或 API,让一次调用完成多步流程。例如:[65]
- 不要分别实现
list_users、list_events、create_event,改为实现schedule_event自动找空档并创建会议。 - 不要实现
read_logs,改为search_logs只返回相关日志与上下文。 - 不要实现
get_customer_by_id、list_transactions、list_notes,改为get_customer_context一次返回客户最新关键信息。
确保每个工具都有清晰、独特的目的。工具应让代理像人类一样拆解任务,同时减少中间输出对上下文的消耗。过多或功能重叠的工具会干扰代理效率。谨慎规划“做哪些工具、哪些不做”非常重要。[65]
为工具建立命名空间¶
AI 代理可能接触几十个 MCP server、上百种工具。当工具功能重叠或用途含糊时,代理会困惑。命名空间(按共同前缀组织工具)可清晰划分边界;MCP client 有时会默认这样做。[65]
例如按服务命名:asana_search、jira_search;按资源细分:asana_projects_search、asana_users_search。命名前后缀方式对评测表现影响显著,效果因模型不同而异,建议基于自身评测选择。[65]
代理可能调用错工具、参数错误、调用次数不足或错误处理响应。通过“符合自然任务拆分”的工具命名,你既减少了上下文内工具数量,也把代理计算从上下文迁移到工具调用本身,从而降低错误风险。[65]
从工具返回有意义的上下文¶
工具实现应只返回高信号信息,优先相关性而不是灵活性,避免低层技术 ID(如 uuid、256px_image_url、mime_type)。name、image_url、file_type 等更能直接支持代理后续决策。[65]
代理比起加密 ID,更擅长处理自然语言名称。我们发现,仅将 UUID 转为更具语义的语言(甚至 0-index ID),就能显著提高检索任务准确率并减少幻觉。[65]
在某些情况下,代理需要同时使用自然语言与技术 ID(例如 search_user(name='jane') → send_message(id=12345))。你可以通过 response_format 枚举让代理选择 “concise” 或 “detailed” 响应(见下图)。[65]
你也可以提供更多格式以增强灵活性,类似 GraphQL 让模型选择需要的字段。示例枚举:[65]
enum ResponseFormat {
DETAILED = "detailed",
CONCISE = "concise"
}
下面是 detailed 与 concise 的示例(原文示意):[65]

图注:Slack 线程与回复由 thread_ts 标识;detailed 响应包含 thread_ts、channel_id、user_id 以支持后续调用;concise 只返回内容,token 约为三分之一。[65]
响应结构(XML/JSON/Markdown)也会影响评测表现。没有一刀切的最佳格式,因为 LLM 更擅长训练数据中常见的格式。最佳结构取决于任务与代理,建议基于评测选择。[65]
优化工具响应的 token 效率¶
优化上下文质量重要,但数量也同样重要。[65]
建议为可能返回大量上下文的工具实现分页、范围选择、过滤或截断,并设定合理默认值。Claude Code 默认将工具响应限制在 25,000 token;未来上下文会变长,但对高效工具的需求不会消失。[65]
如果选择截断响应,请用清晰指令引导代理。例如鼓励“多次小范围检索”而非“一次大范围检索”。当工具调用报错(如输入校验失败),错误响应也应是可执行的建议,而非晦涩的错误码或堆栈。[65]

图注:原文未提供图注。[65]

图注:原文未提供图注。[65]

图注:原文未提供图注。[65]

图注:工具截断与错误响应可引导代理采用过滤/分页等更高效策略,也能示范正确输入格式。[65]
对工具描述进行提示工程¶
最有效的优化之一:对工具描述与规格进行提示工程。因为它们会加载进上下文,从而引导代理的工具调用行为。[65]
写描述时,把它当作给团队新人讲解工具:明确你习惯的查询格式、术语定义、底层资源关系等。用严格的数据模型避免歧义,尤其输入参数应命名清晰:与其叫 user,不如叫 user_id。[65]
评测让你能更自信地衡量提示工程影响。微小调整也可能带来巨大提升。我们对工具描述做精确改进后,Claude Sonnet 3.5 在 SWE-bench Verified 上达到 SOTA,错误率显著降低、任务完成度大幅提升。[65]
更多工具定义最佳实践见 Developer Guide。如果你为 Claude 构建工具,也推荐阅读工具如何动态加载进 Claude 的 system prompt。如果你为 MCP server 写工具,可用 tool annotations 说明哪些工具需要开放世界访问或可能破坏性操作。[65]
展望¶
要让代理有效,我们必须把软件开发实践从“确定性模式”转向“非确定性模式”。[65]
通过迭代、评测驱动的过程,我们总结出高效工具的共同模式:工具应清晰定义、谨慎使用上下文、可在多种工作流中组合、且能让代理直观解决真实问题。[65]
未来,代理与世界交互的机制会持续演进(从 MCP 协议到 LLM 本身)。只要保持系统化、评测驱动的方法,工具将与代理能力同步进化。[65]
致谢¶
本文由 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)的贡献。[65]
- 超越对底层 LLM 的训练本身。[65]