平行工具呼叫:縮短延遲
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將失敗的結果送回,這樣一個失敗的工具呼叫就不會讓整個迴圈中止。