Claude Tool Use: Building Function-Calling Agents with Anthropic's API
Build function-calling agents with Claude's native tool use. Learn how to define tools with JSON schemas, handle tool_use and tool_result blocks, and orchestrate multi-step tool conversations.
What Is Claude Tool Use
Tool use (also called function calling) is the mechanism that transforms Claude from a text generator into an agent that can take actions. When you define tools, Claude can decide when to call them, provide structured arguments, and then incorporate the results into its reasoning.
Unlike approaches that rely on parsing freeform text for function names and arguments, Claude's tool use is a first-class API feature. The model outputs structured tool_use content blocks with validated JSON arguments, and you return tool_result blocks with the execution output. This structured protocol eliminates parsing errors and makes agent loops reliable.
Defining Tools
Tools are defined as JSON schemas in the tools parameter:
import anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a specific location. Use this when the user asks about weather conditions.",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
}
]
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "What is the weather in Boston?"}
]
)
Each tool needs a name, a description that helps Claude decide when to use it, and an input_schema that defines the expected arguments. The description is critical — it is how Claude understands the tool's purpose.
The Tool Use Loop
When Claude decides to use a tool, the response contains a tool_use content block instead of (or alongside) text. Your code must execute the tool and send back a tool_result:
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
import anthropic
import json
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get current weather for a location.",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"},
},
"required": ["location"]
}
}
]
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
# In production, call a real weather API here
return json.dumps({"temp": 62, "condition": "Partly cloudy", "location": args["location"]})
return json.dumps({"error": f"Unknown tool: {name}"})
# Step 1: Send the user message
messages = [{"role": "user", "content": "What is the weather in Boston?"}]
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=messages
)
# Step 2: Check if Claude wants to use a tool
if response.stop_reason == "tool_use":
# Extract the tool use block
tool_block = next(b for b in response.content if b.type == "tool_use")
# Execute the tool
result = execute_tool(tool_block.name, tool_block.input)
# Step 3: Send the tool result back
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_block.id,
"content": result
}
]
})
# Step 4: Get Claude's final response
final = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=messages
)
print(final.content[0].text)
The key insight is the tool_use_id — it links each result back to the specific tool call, which is essential when Claude makes multiple tool calls in a single turn.
Building a Complete Agent Loop
Production agents need a loop that handles multiple consecutive tool calls:
import anthropic
import json
client = anthropic.Anthropic()
tools = [
{
"name": "search_database",
"description": "Search the product database by query string.",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
},
{
"name": "get_product_details",
"description": "Get full details for a product by its ID.",
"input_schema": {
"type": "object",
"properties": {
"product_id": {"type": "string", "description": "The product ID"}
},
"required": ["product_id"]
}
}
]
def execute_tool(name: str, args: dict) -> str:
if name == "search_database":
return json.dumps([{"id": "P001", "name": "Widget Pro", "price": 29.99}])
elif name == "get_product_details":
return json.dumps({"id": args["product_id"], "name": "Widget Pro", "stock": 142})
return json.dumps({"error": "Unknown tool"})
def run_agent(user_input: str) -> str:
messages = [{"role": "user", "content": user_input}]
while True:
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
tools=tools,
system="You are a product search assistant. Use the available tools to answer questions.",
messages=messages
)
# If Claude is done (no more tool calls), return the text
if response.stop_reason == "end_turn":
return "".join(b.text for b in response.content if hasattr(b, "text"))
# Process all tool calls in this turn
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
print(run_agent("Find me details about Widget Pro"))
This while True loop continues until Claude returns end_turn, meaning it has all the information it needs and is ready to give a final answer. This is the core pattern for every tool-using agent.
FAQ
Can Claude call multiple tools in a single response?
Yes. Claude can return multiple tool_use blocks in a single response when it needs information from several tools simultaneously. Your agent loop should process all tool blocks and return all results in a single tool_result message. This parallel tool calling reduces round trips and speeds up agent execution.
How do I handle tool errors?
Return the error message as the tool_result content with is_error: true. Claude will see the error and can retry with different arguments or inform the user. For example: {"type": "tool_result", "tool_use_id": id, "content": "Error: Location not found", "is_error": true}.
How many tools can I define?
Claude can handle dozens of tools in a single request. However, more tools means more tokens spent on tool descriptions, increasing cost and latency. For agents with many capabilities, consider grouping related functions or implementing a two-stage approach where a routing step selects a subset of relevant tools before the main agent call.
#Anthropic #Claude #ToolUse #FunctionCalling #AgenticAI #LearnAI #AIEngineering
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.