n4nAI

Claude tool use vs OpenAI function calling: key differences

Practical comparison of Claude tool use vs OpenAI function calling across wire format, streaming, cost, limits, and which to use per use case for engineers.

n4n Team5 min read1,039 words

Audio narration

Coming soon — every post will get a voice note here.

Claude tool use vs OpenAI function calling isn’t a superficial syntax difference—it reflects two distinct philosophies about how models should invoke external code. Engineers integrating LLMs into production systems need to understand the wire format, streaming behavior, and failure modes before picking one. Both let a model request execution of developer-defined functions, but the request/response shapes and client ergonomics diverge in ways that affect agent design.

Capabilities

Claude tool use

Anthropic’s Messages API treats tools as first-class content blocks. You pass a tools array where each entry has name, description, and input_schema (a JSON Schema subset). The model returns tool_use blocks inside an assistant message. It supports parallel invocations in a single turn, forced tool selection via tool_choice, and streaming of partial JSON arguments.

Claude can emit multiple tool_use blocks interleaved with text, letting it reason aloud while calling tools. To return results, you send a subsequent user message containing tool_result blocks keyed by tool_use_id. This keeps the conversational roles clean: the assistant message holds only the model’s intent, and the user message holds execution results.

OpenAI function calling

OpenAI’s Chat Completions API uses a tools array where each entry is {type: "function", function: {name, description, parameters}}. The model responds with tool_calls attached to an assistant message, each containing function.name and function.arguments (a JSON string). Parallel calls are supported. tool_choice forces a specific function or any.

After execution, you must append the assistant message (with tool_calls) to the history, then add a tool role message referencing the call id. OpenAI does not interleave tool results with user text; they are a distinct message type.

Wire format and ergonomics

A minimal Claude tool definition and call:

{
  "model": "claude-3-5-sonnet-20241022",
  "max_tokens": 1024,
  "tools": [
    {
      "name": "get_weather",
      "description": "Fetch current weather",
      "input_schema": {
        "type": "object",
        "properties": { "location": { "type": "string" } },
        "required": ["location"]
      }
    }
  ],
  "messages": [{ "role": "user", "content": "Weather in Berlin?" }]
}

The assistant response contains:

{
  "role": "assistant",
  "content": [
    { "type": "tool_use", "id": "tu_1", "name": "get_weather", "input": { "location": "Berlin" } }
  ]
}

You return results like this:

{
  "role": "user",
  "content": [
    { "type": "tool_result", "tool_use_id": "tu_1", "content": "{\"temp\":12}" }
  ]
}

OpenAI equivalent request:

{
  "model": "gpt-4o",
  "messages": [{ "role": "user", "content": "Weather in Berlin?" }],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Fetch current weather",
        "parameters": {
          "type": "object",
          "properties": { "location": { "type": "string" } },
          "required": ["location"]
        }
      }
    }
  ]
}

Response:

{
  "choices": [{
    "message": {
      "role": "assistant",
      "tool_calls": [{
        "id": "call_1",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"location\":\"Berlin\"}" }
      }]
    }
  }]
}

Follow-up history:

[
  { "role": "assistant", "tool_calls": [{ "id": "call_1", "function": { "name": "get_weather", "arguments": "{\"location\":\"Berlin\"}" } }] },
  { "role": "tool", "tool_call_id": "call_1", "content": "{\"temp\":12}" }
]

The Claude shape gives you a parsed object; OpenAI gives you a JSON string you must parse. Both support similar schema constraints, but Claude’s input_schema is directly a JSON Schema draft-07 subset, while OpenAI’s parameters is the same but nested under function.

Streaming and partial outputs

In agent loops, streaming tool calls lets you pre-validate arguments or show progress. OpenAI streams tool_calls as a sequence of delta chunks:

import openai
stream = openai.chat.completions.create(
    model="gpt-4o", messages=[...], tools=[...], stream=True
)
for chunk in stream:
    if chunk.choices[0].delta.tool_calls:
        print(chunk.choices[0].delta.tool_calls[0].function.arguments, end="")

Claude streams content_block_delta events of type input_json_delta for tool_use:

import anthropic
with anthropic.Anthropic().messages.stream(
    model="claude-3-5-sonnet-20241022",
    messages=[...], tools=[...], max_tokens=1024
) as stream:
    for event in stream:
        if event.type == "content_block_delta" and event.delta.type == "input_json_delta":
            print(event.delta.partial_json, end="")

