Parallel Tool Calls in Claude, OpenAI, and Gemini: How Each One Signals, Limits, and Breaks

Multiple network cables running in parallel under a data center floor, representing several independent calls happening at once.

Claude, OpenAI, and Gemini all let a single model turn call more than one tool at once, but they document the mechanics differently enough that code written against one provider’s assumptions about parallel calls breaks when it is ported to another. This is a side-by-side look at what each provider’s own reference actually says, not a general explainer of what function calling is.

How Claude signals and controls parallel calls

Claude puts multiple tool_use blocks directly in one response’s content array when it decides more than one tool applies, and nothing in the top-level request has to ask for that: parallel tool use is on by default. Turning it off is a parameter nested inside tool_choice, not a top-level flag: disable_parallel_tool_use, set inside the tool_choice object. What it actually does depends on the tool_choice type it sits inside. With the default auto type, disabling it means Claude calls at most one tool per response, though it can still choose to answer in plain text instead. With the any or tool types, disabling it means Claude calls exactly one tool, no text option.

Anthropic’s own documentation adds a model-specific wrinkle worth checking before relying on the “exactly one call” behavior: Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, and Claude Mythos 5.1 don’t support the any and tool tool_choice types at all, so disable_parallel_tool_use cannot force exactly one call on those models the way it can on older ones. Separately, Claude Fable 5.1 is documented as potentially issuing fewer parallel calls specifically inside long agent loops, custom coding agents, and computer-use harnesses, with standard function calling unaffected.

Handling the response is its own source of bugs independent of whether parallel calls are enabled. Every tool_use block needs exactly one matching tool_result, and all of those results have to go back in a single user message, not one message per result. Anthropic’s own troubleshooting notes call this out directly: splitting results across multiple messages is what teaches the model to stop calling tools in parallel on later turns, since it looks like the previous parallel batch did not actually work the way it expected.

How OpenAI signals and controls it, and where that gets inconsistent

OpenAI’s chat completions API represents multiple calls as entries in a tool_calls array on the response message, each with its own id, and the parameter that controls whether more than one can appear is parallel_tool_calls, a boolean. Setting it to false is documented to ensure exactly zero or one tool is called in that turn, which mirrors Claude’s any/tool behavior fairly closely in intent.

Where this gets less clean than Claude’s documentation is model support. Developers report on OpenAI’s own community forum that the parameter is not accepted uniformly across OpenAI’s model lineup: some reasoning models are reported to return an HTTP 400 error naming parallel_tool_calls as an unsupported parameter for that specific model, while other accounts in the same thread dispute exactly which models fail and why. OpenAI’s API reference states the parameter defaults to true, but the same community thread disputes whether that default actually holds in practice for every model family. The practical takeaway is not “OpenAI’s parallel calling is broken,” it is that the parameter’s behavior is not uniform across OpenAI’s own model lineup the way Claude’s is across Claude models, and that is worth testing against the specific model you call rather than assuming the documented default applies everywhere.

How Gemini signals it, with no dedicated parameter at all

Gemini’s function calling guide takes a structurally different approach: there is no dedicated parallel-calling parameter in the first place. The model calls “multiple functions in a single turn” and the documentation describes this as happening “when they are independent,” with each call appearing as its own function_call step. The page’s own worked example for parallel calls sets generation_config’s tool_choice to any, defined there as a mode where the model is “constrained to always predict a function call,” but the documentation does not state outright that any is a requirement for parallel calls to happen, only that the example uses it.

Gemini’s documentation draws a separate line between this and what it calls compositional function calling: chaining calls across turns when a later call depends on an earlier one’s result, such as getting a location before asking for weather at that location. The page describes this as something that “can be repeated over multiple turns,” which puts the dependency-handling responsibility on the turn structure of the conversation rather than on anything inside a single response the way Claude’s sequential-tool-result handling does.

Side by side

ProviderDefault for parallel callsHow to force a single callWhere multiple calls appearKnown model-support caveat
ClaudeOn by defaultdisable_parallel_tool_use inside tool_choice (any/tool type forces exactly one call; auto forces at most one)Multiple tool_use blocks in response.contentOpus 5.5, Sonnet 5.5, Fable 5.1, and Mythos 5.1 don’t support the any/tool tool_choice types
OpenAIDocumented as true by defaultparallel_tool_calls: false (top-level parameter)Multiple entries in the tool_calls arrayReported, via OpenAI’s community forum, to be rejected outright by some reasoning models
GeminiNo dedicated parameter; depends on the tool-calling modeNot a separate switch; controlled by generation_config’s tool_choice modeEach call as its own function_call stepFunction-calling guide does not spell out per-model exceptions

