Careeroza
Parallel Tool Calls
Several Tools in One Turn
When the calls do not depend on each other, the model can request several tools in a single response: for "compare the Stride Pro and Cushion Jogger" it may return two tool_use blocks. Run them all (concurrently if you like) and send all results in one user message, each with its matching tool_use_id.
Note: To allow at most one call per turn, set tool_choice={"type": "auto", "disable_parallel_tool_use": True}.
Handling Multiple tool_use Blocks
Example
A stand-in model response with two tool calls; they run concurrently in a thread pool and the results go back together, in the original order:
import json
from concurrent.futures import ThreadPoolExecutor
PRODUCTS = {"stride-pro": {"price": 2499, "rating": 4.4}, "cushion-jogger": {"price": 2999, "rating": 4.1}}
def get_product(slug):
return PRODUCTS[slug]
response_content = [ # stand-in for one model reply with two parallel tool calls
{"type": "text", "text": "I'll look up both shoes."},
{"type": "tool_use", "id": "toolu_A", "name": "get_product", "input": {"slug": "stride-pro"}},
{"type": "tool_use", "id": "toolu_B", "name": "get_product", "input": {"slug": "cushion-jogger"}},
]
calls = [b for b in response_content if b["type"] == "tool_use"]
with ThreadPoolExecutor() as pool:
outputs = list(pool.map(lambda b: get_product(**b["input"]), calls))
tool_results = [{"type": "tool_result", "tool_use_id": b["id"], "content": json.dumps(out)}
for b, out in zip(calls, outputs)]
print(json.dumps({"role": "user", "content": tool_results}, indent=1))Output
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_A",
"content": "{\"price\": 2499, \"rating\": 4.4}"
},
{
"type": "tool_result",
"tool_use_id": "toolu_B",
"content": "{\"price\": 2999, \"rating\": 4.1}"
}
]
}