By Sagar Shankaran, Founder of CallSphere
Complete guide to implementing tool use (function calling) with the Claude API. Covers tool definitions, execution patterns, multi-turn conversations, and production best practices.
Key takeaways
Tool use -- also called function calling -- is the mechanism that allows Claude to interact with external systems. Instead of only generating text, Claude can request that your application execute a specific function with specific arguments. Your application runs the function, returns the result, and Claude incorporates that result into its reasoning.
This is the foundation of every agentic application. Without tool use, Claude is limited to its training data and the content you provide in the prompt. With tool use, Claude can query databases, call APIs, read files, send emails, and perform any operation you expose as a tool.
Tools are defined as JSON schemas that describe the function name, description, and parameters. The quality of your tool definitions directly impacts how reliably Claude uses them.
flowchart LR
USER(["User message"])
LOOP{"messages.create<br/>agent loop"}
THINK["Extended thinking<br/>optional"]
TOOL{"stop_reason<br/>tool_use?"}
EXEC["Execute tool<br/>append tool_result"]
DONE(["stop_reason<br/>end_turn"])
USER --> LOOP --> THINK --> TOOL
TOOL -->|Yes| EXEC --> LOOP
TOOL -->|No| DONE
style LOOP fill:#4f46e5,stroke:#4338ca,color:#fff
style THINK fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style DONE fill:#059669,stroke:#047857,color:#fff
from anthropic import Anthropic
client = Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get current weather conditions for a specific location. Returns temperature, humidity, and conditions.",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g. 'San Francisco, CA'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit. Defaults to fahrenheit."
}
},
"required": ["location"]
}
},
{
"name": "search_database",
"description": "Search the product database by name, category, or price range. Returns matching products with details.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query string"
},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "books", "home"],
"description": "Product category filter"
},
"max_price": {
"type": "number",
"description": "Maximum price in USD"
},
"limit": {
"type": "integer",
"description": "Maximum number of results to return. Default 10."
}
},
"required": ["query"]
}
}
]
The tool description is arguably more important than the schema itself. Claude uses it to decide when and whether to use the tool.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
A complete tool use interaction involves multiple API calls:
import json
def run_tool_loop(user_message: str, tools: list, max_iterations: int = 10) -> str:
messages = [{"role": "user", "content": user_message}]
for _ in range(max_iterations):
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=4096,
tools=tools,
messages=messages,
)
# Check if Claude wants to use a tool
if response.stop_reason == "tool_use":
# Extract tool use blocks
tool_results = []
assistant_content = response.content
for block in response.content:
if block.type == "tool_use":
# Execute the tool
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
})
# Add assistant message and tool results
messages.append({"role": "assistant", "content": assistant_content})
messages.append({"role": "user", "content": tool_results})
elif response.stop_reason == "end_turn":
# Claude is done -- extract final text
return "".join(
block.text for block in response.content if block.type == "text"
)
return "Max iterations reached without final response."
def execute_tool(name: str, input_data: dict):
"""Route tool calls to actual implementations."""
if name == "get_weather":
return fetch_weather(input_data["location"], input_data.get("unit", "fahrenheit"))
elif name == "search_database":
return search_products(**input_data)
else:
return {"error": f"Unknown tool: {name}"}
Claude can request multiple tools in a single response. When it does, the tool use blocks appear as separate items in the content array. You should execute them all and return all results.
# Claude might return content like:
# [TextBlock("Let me check both..."), ToolUseBlock(get_weather, ...), ToolUseBlock(search_database, ...)]
# Execute all tool calls (potentially in parallel)
import asyncio
async def execute_tools_parallel(tool_blocks):
tasks = [
execute_tool_async(block.name, block.input)
for block in tool_blocks
if block.type == "tool_use"
]
return await asyncio.gather(*tasks)
Sometimes you want Claude to always use a specific tool rather than answering from its own knowledge. Use the tool_choice parameter:
# Force Claude to use a specific tool
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=4096,
tools=tools,
tool_choice={"type": "tool", "name": "search_database"},
messages=[{"role": "user", "content": "Find me headphones under $100"}]
)
# Force Claude to use any tool (must use at least one)
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=4096,
tools=tools,
tool_choice={"type": "any"},
messages=[{"role": "user", "content": "What is the weather in Tokyo?"}]
)
# Let Claude decide (default behavior)
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=4096,
tools=tools,
tool_choice={"type": "auto"},
messages=[{"role": "user", "content": "Tell me about Claude"}]
)
When a tool execution fails, return the error as a tool result with is_error: true. Claude will see the error and can decide how to proceed -- often retrying with different parameters or informing the user.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
def execute_tool_safe(name: str, input_data: dict) -> dict:
try:
result = execute_tool(name, input_data)
return {
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
}
except Exception as e:
return {
"type": "tool_result",
"tool_use_id": block.id,
"content": f"Error executing {name}: {str(e)}",
"is_error": True,
}
Some workflows require Claude to call tools in a specific sequence. Instead of hardcoding the sequence, describe the workflow in the system prompt and let Claude orchestrate:
system_prompt = """You are a customer support agent with access to these tools:
- lookup_customer: Find a customer by email or phone
- get_order_history: Get recent orders for a customer ID
- create_ticket: Create a support ticket
- send_email: Send an email to a customer
Workflow for order issues:
1. First lookup the customer
2. Then check their order history
3. Create a ticket with the relevant details
4. Send confirmation email to the customer
Always follow this sequence. Do not skip steps."""
Tool definitions consume input tokens on every API call in the conversation. A large tool schema adds significant cost over multi-turn conversations.
| Number of Tools | Avg Schema Size | Tokens Per Call | Cost at Sonnet Rate |
|---|---|---|---|
| 5 tools | 200 tokens each | 1,000 | $0.003 |
| 20 tools | 200 tokens each | 4,000 | $0.012 |
| 50 tools | 200 tokens each | 10,000 | $0.030 |
For applications with many tools, consider using prompt caching to cache the tool definitions. With caching, you pay full price on the first call and 90% less on subsequent calls.
Before deploying tool use in production:

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
GPT-Realtime-2 brings GPT-5-class reasoning into voice. What that means for tool-call reliability, structured output, and production agent design.
May 2026's biggest agent-architecture shift: planning, tool selection, and self-correction move inside the model. Framework code shrinks. Here is what changes.
A three-way comparison of Gemini Enterprise, Anthropic managed agents and OpenAI Frontier Platform after Cloud Next 2026 — strengths, gaps, buyer fit.
Anthropic's May 2026 push positions Claude as a vertical platform for financial services. The strategic positioning versus OpenAI and Google.
ServiceNow Project Arc vs Anthropic Managed Agents — runtime, governance, integration, and use cases. The 2026 enterprise autonomous agent comparison.
Anthropic and Moody's announced a data partnership in May 2026 that grounds Claude in audited financial reference data. Why grounding reduces hallucination and what it unlocks.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco