← Blog

Claude API Tool Use Examples in Python

2026-10-15 · 4 min read · SubToAPI Team

What Claude API Tool Use Actually Means

Tool use (also called function calling) lets Claude decide, mid-conversation, that it needs to call a function you've defined — a weather lookup, a database query, a calculator — instead of just generating text. You describe the tool's name, purpose, and input schema; Claude returns a structured request to call it; your Python code executes the actual function; you send the result back; Claude uses it to finish its answer.

This article walks through working Python examples: a single tool, multiple tools, forcing tool choice, and the full multi-turn loop you need for production code. The patterns below work with Anthropic's native API and, with a one-line base URL swap, with SubToAPI if you're already routing Claude calls through it.

The Basic Tool Use Request

Here's a minimal example defining one tool — a function that gets the current stock price — and sending it to Claude:

import anthropic

client = anthropic.Anthropic(api_key="YOUR_API_KEY")

tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current price of a stock by ticker symbol.",
        "input_schema": {
            "type": "object",
            "properties": {
                "ticker": {
                    "type": "string",
                    "description": "Stock ticker symbol, e.g. AAPL"
                }
            },
            "required": ["ticker"]
        }
    }
]

response = client.messages.create(
    model="claude-opus-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[
        {"role": "user", "content": "What's the price of AAPL right now?"}
    ]
)

print(response.stop_reason)
print(response.content)

When Claude decides it needs the tool, stop_reason will be "tool_use" and response.content will include a block with type: "tool_use", a name, an id, and an input dict matching your schema.

Handling the Tool Call and Sending Results Back

Claude doesn't execute anything itself — your code has to run the real function and send the output back as a tool_result:

def get_stock_price(ticker):
    # Replace with a real API call
    prices = {"AAPL": 189.50, "MSFT": 412.30}
    return prices.get(ticker, "unknown")

# Extract the tool use block
tool_use_block = next(
    block for block in response.content if block.type == "tool_use"
)

tool_result = get_stock_price(tool_use_block.input["ticker"])

followup = client.messages.create(
    model="claude-opus-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[
        {"role": "user", "content": "What's the price of AAPL right now?"},
        {"role": "assistant", "content": response.content},
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use_block.id,
                    "content": str(tool_result)
                }
            ]
        }
    ]
)

print(followup.content[0].text)

The key detail developers miss: you must echo back the full assistant message containing the original tool_use block before appending your tool_result. Skipping that breaks the conversation state and Claude will error or hallucinate context.

Multiple Tools in One Request

Claude can pick between several tools, or even call more than one in sequence. Define them all in the tools array:

tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current price of a stock by ticker symbol.",
        "input_schema": {
            "type": "object",
            "properties": {"ticker": {"type": "string"}},
            "required": ["ticker"]
        }
    },
    {
        "name": "get_company_news",
        "description": "Get recent news headlines for a company.",
        "input_schema": {
            "type": "object",
            "properties": {"company": {"type": "string"}},
            "required": ["company"]
        }
    }
]

Claude will choose the right tool based on the description field, so write descriptions the way you'd explain the function to a new teammate — specific about what it does and when to use it.

Forcing a Specific Tool

Sometimes you don't want Claude to decide — you want it to always call a particular tool, useful for structured data extraction. Use tool_choice:

response = client.messages.create(
    model="claude-opus-4-20250514",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "tool", "name": "get_stock_price"},
    messages=[{"role": "user", "content": "AAPL please"}]
)

tool_choice also supports {"type": "auto"} (default) and {"type": "any"} (must call some tool, Claude picks which).

The Full Multi-Turn Loop

In real applications you need a loop that keeps calling Claude and executing tools until it stops asking for them:

def run_conversation(user_message, tools, tool_functions):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.messages.create(
            model="claude-opus-4-20250514",
            max_tokens=1024,
            tools=tools,
            messages=messages
        )

        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason != "tool_use":
            return response.content[0].text

        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                fn = tool_functions[block.name]
                result = fn(**block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(result)
                })

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

This handles single and multiple tool calls per turn, and loops until Claude produces a final text answer.

Running This Through SubToAPI

If your app already calls Claude through SubToAPI, the tool use flow is identical — only the endpoint and auth header change. You send requests to https://api.subtoapi.app/v1/messages with Authorization: Bearer $SUBTOAPI_KEY, and the tools, tool_choice, and tool_result structures work exactly as shown above. That matters if you want application-level API keys (sub_live_...), usage metadata per key, and team seats on top of raw Claude tool calling — see the tools docs and quickstart for the exact request format, or check messages for the full request/response schema. Sign up at /signup if you want to test it against a real key.

Common Mistakes to Avoid

Questions

Does Claude API tool use work with streaming? Yes, but tool_use blocks arrive as streamed content deltas you need to accumulate before executing the function — see /docs/streaming for the event format.

Can I define more than one tool per request? Yes, there's no hard limit on tool count per request, though fewer, well-described tools generally improve selection accuracy.

What Python library do I need for this? The official anthropic package (pip install anthropic) handles all the request formatting shown above; no extra framework is required for basic tool use.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →