Claude Function Calling (Tool Use) in Python

Claude uses 'tool use' instead of 'function calling'. This guide shows how Claude tool_use maps to OpenAI function calling and how to migrate your existing code. Working examples for 2026.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Claude doesn't use the term "function calling" — the feature is called tool use. The behavior is identical to OpenAI function calling, with minor API surface differences.

Side-by-side comparison

ConceptOpenAI (Python)Claude (Python)
Define toolsfunctions=[{name, description, parameters}]tools=[{name, description, input_schema}]
Auto tool choicefunction_call="auto"tool_choice="auto" (default)
Force a toolfunction_call={"name": "fn"}tool_choice={"type": "tool", "name": "fn"}
Disable toolsfunction_call="none"tool_choice={"type": "none"}
Tool call in responsechoice.message.function_callblock (type="tool_use")
Argumentsjson.loads(function_call.arguments)block.input (already a dict)
Send result backrole="function"type="tool_result"

Claude tool use — working example

import anthropic
import json

client = anthropic.Anthropic()

# Define tools (equivalent to OpenAI's 'functions')
tools = [
    {
        "name": "get_weather",
        "description": "Get current weather for a city. Returns temperature in Celsius and conditions.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name, e.g. 'London'"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "Temperature unit"}
            },
            "required": ["city"]
        }
    },
    {
        "name": "search_web",
        "description": "Search the web for current information.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query"},
                "max_results": {"type": "integer", "description": "Max results to return (default 5)"}
            },
            "required": ["query"]
        }
    }
]

# First call — Claude may call a tool
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather like in Tokyo?"}]
)

print(f"stop_reason: {response.stop_reason}")  # "tool_use" if Claude calls a tool

# Handle tool call
if response.stop_reason == "tool_use":
    messages = [{"role": "user", "content": "What's the weather like in Tokyo?"}]
    messages.append({"role": "assistant", "content": response.content})

    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            print(f"Claude called: {block.name}({block.input})")
            # block.input is already a dict (no json.loads needed — unlike OpenAI)

            # Execute your function here
            result = {"temperature": 22, "conditions": "Partly cloudy", "city": block.input["city"]}

            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(result)
            })

    messages.append({"role": "user", "content": tool_results})

    # Final response with tool result
    final = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )
    print(final.content[0].text)

Migrating from OpenAI function calling

# OpenAI pattern (before)
# response = openai_client.chat.completions.create(
#     model="gpt-4o",
#     messages=messages,
#     functions=[{"name": "get_weather", "description": "...", "parameters": schema}],
#     function_call="auto"
# )
# fn_call = response.choices[0].message.function_call
# args = json.loads(fn_call.arguments)   # ← must parse JSON string

# Claude equivalent (after)
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[{"name": "get_weather", "description": "...", "input_schema": schema}],
    # tool_choice defaults to "auto" — no change needed
    messages=messages
)
for block in response.content:
    if block.type == "tool_use":
        args = block.input   # ← already a dict, no json.loads needed
        print(f"Tool: {block.name}, Args: {args}")

Forcing a specific function (structured extraction)

response = client.messages.create(
    model="claude-haiku-4-5-20251001",
    max_tokens=256,
    tools=[{"name": "extract_address", "description": "Extract address components.", "input_schema": {
        "type": "object",
        "properties": {
            "street": {"type": "string"},
            "city": {"type": "string"},
            "state": {"type": "string"},
            "zip": {"type": "string"}
        },
        "required": ["street", "city", "state", "zip"]
    }}],
    tool_choice={"type": "tool", "name": "extract_address"},  # force this tool always
    messages=[{"role": "user", "content": "Ship to: 1 Infinite Loop, Cupertino, CA 95014"}]
)
for block in response.content:
    if block.type == "tool_use":
        print(block.input)
# {'street': '1 Infinite Loop', 'city': 'Cupertino', 'state': 'CA', 'zip': '95014'}

For structured output with Pydantic models, see Claude Structured Output Python. For multi-step agentic patterns, see Claude Agents Python. For cost estimates on tool-heavy workflows, use the Cost Calculator.

Frequently asked questions

Does Claude support function calling?
Claude's equivalent is called 'tool use'. The concept is identical to OpenAI function calling: you define tools with JSON schemas, Claude decides which tool to call and with what arguments, you execute the function and return the result. The API parameter is `tools` instead of `functions`.
How does Claude tool_use map to OpenAI function calling?
OpenAI: `functions=[{name, description, parameters}]`, Claude: `tools=[{name, description, input_schema}]`. OpenAI: `function_call='auto'`, Claude: `tool_choice='auto'`. OpenAI response: `choice.message.function_call.arguments (JSON string)`, Claude response: `block.input (dict, already parsed)`. The structure is nearly identical.
Can I force Claude to call a specific function?
Yes: set `tool_choice={'type': 'tool', 'name': 'your_function_name'}`. This forces Claude to always use that tool, guaranteed. OpenAI's equivalent is `function_call={'name': 'your_function'}`. Use this for structured data extraction where you always want a specific schema.
Does Claude parse function arguments automatically?
Yes — unlike OpenAI where `function_call.arguments` is a JSON string you must parse with `json.loads()`, Claude returns `block.input` as an already-parsed Python dict. This is a convenient improvement when migrating.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript