Claude 开发者平台高级工具使用介绍

本文翻译自 Anthropic 官方博客:Introducing advanced tool use on the Claude Developer Platform

译者注:本文介绍了 Claude Agent 开发中工具使用的三个重要高级功能。

AI Agent 的未来是模型可以在数百或数千个工具上无缝工作。一个集成 git 操作、文件操作、包管理器、测试框架和部署流水线的 IDE 助手。一个同时连接 Slack、GitHub、Google Drive、Jira、公司数据库和数十个 MCP 服务器的运营协调器。

要构建高效的 Agent,它们需要使用无限的工具库,而无需预先将每个定义都填入上下文。我们关于使用 MCP 代码执行的文章讨论了工具结果和定义有时如何在 Agent 读取请求之前消耗 50,000+ 个 token。Agent 应该按需发现和加载工具,只保留与当前任务相关的内容。

Agent 还需要能够从代码中调用工具。当使用自然语言工具调用时,每次调用都需要完整的推理过程,而且中间结果无论是否有用都会堆积在上下文中。代码是编排逻辑的自然选择,例如循环、条件句和数据转换。Agent 需要根据手头的任务灵活地在代码执行和推理之间做出选择。

Agent 还需要从示例中学习正确的工具使用,而不仅仅是模式定义。JSON 模式定义了结构上有效的内容,但无法表达使用模式:何时包含可选参数、哪些组合有意义,或你的 API 期望什么约定。

今天,我们发布了使这成为可能的三个功能:

  • 工具搜索工具(Tool Search Tool),允许 Claude 使用搜索工具访问数千个工具,而无需消耗其上下文窗口
  • 程序化工具调用(Programmatic Tool Calling),允许 Claude 在代码执行环境中调用工具,减少对模型上下文窗口的影响
  • 工具使用示例(Tool Use Examples),提供展示如何有效使用给定工具的通用标准

在内部测试中,我们发现这些功能帮助我们构建了使用传统工具使用模式无法实现的东西。例如,Excel 版 Claude使用程序化工具调用来读取和修改具有数千行的电子表格,而不会使模型的上下文窗口过载。

基于我们的经验,我们认为这些功能为使用 Claude 可以构建的内容开辟了新的可能性。

工具搜索工具

挑战

MCP 工具定义提供了重要的上下文,但随着更多服务器的连接,这些 token 会累积。考虑一个五服务器设置:

  • GitHub:35 个工具(~26K token)
  • Slack:11 个工具(~21K token)
  • Sentry:5 个工具(~3K token)
  • Grafana:5 个工具(~3K token)
  • Splunk:2 个工具(~2K token)

这是 58 个工具在对话开始之前消耗大约 55K token。添加更多服务器如 Jira(仅它就使用 ~17K token),你很快就接近 100K+ token 开销。在 Anthropic,我们看到工具定义在优化之前消耗了 134K token。

但 token 成本不是唯一的问题。最常见的失败是错误的工具选择和错误的参数,尤其是当工具有类似的名称如 notification-send-user vs notification-send-channel

我们的解决方案

工具搜索工具不是预先加载所有工具定义,而是按需发现工具。Claude 只看到它当前任务实际需要的工具。

工具搜索工具图

与 Claude 传统方法使用的 122,800 token 相比,工具搜索工具保留了 191,300 token 的上下文。

传统方法:

  • 所有工具定义预先加载(50+ MCP 工具约 72K token)
  • 对话历史和系统提示竞争剩余空间
  • 总上下文消耗:任何工作开始前约 77K token

使用工具搜索工具:

  • 只预先加载工具搜索工具(约 500 token)
  • 工具按需发现(3-5 个相关工具,约 3K token)
  • 总上下文消耗:约 8.7K token,保留 95% 的上下文窗口

这代表了在保持对完整工具库访问的同时,token 使用量减少了 85%。内部测试显示,在使用大型工具库时,MCP 评估的准确性显著提高。Opus 4 从 49% 提高到 74%,Opus 4.5 从 79.5% 提高到 88.1%。

工具搜索工具的工作原理

工具搜索工具让 Claude 动态发现工具,而不是预先加载所有定义。你向 API 提供所有工具定义,但用 defer_loading: true 标记工具以使其按需可发现。延迟的工具最初不会加载到 Claude 的上下文中。Claude 只看到工具搜索工具本身加上任何具有 defer_loading: false 的工具(你最重要、最常用的工具)。

当 Claude 需要特定功能时,它会搜索相关工具。工具搜索工具返回匹配工具的引用,这些引用会在 Claude 的上下文中扩展为完整定义。

例如,如果 Claude 需要与 GitHub 交互,它会搜索"github",只有 github.createPullRequestgithub.listIssues 被加载——而不是你来自 Slack、Jira 和 Google Drive 的其他 50+ 工具。

这样,Claude 可以访问你的完整工具库,同时只为它实际需要的工具支付 token 成本。

提示缓存说明: 工具搜索工具不会破坏提示缓存,因为延迟的工具完全从初始提示中排除。它们只有在 Claude 搜索它们后才被添加到上下文中,所以你的系统提示和核心工具定义仍然可缓存。

实现:

{
  "tools": [
    // 包括一个工具搜索工具(regex、BM25 或自定义)
    {"type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex"},

    // 标记工具以供按需发现
    {
      "name": "github.createPullRequest",
      "description": "Create a pull request",
      "input_schema": {...},
      "defer_loading": true
    }
    // ... 数百个更多带有 defer_loading: true 的延迟工具
  ]
}

对于 MCP 服务器,你可以延迟加载整个服务器,同时保持特定的高使用工具加载:

{
  "type": "mcp_toolset",
  "mcp_server_name": "google-drive",
  "default_config": {"defer_loading": true}, // 延迟加载整个服务器
  "configs": {
    "search_files": {
      "defer_loading": false
    }  // 保持最常用的工具加载
  }
}

Claude 开发者平台提供了开箱即用的基于 regex 和 BM25 的搜索工具,但你也可以使用嵌入或其他策略实现自定义搜索工具。

何时使用工具搜索工具

像任何架构决策一样,启用工具搜索工具涉及权衡。该功能在工具调用之前添加了一个搜索步骤,因此当上下文节省和准确性改进超过额外延迟时,它提供最佳 ROI。

在以下情况使用:

  • 工具定义消耗 >10K token
  • 遇到工具选择准确性问题
  • 构建具有多个服务器的 MCP 驱动系统
  • 有 10+ 个可用工具

不太有益于:

  • 小型工具库(< 10 个工具)
  • 所有工具在每个会话中频繁使用
  • 工具定义紧凑

程序化工具调用

挑战

随着工作流变得更加复杂,传统工具调用会产生两个基本问题:

  • 来自中间结果的上下文污染: 当 Claude 分析 10MB 日志文件以查找错误模式时,整个文件进入其上下文窗口,即使 Claude 只需要错误频率的摘要。当跨多个表获取客户数据时,每条记录无论相关性如何都会在上下文中累积。这些中间结果消耗大量 token 预算,并可能将重要信息完全推到上下文窗口之外。
  • 推理开销和手动综合: 每个工具调用都需要完整的模型推理过程。接收结果后,Claude 必须通过"眼动"提取相关信息,推理各部分如何组合,并决定下一步做什么——所有这些都通过自然语言处理。五个工具的工作流意味着五次推理过程加上 Claude 解析每个结果、比较值和综合结论。这既慢又容易出错。

我们的解决方案

程序化工具调用使 Claude 能够通过代码而不是通过单独的 API 往返来编排工具。Claude 不是一次请求一个工具,每个结果都返回到其上下文,而是编写调用多个工具、处理其输出并控制什么信息实际进入其上下文窗口的代码。

Claude 擅长编写代码,通过让它用 Python 而不是自然语言工具调用来表达编排逻辑,你会获得更可靠、精确的控制流。循环、条件句、数据转换和错误处理在代码中都是显式的,而不是隐含在 Claude 的推理中。

示例:预算合规检查

考虑一个常见的业务任务:"哪些团队成员超出了他们的 Q3 差旅预算?"

你有三个可用工具:

  • get_team_members(department) - 返回团队成员列表,包含 ID 和级别
  • get_expenses(user_id, quarter) - 返回用户的费用行项目
  • get_budget_by_level(level) - 返回员工级别的预算限制

传统方法:

  • 获取团队成员 → 20 人
  • 对每个人,获取他们的 Q3 费用 → 20 次工具调用,每次返回 50-100 个行项目(航班、酒店、餐费、收据)
  • 按员工级别获取预算限制
  • 所有这些进入 Claude 的上下文:2,000+ 费用行项目(50 KB+)
  • Claude 手动汇总每个人的费用,查找他们的预算,将费用与预算限制进行比较
  • 更多的往返模型,大量上下文消耗

使用程序化工具调用:

不是每个工具结果都返回给 Claude,Claude 编写编排整个工作流的 Python 脚本。脚本在代码执行工具(沙箱环境)中运行,当它需要你的工具结果时暂停。当你通过 API 返回工具结果时,它们由脚本处理而不是由模型消耗。脚本继续执行,Claude 只看到最终输出。

程序化工具调用流程

程序化工具调用使 Claude 能够通过代码而不是通过单独的 API 往返来编排工具,允许并行工具执行。

以下是 Claude 的预算合规任务编排代码:

team = await get_team_members("engineering")

# 获取每个唯一级别的预算
levels = list(set(m["level"] for m in team))
budget_results = await asyncio.gather(*[
    get_budget_by_level(level) for level in levels
])

# 创建查找字典:{"junior": budget1, "senior": budget2, ...}
budgets = {level: budget for level, budget in zip(levels, budget_results)}

# 并行获取所有费用
expenses = await asyncio.gather(*[
    get_expenses(m["id"], "Q3") for m in team
])

# 查找超出差旅预算的员工
exceeded = []
for member, exp in zip(team, expenses):
    budget = budgets[member["level"]]
    total = sum(e["amount"] for e in exp)
    if total > budget["travel_limit"]:
        exceeded.append({
            "name": member["name"],
            "spent": total,
            "limit": budget["travel_limit"]
        })

print(json.dumps(exceeded))

Claude 的上下文只接收最终结果:超出预算的两三个人。2,000+ 行项目、中间总和和预算查找不会影响 Claude 的上下文,将消耗从 200KB 的原始费用数据减少到仅 1KB 的结果。

效率收益是显著的:

  • Token 节省: 通过保持中间结果不在 Claude 的上下文中,PTC 显著减少了 token 消耗。在复杂研究任务上,平均使用从 43,588 下降到 27,297 token,减少了 37%。
  • 减少延迟: 每个 API 往返都需要模型推理(几百毫秒到几秒)。当 Claude 在单个代码块中编排 20+ 工具调用时,你消除了 19+ 次推理过程。API 处理工具执行,而无需每次都返回模型。
  • 提高准确性: 通过编写显式编排逻辑,Claude 比在自然语言中处理多个工具结果时犯的错误更少。内部知识检索从 25.6% 提高到 28.5%;GIA 基准从 46.5% 提高到 51.2%。

生产工作流涉及混乱的数据、条件逻辑和需要扩展的操作。程序化工具调用让 Claude 以编程方式处理这种复杂性,同时保持其专注于可操作的结果而不是原始数据处理。

程序化工具调用的工作原理

1. 将工具标记为可从代码调用

向工具添加 code_execution,并设置 allowed_callers 以选择加入程序化执行:

{
  "tools": [
    {
      "type": "code_execution_20250825",
      "name": "code_execution"
    },
    {
      "name": "get_team_members",
      "description": "Get all members of a department...",
      "input_schema": {...},
      "allowed_callers": ["code_execution_20250825"] // 选择加入程序化工具调用
    },
    {
      "name": "get_expenses",
      ...
    },
    {
      "name": "get_budget_by_level",
      ...
    }
  ]
}

API 将这些工具定义转换为 Claude 可以调用的 Python 函数。

2. Claude 编写编排代码

不是一次请求一个工具,Claude 生成 Python 代码:

{
  "type": "server_tool_use",
  "id": "srvtoolu_abc",
  "name": "code_execution",
  "input": {
    "code": "team = get_team_members('engineering')\n..." // 上面的代码示例
  }
}

3. 工具执行而不影响 Claude 的上下文

当代码调用 get_expenses() 时,你会收到一个带有 caller 字段的工具请求:

{
  "type": "tool_use",
  "id": "toolu_xyz",
  "name": "get_expenses",
  "input": {"user_id": "emp_123", "quarter": "Q3"},
  "caller": {
    "type": "code_execution_20250825",
    "tool_id": "srvtoolu_abc"
  }
}

你提供结果,结果在代码执行环境中处理而不是在 Claude 的上下文中。此请求-响应周期对代码中的每个工具调用重复。

4. 只有最终输出进入上下文

当代码完成运行时,只有代码的结果返回给 Claude:

