"Programmatic tool calling"(编程式工具调用)允许 Claude 编写代码,在 code execution(代码执行)容器中以编程方式调用您的工具,而无需每次工具调用都经过模型往返。这降低了多工具工作流的延迟,并通过允许 Claude 在数据进入模型的上下文窗口之前对其进行过滤或处理来减少令牌消耗。在 BrowseComp 和 DeepSearchQA 等智能体搜索基准测试中(这些测试评估多步骤网络研究和复杂信息检索能力),在基础搜索工具之上添加编程式工具调用使性能平均提升了 11%,同时输入令牌使用量减少了 24%(参见 Improved web search with dynamic filtering)。
以检查 20 名员工的预算合规情况为例:传统方法需要 20 次独立的模型往返,期间会将数千条费用明细拉入上下文。而使用编程式工具调用,单个脚本即可运行全部 20 次查询、过滤结果,并仅返回超出限额的员工,将 Claude 需要推理的内容从数百 KB 缩减到寥寥几行。
如需深入了解编程式工具调用所解决的推理和上下文成本问题,请参阅 Advanced tool use。
此功能需要启用代码执行工具。
此功能不符合零数据保留(ZDR)的条件。数据将根据该功能的标准保留策略进行保留。
编程式工具调用需要 code_execution_20260120 或更高版本,以下模型支持该版本:
| 模型 |
|---|
| Claude Fable 5 (claude-fable-5) |
| Claude Mythos 5 (claude-mythos-5) |
| Claude Opus 4.8 (claude-opus-4-8) |
| Claude Opus 4.7 (claude-opus-4-7) |
| Claude Opus 4.6 (claude-opus-4-6) |
| Claude Sonnet 5 (claude-sonnet-5) |
| Claude Sonnet 4.6 (claude-sonnet-4-6) |
| Claude Opus 4.5 (claude-opus-4-5-20251101) |
| Claude Sonnet 4.5 (claude-sonnet-4-5-20250929) |
有关完整的代码执行工具版本矩阵,请参阅代码执行工具模型兼容性表。编程式工具调用可在 Claude API、AWS 上的 Claude Platform 和 Microsoft Foundry 上使用。在 Microsoft Foundry 上,编程式工具调用需要 Hosted on Anthropic 部署。目前在 Amazon Bedrock 或 Google Cloud 上不可用。
以下示例展示了 Claude 如何以编程方式多次查询数据库并聚合结果:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
messages=[
{
"role": "user",
"content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue",
}
],
tools=[
{"type": "code_execution_20260120", "name": "code_execution"},
{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query to execute"}
},
"required": ["sql"],
},
"allowed_callers": ["code_execution_20260120"],
},
],
)
print(response)响应会以 stop_reason: "tool_use" 停止,并包含一个 container ID 和一个针对 query_database 的 tool_use 块,其 caller 字段标识了调用它的代码执行运行。按照示例工作流的第 3 步所示返回结果,以便代码完成执行。
当您将工具配置为可从代码执行中调用,且 Claude 决定使用该工具时:
tool_use 块此方法特别适用于:
允许代码执行调用方的工具会作为异步 Python 函数暴露给 Claude 的代码,因此 Claude 可以使用 asyncio.gather 并行运行它们。每个函数接受单个参数字典并返回一个字符串:即您发回的 tool_result 的文本。Claude 的代码使用顶层 await 等待这些函数,并将需要作为结构化数据的结果进行解析,例如 rows = json.loads(await query_database({"sql": "<sql>"}))。
allowed_callers 字段allowed_callers 字段指定哪些上下文可以调用工具:
{
"name": "query_database",
"description": "Execute a SQL query against the database",
"input_schema": {
// ...
},
"allowed_callers": ["code_execution_20260120"]
}可能的值:
["direct"] - 引导 Claude 直接调用此工具(省略时的默认值)["code_execution_20260120"] - 引导 Claude 仅从代码执行内部调用此工具["direct", "code_execution_20260120"] - Claude 可以直接调用此工具,也可以从代码执行内部调用allowed_callers 中同时接受 "code_execution_20260120" 和 "code_execution_20260521",二者可互换:使用任一代码执行工具版本的请求都能满足列出任一调用方的工具。无论请求声明的是哪个版本,响应块始终将调用方标记为 code_execution_20260120。
为每个工具选择 ["direct"] 或 ["code_execution_20260120"] 之一,而不是同时启用两者,因为这能为 Claude 提供更清晰的指导,帮助其以最佳方式使用该工具。
allowed_callers 控制工具如何呈现给 Claude,并会针对 tool_choice 进行验证,但它并非 API 层面对直接调用的硬性阻止。Claude 会被强烈引导遵守该设置,但您的客户端仍应准备好处理其定义的任何工具的直接 tool_use。请勿将 allowed_callers 作为安全边界来依赖。
caller 字段每个工具使用块都包含一个 caller 字段,指示其调用方式:
直接调用(传统工具使用):
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": { "type": "direct" }
}编程式调用:
{
"type": "tool_use",
"id": "toolu_xyz789",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123"
}
}tool_id 是发起该调用的代码执行 server_tool_use 块的 id,因此您可以将每个编程式 tool_use 与产生它的代码执行运行相匹配。
编程式工具调用使用与代码执行相同的容器:
container 字段中返回,同时附带 expires_at 时间戳expires_at 告诉您容器还剩多长时间。空闲容器目前在约 5 分钟后被回收,且任何容器在创建后超过 30 天都无法重用。当 Claude 的代码正在等待编程式工具结果时,待处理的调用会在约 4 分钟后超时,并在代码内部引发 TimeoutError。请在暂停响应的 expires_at 时间戳之前尽早返回每个工具结果。参见工具调用期间容器过期。
以下是完整的编程式工具调用流程的工作方式:
发送一个包含代码执行和允许编程式调用的工具的请求。要启用编程式调用,请在工具定义中添加 allowed_callers 字段。
在工具描述中提供工具输出格式的详细说明。如果您指定工具返回 JSON,Claude 会尝试在代码中反序列化并处理结果。您提供的输出模式细节越多,Claude 就越能以编程方式处理响应。
请求结构与快速开始示例相同:在您的工具列表中包含 code_execution,为您希望 Claude 从代码中调用的任何工具添加 allowed_callers: ["code_execution_20260120"],然后发送您的用户消息。此工作流的其余步骤使用的用户消息为 "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"。
Claude 编写调用您的工具的代码。API 暂停并返回:
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll query the purchase history and analyze the results."
},
{
"type": "server_tool_use",
"id": "srvtoolu_abc123",
"name": "code_execution",
"input": {
"code": "import json\n\nrows = json.loads(await query_database({'sql': '<sql>'}))\ntop_customers = sorted(rows, key=lambda x: x['revenue'], reverse=True)[:5]\nprint(f'Top 5 customers: {top_customers}')"
}
},
{
"type": "tool_use",
"id": "toolu_def456",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123"
}
}
],
"container": {
"id": "container_xyz789",
"expires_at": "2026-01-20T14:30:00Z"
},
"stop_reason": "tool_use"
}发送完整的对话历史以及您的工具结果。此请求有三个重要细节:
tool_result 块。参见消息格式限制。container ID。如果续接请求有待处理的编程式工具调用但没有容器 ID,API 会拒绝该请求。tools 数组。代码执行工具必须仍然存在,暂停的代码才能恢复,并且您在此请求中发送的工具是 Claude 和正在运行的代码在本轮剩余时间内可以使用的定义。response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
container="container_xyz789", # Reuse the container
messages=[
{
"role": "user",
"content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue",
},
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll query the purchase history and analyze the results.",
},
{
"type": "server_tool_use",
"id": "srvtoolu_abc123",
"name": "code_execution",
"input": {"code": "..."},
},
{
"type": "tool_use",
"id": "toolu_def456",
"name": "query_database",
"input": {"sql": "<sql>"},
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123",
},
},
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_def456",
"content": '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',
}
],
},
],
# 与原始请求相同的 tools 数组
tools=[
{"type": "code_execution_20260120", "name": "code_execution"},
{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query to execute"}
},
"required": ["sql"],
},
"allowed_callers": ["code_execution_20260120"],
},
],
)
print(response)代码从暂停处继续执行并处理您的结果。每个续接响应要么再次暂停并返回更多编程式 tool_use 块,要么完成代码执行并让 Claude 继续本轮对话(第 5 步)。检查 stop_reason 和每个 tool_use 块的 caller 以区分这两种情况:为您暂停的响应具有 stop_reason: "tool_use" 和一个 caller 指向代码执行版本的 tool_use 块,此时您需要重复第 3 步,在一条用户消息中为每个待处理的编程式调用提供 tool_result。
代码执行完成后,Claude 提供最终响应:
{
"content": [
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_abc123",
"content": {
"type": "code_execution_result",
"stdout": "Top 5 customers: [{'customer_id': 'C1', 'revenue': 45000}, {'customer_id': 'C2', 'revenue': 38000}, {'customer_id': 'C5', 'revenue': 32000}, {'customer_id': 'C8', 'revenue': 28500}, {'customer_id': 'C3', 'revenue': 24000}]",
"stderr": "",
"return_code": 0,
"content": []
}
},
{
"type": "text",
"text": "I've analyzed the purchase history from last quarter. Your top 5 customers generated $167,500 in total revenue, with Customer C1 leading at $45,000."
}
],
"stop_reason": "end_turn"
}Claude 可以编写高效处理多个项目的代码:
regions = ["West", "East", "Central", "North", "South"]
results = {}
for region in regions:
rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))
results[region] = sum(row["revenue"] for row in rows)
# 以编程方式处理结果
top_region = max(results.items(), key=lambda x: x[1])
print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")此模式:
Claude 可以在满足成功条件后立即停止处理:
endpoints = ["us-east", "eu-west", "apac"]
for endpoint in endpoints:
status = await check_health({"endpoint": endpoint})
if status == "healthy":
print(f"Found healthy endpoint: {endpoint}")
break # Stop early, don't check remainingpath = "/tmp/example.txt"
file_info = json.loads(await get_file_info({"path": path}))
if file_info["size"] < 10000:
content = await read_full_file({"path": path})
else:
content = await read_file_summary({"path": path})
print(content)server_id = "srv-01"
log_text = await fetch_logs({"server_id": server_id})
errors = [line for line in log_text.splitlines() if "ERROR" in line]
print(f"Found {len(errors)} errors")
for error in errors[-10:]: # Only return last 10 errors
print(error)当代码执行调用工具时:
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_xyz789"
}
}您的工具结果会传回给正在运行的代码:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000, \"orders\": 23}, {\"customer_id\": \"C2\", \"revenue\": 38000, \"orders\": 18}, ...]"
}
]
}当所有工具调用都得到满足且代码完成时:
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_xyz789",
"content": {
"type": "code_execution_result",
"stdout": "Analysis complete. Top 5 customers identified from 847 total records.",
"stderr": "",
"return_code": 0,
"content": []
}
}| 错误 | 出现位置 | 描述 | 解决方案 |
|---|---|---|---|
invalid_tool_input | 响应中 code_execution_tool_result 错误块上的 error_code | 向代码执行工具传递了无效参数 | 参见代码执行工具错误 |
invalid_request_error(针对 tool_choice) | HTTP 400 错误响应 | tool_choice 指定的工具的 allowed_callers 不包含 "direct" | 要么将 "direct" 添加到该工具的 allowed_callers,要么从 tool_choice 中移除该工具并让 Claude 从代码中调用它 |
如果您的工具结果未在约 4 分钟内到达,待处理的调用会在 Claude 正在运行的代码内部引发 TimeoutError。Claude 会在 stderr 中看到该错误,通常会重试该调用:
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_abc123",
"content": {
"type": "code_execution_result",
"stdout": "",
"stderr": "TimeoutError: Calling tool ['query_database'] timed out (no response after 270s).",
"return_code": 0,
"content": []
}
}为防止超时:
expires_at 字段如果您的工具返回错误:
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "Error: Query timeout - table lock exceeded 30 seconds"
}Claude 的代码会接收此错误并可以适当地处理它。
strict: true 的工具tool_choice 强制对特定工具进行编程式调用disable_parallel_tool_use: trueinput_schema 包含递归 $ref(引用循环,例如引用自身的模式)的自定义工具无法启用编程式调用。在此类工具的 allowed_callers 中包含代码执行工具版本会导致请求失败,返回 400 invalid_request_error,其消息包含 Circular $ref detected。相同的模式在直接工具调用中是可接受的。
要解决此问题,请执行以下操作之一:
allowed_callers(或将其设置为 ["direct"])使该工具仅限直接调用。同一请求中的其他工具仍可使用编程式调用。description 中描述任何更深的嵌套,或者将递归属性替换为普通的 {"type": "object"},并在其 description 中解释预期的结构。以下工具无法以编程方式调用:
响应编程式工具调用时,有严格的格式要求:
仅包含工具结果的响应: 如果有待处理的编程式工具调用正在等待结果,您的响应消息必须仅包含 tool_result 块。您不能包含任何文本内容,即使在工具结果之后也不行。
无效 - 响应编程式工具调用时不能包含文本:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
},
{ "type": "text", "text": "What should I do next?" }
]
}有效 - 响应编程式工具调用时仅包含工具结果:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
}
]
}此限制仅适用于响应编程式(代码执行)工具调用的情况。对于常规客户端工具调用,您可以在工具结果之后包含文本内容。
仅文本的工具结果内容: 回应编程式调用的每个 tool_result 的 content 必须是字符串或 text 块。图像、文档和其他内容块类型会被拒绝。
编程式工具调用受与常规工具调用相同的速率限制约束。代码执行中的每次工具调用都计为一次独立调用。
在实现将被编程式调用的用户定义工具时:
编程式工具调用通过三种方式减少令牌消耗:
例如,直接调用 10 个工具所使用的令牌约为以编程方式调用它们并返回摘要的 10 倍。
在 Anthropic 对生产环境 Claude 模型的内部评估中:
tools 数组包含 10 到 49 个工具定义的请求在启用编程式工具调用后,通常可节省 20% 到 40% 的令牌。实际节省量因工作负载形态而异。参见何时使用编程式调用。
编程式工具调用使用与代码执行相同的定价。详情请参阅代码执行定价。
编程式工具调用的令牌计数:编程式调用的工具结果不计入您的输入/输出令牌使用量。只有最终的代码执行结果和 Claude 的响应会被计入。
编程式工具调用以少量固定开销(容器启动、脚本生成)换取工具结果令牌和模型往返的大幅节省。这种权衡是否划算取决于工作负载形态。
非常适合:
不太适合:
如果您不确定,请在广泛启用之前,在具有代表性的流量样本上测量启用和不启用 allowed_callers 时的计费输入令牌。
设置 tool_choice 时出现 invalid_request_error
tool_choice 不能指定 allowed_callers 中省略了 "direct" 的工具。要么将 "direct" 添加到该工具的 allowed_callers,要么从 tool_choice 中移除该工具并让 Claude 从代码中调用它。容器过期
expires_at 时间戳之前尽早响应每个编程式工具调用。Claude 的代码在约 4 分钟后停止等待结果,空闲容器目前在约 5 分钟后被回收。工具结果未正确解析
caller 字段以确认编程式调用Claude 在大量代码上进行了训练,因此将工具呈现为可调用的 Python 函数可以让它发挥这一优势:
编程式工具调用是一种可泛化的模式,也可以在您自己的基础设施上实现。以下是各种方法的比较:
为 Claude 提供一个代码执行工具,并描述该环境中可用的函数。当 Claude 使用代码调用该工具时,您的应用程序在定义这些函数的本地环境中执行它。
优点:
缺点:
适用场景: 您的应用程序可以安全地执行任意代码,您希望实现最小化,且 Anthropic 的托管方案不符合您的需求。
从 Claude 的角度来看方法相同,但代码在具有安全限制(例如,无网络出口)的沙箱容器中运行。如果您的工具需要外部资源,您需要一个在沙箱外执行工具调用的协议。
优点:
缺点:
适用场景: 安全性至关重要,且 Anthropic 的托管解决方案不符合您的要求。
Anthropic 的编程式工具调用是沙箱执行的托管版本,具有为 Claude 调优的特定 Python 环境。Anthropic 负责处理容器管理、代码执行和安全的工具调用通信。
优点:
如果您正在使用 Claude API、AWS 上的 Claude Platform 或 Microsoft Foundry,请考虑使用 Anthropic 的托管解决方案。在 Microsoft Foundry 上,编程式工具调用需要 Hosted on Anthropic 部署。
编程式工具调用构建在代码执行基础设施之上,并使用相同的沙箱容器。容器数据(包括执行产物和输出)最多保留 30 天。
有关所有功能的 ZDR 资格,请参阅 API 和数据保留。
在无需服务器端 JSON 缓冲的情况下流式传输工具输入,适用于对延迟敏感的应用程序。
在沙箱容器中运行 Python 和 bash 代码,以分析数据、生成文件并迭代解决方案。
将 Claude 连接到外部工具和 API。了解工具在何处执行、Claude 何时调用它们,以及哪种工具适合您的任务。
指定工具模式、编写有效的描述,并控制 Claude 何时调用您的工具。
Was this page helpful?