并行工具调用:降低延迟
Claude可以在一次响应中请求多个工具,您的代码可以一起运行它们。该视频检查了Meridian(一家虚构的工程咨询公司)的工作现场。逐个运行工具调用需要19.9秒,而并行工具调用只需10.8秒。
本视频中的演示录制于2026年9月。它运行在Claude Sonnet 5(claude-sonnet-5)上。在较新的模型上,结果可能会有所不同。
逐个运行工具调用会让您的用户依次等待每一个调用。
当Claude想要的工具彼此不依赖时,它可以在一次响应中全部请求。Claude默认会这样做,因此您的循环必须处理响应中的每一个工具调用,并为每一个都发回一个结果。
一次响应中的三个工具调用
并行工具使用意味着一个响应中包含多个tool_use块。
Meridian有一个Python脚本,用于检查工作现场是否已准备好进行现场作业。现场检查需要三项互不依赖的查询:项目状态、现场天气,以及许可证状态。
以下是Claude对Meridian现场检查的响应,其中为每个想要使用的工具都有一个tool_use块。
{
"role": "assistant",
"stop_reason": "tool_use",
"content": [
{"type": "tool_use", "id": "toolu_01", "name": "get_project_status",
"input": {"job_number": "MEG-2026-0142"}},
{"type": "tool_use", "id": "toolu_02", "name": "get_site_weather",
"input": {"site": "Riverside"}},
{"type": "tool_use", "id": "toolu_03", "name": "get_permit_state",
"input": {"permit_id": "P-88213"}}
]
}该响应的stop_reason是tool_use,每个工具调用都有各自的id。
运行每一个工具调用
为单个工具调用编写的循环只会读取第一个tool_use块。它只会发回一个结果,另外两个工具调用永远得不到各自的结果,API会拒绝该请求。因此要收集响应中的每一个tool_use块。
calls = [b for b in resp.content if b.type == "tool_use"]接下来,同时运行这些工具调用。每个查询大部分时间都花在等待另一个系统上。给每个查询分配各自的线程,这样三个等待过程就会重叠,而不是累加。
with ThreadPoolExecutor() as pool:
results = list(pool.map(run_tool, calls))run_tool运行一个工具调用并返回其结果,接下来的两节将构建这个函数。
当工具调用只读取数据、彼此不依赖时(就像Meridian的查询那样),同时运行它们通常是安全的。当工具会更改数据,或必须按特定顺序执行时,最好逐个依次运行它们。
在一条消息中发回所有结果
一旦三个工具调用运行完毕,Claude就在等待它们的结果。每个结果都回传到一个tool_result块中,其tool_use_id持有它所响应的工具调用的id。
result = {"type": "tool_result", "tool_use_id": call.id}每个tool_use块都会得到一个tool_result,它们全部放在下一条用户消息中。
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": results})
将全部三个结果放在一条用户消息中,可以让Claude继续并行调用工具。
如果您的循环改为将每个结果放在各自的消息中发送,那么对话看起来就像Claude一次只请求了一个工具一样。这是Claude减少并行工具调用的一个常见原因。
为错误的工具调用返回一个错误结果
同时运行三个工具调用意味着其中一个可能失败,而另外两个成功。如果您的代码抛出异常且没有任何地方捕获它,您的循环就会停止,那两个正确的结果也会随之丢失。
因此要把失败也作为结果发回去。 这就是一个普通的tool_result,其content为错误信息,并附带is_error: true。该消息应说明出了什么问题,以及Claude接下来应该尝试什么。
try:
result["content"] = HANDLERS[call.name](**call.input)
except Exception as exc:
result["content"] = f"{call.name} failed: {exc}"
result["is_error"] = TrueHANDLERS是一个字典,将工具名称映射到执行每个工具具体工作的Python函数。每个函数都返回一个字符串,因为tool_result的content既可以是字符串,也可以是内容块列表。
把循环组装起来
上面的代码片段组合成了下面Meridian的循环。该脚本已经设置好了client、tools、prompt和HANDLERS。
关键要点
- 运行响应中的每一个工具调用,当它们彼此不依赖时,同时运行它们。
- 为每个工具调用发回一个
tool_result,并将它们全部放在一条用户消息中。 - 不要把每个结果放在各自的消息中发送,因为那样会减少并行工具使用。
- 将失败作为结果发回,并附带
is_error: true,这样一个坏的工具调用就不会使循环停止。