Building agentic systems forces a pragmatic choice of which model emits your tool calls. This function calling comparison GPT-5 Claude Gemini Llama 4 goes past the docs to the wire format, failure modes, and integration friction you’ll actually face when shipping. All four can drive a tool-using loop, but the distance between their APIs and your codebase varies sharply.
Wire format and capabilities
Every model supports parallel invocation, but the serialization differs enough to dictate your client design.
GPT-5 (OpenAI tools)
OpenAI sticks with the tools array and JSON Schema. The assistant response carries tool_calls where arguments is a JSON string you must parse.
{
"model": "gpt-5",
"messages": [{"role": "user", "content": "Ping the warehouse API for SKU X"}],
"tools": [{
"type": "function",
"function": {
"name": "get_inventory",
"parameters": {"type": "object", "properties": {"sku": {"type": "string"}}}
}
}],
"tool_choice": "auto"
}
The model can emit multiple tool_calls in one turn. Strict schema adherence is strong; malformed arguments are rare but you still validate.
Claude (Anthropic)
Claude uses a top-level tools field and returns tool_use content blocks with a parsed input object and an id for correlation.
{
"model": "claude-opus-4",
"messages": [{"role": "user", "content": "Ping the warehouse API for SKU X"}],
"tools": [{
"name": "get_inventory",
"input_schema": {"type": "object", "properties": {"sku": {"type": "string"}}}
}]
}
In practice, Claude rejects ambiguous schemas more cleanly than the others. It will refuse to call a tool if required properties are missing from context rather than hallucinating.
Gemini (Google)
Gemini declares functionDeclarations and returns functionCall parts mixed into the response parts array.
{
"contents": [{"role": "user", "parts": [{"text": "Ping the warehouse API for SKU X"}]}],
"tools": [{
"functionDeclarations": [{
"name": "get_inventory",
"parameters": {"type": "object", "properties": {"sku": {"type": "string"}}}
}]
}]
}
You must iterate parts and check for functionCall. It works, but the separation of text and calls is less ergonomic than a dedicated field.
Llama 4 (Meta)
Llama 4 ships native function calling when served through a compliant endpoint. Raw self-hosted builds often expect a constrained grammar or a system prompt describing tools. Using an OpenAI-compatible shim makes it drop-in:
from openai import OpenAI
client = OpenAI(base_url="https://your-llama-endpoint/v1")
resp = client.chat.completions.create(
model="llama-4-70b",
messages=[{"role": "user", "content": "Ping warehouse for SKU X"}],
tools=[{"type": "function", "function": {"name": "get_inventory",
"parameters": {"type": "object", "properties": {"sku": {"type": "string"}}}}}]
)
print(resp.choices[0].message.tool_calls)
If you self-host, you own the validation and the fallback when the model emits near-JSON.
Cost model and metering
Tool schemas are not free. A 20-tool agent injects the full JSON Schema on every turn, so input tokens silently inflate. Measure schema size like you measure prompt size.
- GPT-5 / Claude: per input/output token, no separate tool fee.
- Gemini: per-token with a free tier for low volume; multimodal parts billed differently.
- Llama 4: fixed GPU cost if self-hosted; variable if routed via a cloud endpoint.
If you route through a gateway like n4n.ai, per-token usage metering works uniformly across all four, so you can compare effective cost without writing four billing integrations. That abstraction is the only one that consistently saved me time across providers.
Latency and throughput
Real numbers depend on region and load, but the shape is consistent:
- GPT-5: low time-to-first-token on small prompts; parallel fan-out adds marginal overhead.
- Claude: stable streaming;
tool_useblocks often arrive before the final text, enabling pipelining. - Gemini: high batch throughput; single-call latency acceptable but variable under contention.
- Llama 4: entirely infra-dependent. On vLLM with A100s, p50 can beat cloud APIs; on CPU it is unusable for interactive agents.
Streaming partial tool calls matters for UX. GPT-5 and Claude stream incremental JSON strings; Gemini streams text and call parts together; Llama 4 depends on the serving stack.
// Incremental tool-call assembly from a stream
let buf = "";
for await (const chunk of stream) {
buf += chunk.choices[0]?.delta?.tool_calls?.[0]?.function?.arguments ?? "";
}
const args = JSON.parse(buf); // validate before use
Ergonomics for developers
SDK maturity decides velocity more than raw model quality.
OpenAI’s Python and TS SDKs parse tool_calls into objects. Anthropic returns typed ToolUseBlock with id and input. Gemini’s SDK requires manual part scanning. Llama 4 behind an OpenAI-compatible endpoint lets you reuse existing clients, but verify the server honors tool_choice.
Strict mode exists everywhere but with different spelling:
- GPT-5:
tool_choice: {"type": "function", "function": {"name": "x"}} - Claude:
tool_choice: {"type": "tool", "name": "x"} - Gemini:
tool_config: {functionCallingConfig: {forcedFunction: {name: "x"}}} - Llama 4: prompt constraint or gateway-enforced
tool_choicepassthrough.
Error handling diverges. Claude returns a clear error block on schema violation; OpenAI returns a normal message with no call; Gemini may emit empty functionCall; Llama may emit prose. Build a normalization layer.
Ecosystem and limits
- Context window: GPT-5 and Claude sit at 200K+ tokens; Gemini offers 1M+; Llama 4 depends on the serving config (commonly 128K).
- Parallel tools: All emit arrays; practical limit is model attention, not API.
- Rate limits: Cloud providers throttle per tier; Llama only limited by your hardware queue.
- Caching: OpenAI and Anthropic support prompt caching; Gemini caches implicitly; Llama depends on your proxy.
Provider degradation is not theoretical. Gateways that honor client routing directives and provide automatic fallback (e.g., n4n.ai) let you mix GPT-5 and Claude without rewriting call sites when one is rate-limited or degraded. They also forward provider cache-control hints, so your schema prefix stays cached across attempts.
Head-to-head table
| Model | Capabilities | Cost model | Latency/throughput | Ergonomics | Ecosystem | Limits |
|---|---|---|---|---|---|---|
| GPT-5 | Native tools, parallel, strict mode | Per-token input/output | Low TTFT, scalable | Best SDK, OpenAI-compat | 200K+ ctx, broad tooling | Cloud rate limits |
| Claude | tool_use blocks, predictable reject | Per-token, similar | Stable stream, pipelined | Typed blocks, clean | 200K+ ctx, caching | Cloud tier throttling |
| Gemini | functionDeclarations, mixed parts | Per-token, free tier | Variable, high batch | Manual part scan | 1M+ ctx, multimodal | Modality separation |
| Llama 4 | Native if normalized, self-host | Fixed GPU or endpoint | Infra-dependent | Reuse OAI client | Flexible ctx, your stack | Hardware ceiling |
Which to choose
Latency-sensitive agent with strict schemas: Use GPT-5 or Claude. If you need the cleanest rejection of invalid calls, Claude. If you already run OpenAI stack, GPT-5 minimizes code change.
Cost-sensitive batch extraction: Gemini’s free tier and million-token context win for document pipelines. Llama 4 self-hosted wins if you have steady high volume and spare GPU capacity.
On-prem regulatory constraints: Llama 4 is the only option that runs inside your VPC without data egress. Wrap it with an OpenAI-compatible shim and keep your tool-calling loop unchanged.
Multi-model resilience: Route across GPT-5 and Claude with fallback. Use a gateway that forwards cache-control hints to avoid recomputing schemas, and meter per-token uniformly. This protects uptime when a provider degrades.
The function calling comparison GPT-5 Claude Gemini Llama 4 shows they are interchangeable at the protocol level only after you normalize the response shape and own the validation loop. Pick based on where your pain is: schema strictness, latency, data residency, or cost.