Both require you to accumulate strings and parse when complete. Claude’s event stream separates text and tool blocks cleanly; OpenAI interleaves role and content deltas with tool_calls. Neither guarantees valid JSON until the block closes, so production code needs a fallback for truncated streams.

Cost model and metering

Neither provider charges separately for tool definitions; you pay per input and output token. Input tokens include the tool schemas and any tool_result content you send back. Output tokens include the generated argument JSON.

Publicly listed per-token rates differ by model class—Claude 3.5 Sonnet and GPT-4o sit in similar price tiers, but smaller models from both vendors are cheaper. Large tool schemas inflate input token counts on every turn, making caching critical. If you route through an OpenRouter-class gateway such as n4n.ai, you get per-token usage metering across 240+ models behind one OpenAI-compatible endpoint, with automatic fallback when a provider is rate-limited. That simplifies cost attribution when mixing Claude and OpenAI calls.

Latency and throughput

Measured latency depends on model size, load, and region. Both vendors exhibit higher time-to-first-token for larger contexts. Tool calling adds minimal overhead beyond generating the argument tokens. In practice, Claude’s streaming of structured blocks and OpenAI’s delta tool calls have comparable wall-clock behavior for single calls; batch throughput is governed by provider rate limits, not the tool protocol. The first token may be delayed until the model commits to a tool call, especially under forced-tool modes.

Ecosystem and client support

OpenAI’s format is supported by the official openai Python/TS SDKs, LangChain, and most frameworks. Claude tool use is native to the anthropic SDK and increasingly supported by agent libraries, but some older tools assume the OpenAI shape.

If you standardize on the OpenAI function calling schema, you can adapt to Claude via a translation layer or a gateway that honors client routing directives and forwards provider cache-control hints. This avoids rewriting agent loops when you switch models.

Limits and constraints

  • Context windows: Claude models commonly support 200K token context (1M in beta); GPT-4o supports 128K. Tool schemas eat into this.
  • Max tools: Both accept dozens of tools; performance degrades as schema count grows because the model must attend to them.
  • Nested calls: Neither supports native recursive tool calls in one response; you must loop.
  • Forced calls: Both support tool_choice: "any" (Claude) or tool_choice: "required" (OpenAI) and specific function forcing.
  • Cache control: Claude lets you mark tool definitions as cached via cache_control on system blocks; OpenAI supports prompt caching automatically for repeated prefixes.
  • Validation: Both validate arguments against the schema loosely; the model may omit optional fields. Strict mode is not enforced server-side.

Head-to-head comparison

Dimension Claude tool use OpenAI function calling
Wire shape tool_use content blocks, parsed input object tool_calls array, arguments as JSON string
Streaming input_json_delta per block delta.tool_calls arguments chunks
Forced invocation tool_choice: {type:"any"|"tool"} tool_choice: "required"|{type:"function"}
Parallel calls Multiple tool_use blocks in one turn Multiple tool_calls in one message
Context limit Up to 200K (1M beta) 128K on GPT-4o
SDK ecosystem Official anthropic SDK, growing Ubiquitous openai SDK, LangChain, etc.
Cost metering Per input/output token Per input/output token
Cache hints Explicit cache_control on tools Automatic prefix caching

Which to choose

Pick Claude tool use if:

  • You already use Anthropic’s Messages API and want native tool_result handling without string parsing.
  • Your agent needs long context (large system prompts plus many tool outputs) beyond 128K.
  • You want explicit cache control on tool schemas to cut repeat costs across long sessions.

Pick OpenAI function calling if:

  • Your stack is built on the OpenAI SDK or frameworks that assume its shape.
  • You need the widest third-party tool integration and minimal translation.
  • You are using GPT-4o or smaller OpenAI models and want automatic prompt caching with zero config.

Pick a hybrid/gateway approach if:

  • You want to A/B models or avoid vendor lock-in. Standardize on the OpenAI schema, route to either provider, and let a fallback layer handle degradation. This works well for high-availability agent services that must survive provider outages.

Claude tool use vs OpenAI function calling ultimately converges on the same capability: letting models drive functions. The decision hinges on ecosystem fit, context needs, and how much wire-format translation you are willing to maintain.

Tagstool-callingclaudeopenaicomparison

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All streaming, tool calling & structured outputs support posts →