{
  "type": "code_execution_tool_result",
  "tool_use_id": "srvtoolu_abc",
  "content": {
    "stdout": "[{\"name\": \"Alice\", \"spent\": 12500, \"limit\": 10000}...]"
  }
}

这就是 Claude 看到的全部,而不是沿途处理的 2000+ 费用行项目。

何时使用程序化工具调用

程序化工具调用向你的工作流添加了一个代码执行步骤。当 token 节省、延迟改进和准确性收益显著时,这个额外开销是值得的。

最有助于:

  • 处理大型数据集,你只需要聚合或摘要
  • 运行具有三个或更多依赖工具调用的多步骤工作流
  • 在 Claude 看到之前过滤、排序或转换工具结果
  • 处理中间数据不应影响 Claude 推理的任务
  • 跨许多项目运行并行操作(例如,检查 50 个端点)

不太有益于:

  • 进行简单的单工具调用
  • 处理 Claude 应该看到并推理所有中间结果的任务
  • 运行具有小响应的快速查找

工具使用示例

挑战

JSON Schema 擅长定义结构——类型、必需字段、允许的枚举——但它无法表达使用模式:何时包含可选参数、哪些组合有意义,或你的 API 期望什么约定。

考虑一个支持票据 API:

{
  "name": "create_ticket",
  "input_schema": {
    "properties": {
      "title": {"type": "string"},
      "priority": {"enum": ["low", "medium", "high", "critical"]},
      "labels": {"type": "array", "items": {"type": "string"}},
      "reporter": {
        "type": "object",
        "properties": {
          "id": {"type": "string"},
          "name": {"type": "string"},
          "contact": {
            "type": "object",
            "properties": {
              "email": {"type": "string"},
              "phone": {"type": "string"}
            }
          }
        }
      },
      "due_date": {"type": "string"},
      "escalation": {
        "type": "object",
        "properties": {
          "level": {"type": "integer"},
          "notify_manager": {"type": "boolean"},
          "sla_hours": {"type": "integer"}
        }
      }
    },
    "required": ["title"]
  }
}

模式定义了什么是有效的,但留下了关键问题未回答:

  • 格式歧义: due_date 应该使用"2024-11-06"、"Nov 6, 2024"还是"2024-11-06T00:00:00Z"?
  • ID 约定: reporter.id 是 UUID、"USR-12345"还是仅仅是"12345"?
  • 嵌套结构使用: Claude 应该何时填充 reporter.contact
  • 参数相关性: escalation.levelescalation.sla_hours 如何与 priority 相关?

这些歧义可能导致工具调用格式错误和参数使用不一致。

我们的解决方案

工具使用示例让你可以直接在工具定义中提供示例工具调用。而不是仅依赖模式,你向 Claude 展示具体的使用模式:

{
  "name": "create_ticket",
  "input_schema": { /* 与上面相同的模式 */ },
  "input_examples": [
    {
      "title": "Login page returns 500 error",
      "priority": "critical",
      "labels": ["bug", "authentication", "production"],
      "reporter": {
        "id": "USR-12345",
        "name": "Jane Smith",
        "contact": {
          "email": "jane@acme.com",
          "phone": "+1-555-0123"
        }
      },
      "due_date": "2024-11-06",
      "escalation": {
        "level": 2,
        "notify_manager": true,
        "sla_hours": 4
      }
    },
    {
      "title": "Add dark mode support",
      "labels": ["feature-request", "ui"],
      "reporter": {
        "id": "USR-67890",
        "name": "Alex Chen"
      }
    },
    {
      "title": "Update API documentation"
    }
  ]
}

从这三个示例中,Claude 学到:

  • 格式约定: 日期使用 YYYY-MM-DD,用户 ID 遵循 USR-XXXXX,标签使用 kebab-case
  • 嵌套结构模式: 如何构建具有嵌套联系对象的 reporter 对象
  • 可选参数相关性: 关键错误有完整的联系信息 + 升级和严格的 SLA;功能请求有 reporter 但没有联系/升级;内部任务只有标题

在我们自己的内部测试中,工具使用示例将复杂参数处理的准确性从 72% 提高到 90%。

何时使用工具使用示例

工具使用示例向你的工具定义添加 token,因此当准确性改进超过额外成本时,它们最有价值。

