When you give Claude tools — functions your application executes on the model's behalf — Claude does not politely request them one at a time. If it decides three independent lookups are needed to answer a question, the latest models will request all three in a single response. Anthropic's prompting guidance notes that current models run independent tool calls in parallel by default, covering patterns like speculative searches and multi-file reads. Your integration needs to handle that shape correctly, and ideally exploit it for latency.
What a parallel tool call looks like on the wire
A tool-using response arrives with stop_reason: "tool_use" and a content array that can contain multiple tool_use blocks, each with its own id, tool name, and input object. There may also be a text block before them explaining what Claude is doing. The contract on your side has two parts:
First, execute every requested tool. The calls are independent from the model's perspective, so you are free to run them concurrently — with asyncio, a thread pool, or parallel service calls. That is the entire latency win: three 2-second lookups finish in roughly 2 seconds instead of 6.
Second, return all results in one user turn. Claude expects a single follow-up user message containing one tool_result block per tool_use block, each carrying the matching tool_use_id. Do not split results across multiple user messages.
from anthropic import AnthropicVertex
client = AnthropicVertex(project_id="my-project", region="global")
resp = client.messages.create(model="claude-sonnet-5", max_tokens=1024,
tools=tools, messages=messages)
if resp.stop_reason == "tool_use":
calls = [b for b in resp.content if b.type == "tool_use"]
results = [{"type": "tool_result", "tool_use_id": c.id,
"content": run_tool(c.name, c.input)} # run concurrently
for c in calls]
messages += [{"role": "assistant", "content": resp.content},
{"role": "user", "content": results}]
resp = client.messages.create(model="claude-sonnet-5",
max_tokens=1024, tools=tools,
messages=messages)
Turning parallelism up — or off
Parallel tool use is allowed by default. If your tools have side effects that must happen strictly one at a time — say, a payment step that depends on an earlier validation step — you can force at most one tool call per response by adding "disable_parallel_tool_use": true to any tool_choice value (auto, any, or a specific tool). You trade latency for ordering guarantees, which is often the right trade for write-heavy tools.
Going the other direction, parallel usage is steerable. Anthropic's prompting best practices note that an explicit instruction — for example a <use_parallel_tool_calls>-style section in your system prompt telling Claude to batch independent calls — can push parallel invocation to nearly 100% when calls are genuinely independent. If you see the model serializing lookups that could obviously run together, prompt for it rather than accepting the extra round trips.
Common integration mistakes
Handling only content[0]. Code written against early single-call examples often grabs the first tool_use block and ignores the rest. Claude then receives results for one call and dangling references for the others, and the conversation derails. Always iterate over the full content array.
Returning results in separate user messages. All tool_result blocks for one assistant turn belong in a single user message. Splitting them changes the conversation structure the model expects.
Dropping the assistant turn. The assistant message containing the tool_use blocks must be appended to history exactly as received before you add your results — the tool_use_id values in your results refer back to it.
Serial execution by accident. A simple for loop over tool calls works but forfeits the speed benefit. For I/O-bound tools, concurrent execution is usually a one-line change with asyncio.gather or a thread pool.
Platform notes
Tool use — including multiple tool_use blocks per response — is part of the core Messages API and is generally available on all four third-party platforms: Claude Platform on AWS, Amazon Bedrock, Google Vertex AI, and Microsoft Foundry. The request and response shapes are the same everywhere the Anthropic SDK clients are used, so the handling code above ports across platforms with only the client constructor changing.
Where to go next
For the streaming version of this problem — assembling tool inputs that arrive as partial JSON — read Streaming With Tool Use. For what to send back when a tool fails, see Tool Result Errors, and for the block types themselves, Content Blocks.