What actually breaks when porting code between providers

Code that assumes Claude’s “all results in one message” rule, and sends OpenAI-style one-result-per-message replies instead, will quietly degrade Claude’s willingness to batch tool calls on later turns rather than throwing an immediate error, which is a slower and harder bug to spot than a parameter rejection. Code that assumes OpenAI’s parallel_tool_calls flag exists on every model and ports that same assumption to a reasoning model in OpenAI’s own lineup can hit a hard 400 error instead. And code that assumes Gemini needs an explicit flag to unlock parallel calls, when its documentation does not describe one, will spend time looking for a parameter that is not there to find, when the actual lever is how the available tools and the prompt are structured rather than a request-level switch.

Where this fits with model choice generally

None of this is a reason to prefer one provider’s tool-calling design over another on its own. It is a reason to treat “does this support parallel tool calls” as a question with a provider-specific, sometimes model-specific, answer rather than a single yes-or-no fact to check once, the same way a model’s deprecation timeline or its rate-limit tier needs checking per model rather than assumed from a previous one. It sits alongside two other provider-specific details worth checking together rather than separately: how each provider defines a tool’s schema in the first place, and how each one handles structured output modes when a response needs to come back in a fixed shape.

The minimal request that forces a single call, for each provider

Seeing the actual parameter in place, rather than just its description, makes the differences in where each provider puts the control concrete.

Claude: the flag lives inside tool_choice, not beside it.

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=1024,
    tools=[weather_tool, calendar_tool],
    tool_choice={"type": "any", "disable_parallel_tool_use": True},
    messages=[{"role": "user", "content": "What's the weather, and what's on my calendar?"}],
)

OpenAI: the flag is a top-level, sibling parameter to tools and messages, not nested inside anything else.

response = client.chat.completions.create(
    model="gpt-4.1",
    tools=[weather_tool, calendar_tool],
    parallel_tool_calls=False,
    messages=[{"role": "user", "content": "What's the weather, and what's on my calendar?"}],
)

Gemini: there is nothing to set for this specifically; the closest lever is generation_config’s tool_choice, which constrains whether a function call happens at all rather than how many can happen in one turn.

response = model.generate_content(
    "What's the weather, and what's on my calendar?",
    tools=[weather_tool, calendar_tool],
    generation_config={"tool_choice": "any"},  # constrains whether a call happens, not how many
)

The structural difference these three snippets make visible is the one worth remembering past the specific parameter names: Claude and OpenAI both expose a dedicated on/off switch for parallel calls, placed in different parts of the request body, while Gemini’s documentation ties the behavior to the broader tool-calling mode rather than giving it its own switch. A migration from one provider to another has to find the equivalent concept, not just rename a parameter.

A model-support caveat worth checking before you ship

Every provider’s own documentation describes a general rule and then narrows it per model somewhere else. Claude’s newest models drop support for the tool_choice types that disable_parallel_tool_use depends on for forcing exactly one call. OpenAI’s reasoning models are reported, through its own community forum rather than its primary API reference, to reject the parallel_tool_calls parameter outright. Gemini’s documentation does not make this kind of per-model carve-out visible in the function-calling guide itself, which is worth treating as an open question to verify against the specific model you call, not as evidence that no carve-out exists.

Checking whether parallel calls are actually happening, not just enabled

Leaving a provider’s default behavior in place does not guarantee the model will actually batch independent calls together; a model can still choose to call tools one at a time even when nothing is stopping it from calling several. Anthropic’s own troubleshooting guidance gives a concrete way to check this for Claude rather than guessing from a handful of manual tests: track the average number of tool_use blocks per tool-calling message across real traffic, and treat an average at or below 1.0 as a sign the model is not batching independent calls the way the request structure allows. The same style of check, counting how many calls actually land in one turn versus how many turns a multi-step task takes end to end, works for OpenAI and Gemini too, even without an equivalent published guideline, because the underlying question, is the model actually using the parallelism it is allowed to use, is the same regardless of which provider’s parameter enabled it.

Photo: Robert.Harker / Wikimedia Commons, CC BY-SA 3.0.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top