最有助于:

  • 复杂的嵌套结构,有效的 JSON 并不意味着正确的使用
  • 具有许多可选参数和包含模式的工具
  • 具有模式未捕获的领域特定约定的 API
  • 类似的工具,其中示例阐明使用哪一个(例如,create_ticket vs create_incident

不太有益于:

  • 具有明显使用的简单单参数工具
  • Claude 已经理解的标准格式,如 URL 或电子邮件
  • 最好由 JSON Schema 约束处理的验证问题

最佳实践

构建在现实世界中采取行动的 Agent 意味着同时处理规模、复杂性和精度。这三个功能协同工作以解决工具使用工作流中的不同瓶颈。以下是如何有效地组合它们。

战略性地分层功能

并非每个 Agent 都需要为给定任务使用所有三个功能。从你最大的瓶颈开始:

  • 来自工具定义的上下文膨胀 → 工具搜索工具
  • 大量中间结果污染上下文 → 程序化工具调用
  • 参数错误和格式错误的调用 → 工具使用示例

这种有针对性的方法让你解决限制 Agent 性能的特定约束,而不是预先增加复杂性。

然后根据需要添加其他功能。它们是互补的:工具搜索工具确保找到正确的工具,程序化工具调用确保高效执行,工具使用示例确保正确调用。

设置工具搜索工具以实现更好的发现

工具搜索匹配名称和描述,因此清晰、描述性的定义提高发现准确性。

// 好的
{
  "name": "search_customer_orders",
  "description": "Search for customer orders by date range, status, or total amount. Returns order details including items, shipping, and payment info."
}

// 坏的
{
  "name": "query_db_orders",
  "description": "Execute order query"
}

添加系统提示指导,以便 Claude 知道可用的内容:

You have access to tools for Slack messaging, Google Drive file management,
Jira ticket tracking, and GitHub repository operations. Use the tool search
to find specific capabilities.

保持你 3-5 个最常用的工具始终加载,其余的延迟加载。这平衡了常见操作的立即访问与其他所有内容的按需发现。

设置程序化工具调用以实现正确执行

由于 Claude 编写代码来解析工具输出,因此清楚地记录返回格式。这有助于 Claude 编写正确的解析逻辑:

{
  "name": "get_orders",
  "description": "Retrieve orders for a customer.
Returns:
List of order objects, each containing:
- id (str): Order identifier
- total (float): Order total in USD
- status (str): One of 'pending', 'shipped', 'delivered'
- items (list): Array of {sku, quantity, price}
- created_at (str): ISO 8601 timestamp"
}

参见下面选择加入受益于程序化编排的工具:

  • 可以并行运行的工具(独立操作)
  • 安全重试的操作(幂等)

设置工具使用示例以提高参数准确性

为行为清晰度制作示例:

  • 使用真实数据(真实城市名称、合理价格,而不是"string"或"value")
  • 显示最小、部分和完整规范模式的变化
  • 保持简洁:每个工具 1-5 个示例
  • 专注于歧义(仅在模式中正确使用不明显的地方添加示例)

入门

这些功能处于测试阶段。要启用它们,添加测试头并包括你需要的工具:

client.beta.messages.create(
    betas=["advanced-tool-use-2025-11-20"],
    model="claude-sonnet-4-5-20250929",
    max_tokens=4096,
    tools=[
        {"type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex"},
        {"type": "code_execution_20250825", "name": "code_execution"},
        # 你的带有 defer_loading、allowed_callers 和 input_examples 的工具
    ]
)

有关详细的 API 文档和 SDK 示例,请参阅我们的:

  • 工具搜索工具的文档和 cookbook
  • 程序化工具调用的文档和 cookbook
  • 工具使用示例的文档

这些功能将工具使用从简单的函数调用转向智能编排。随着 Agent 处理跨越数十个工具和大型数据集的更复杂工作流,动态发现、高效执行和可靠调用变得基础。

我们很高兴看到你构建什么。

致谢

由 Bin Wu 撰写,Adam Jones、Artur Renault、Henry Tay、Jake Noble、Nathan McCandlish、Noah Picard、Sam Jiang 和 Claude 开发者平台团队贡献。这项工作建立在 Chris Gorgolewski、Daniel Jiang、Jeremy Fox 和 Mike Lambert 的基础研究之上。我们还从整个 AI 生态系统中汲取了灵感,包括 Joel Pobar 的 LLMVM、Cloudflare 的代码模式和作为 MCP 的代码执行。特别感谢 Andy Schumeister、Hamish Kerr、Keir Bradwell、Matt Bleifer 和 Molly Vorwerck 的支持。