Back to .md Directory

Claude Tool Use (Function Calling) Documentation

Tool use (formerly called function calling) allows Claude to interact with external tools, APIs, and functions. Released on April 4, 2024, and made generally available on May 30, 2024, this feature enables Claude to perform actions beyond text generation.

May 2, 2026
0 downloads
4 views
ai claude
View source

Claude Tool Use (Function Calling) Documentation

Overview

Tool use (formerly called function calling) allows Claude to interact with external tools, APIs, and functions. Released on April 4, 2024, and made generally available on May 30, 2024, this feature enables Claude to perform actions beyond text generation.

Current Model Support

Claude Sonnet 4

  • Model ID: claude-sonnet-4-5-20250929
  • Input: $3 per million tokens
  • Output: $15 per million tokens
  • Max output: 8192 tokens
  • Excellent tool use performance with 72.7% on SWE-bench

Basic Tool Definition Structure

Tools must follow this JSON schema format:

{
  "name": "tool_name",
  "description": "Detailed description of what the tool does",
  "input_schema": {
    "type": "object",
    "properties": {
      "parameter1": {
        "type": "string",
        "description": "Description of parameter1"
      },
      "parameter2": {
        "type": "integer",
        "description": "Description of parameter2"
      }
    },
    "required": ["parameter1"]
  }
}

Important Schema Rules

  • No $schema property - Don't include JSON Schema version references
  • No additionalProperties - This is not supported
  • Simple types only - Use string, integer, boolean, number, array, object
  • Tool names - Must match regex ^[a-zA-Z0-9_-]{1,64}$
  • Clear descriptions - Critical for Claude to understand when and how to use tools

Python Implementation

Basic Setup

import anthropic
import json

client = anthropic.Anthropic(api_key="your-api-key")

# Define your tool
tools = [
    {
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA"
                },
                "unit": {
                    "type": "string",
                    "description": "Temperature unit: 'celsius' or 'fahrenheit'"
                }
            },
            "required": ["location"]
        }
    }
]

# Send message with tools
response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1000,
    tools=tools,
    messages=[
        {"role": "user", "content": "What's the weather in New York?"}
    ]
)

Handling Tool Calls

def handle_tool_use(response):
    for content in response.content:
        if content.type == "tool_use":
            tool_name = content.name
            tool_input = content.input
            tool_use_id = content.id

            # Execute your tool
            if tool_name == "get_weather":
                result = get_weather(**tool_input)

            # Return result to Claude
            return {
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": tool_use_id,
                        "content": json.dumps(result)
                    }
                ]
            }

Complete Conversation Flow

import anthropic
import json

client = anthropic.Anthropic()

def get_weather(location, unit="fahrenheit"):
    """Simulated weather function"""
    # Your actual implementation here
    return {
        "location": location,
        "temperature": 72,
        "unit": unit,
        "conditions": "partly cloudy"
    }

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

    tools = [
        {
            "name": "get_weather",
            "description": "Get current weather in a location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City and state"
                    }
                },
                "required": ["location"]
            }
        }
    ]

    while True:
        # Get Claude's response
        response = client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1000,
            tools=tools,
            messages=messages
        )

        # Check for tool use
        tool_use = None
        final_text = ""

        for content in response.content:
            if content.type == "text":
                final_text += content.text
            elif content.type == "tool_use":
                tool_use = content

        # If no tool use, we're done
        if not tool_use:
            return final_text

        # Execute tool
        if tool_use.name == "get_weather":
            tool_result = get_weather(**tool_use.input)

        # Add Claude's message with tool use to history
        messages.append({
            "role": "assistant",
            "content": response.content
        })

        # Add tool result
        messages.append({
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(tool_result)
                }
            ]
        })

        # Continue conversation

Advanced Tool Patterns

Multiple Tools

tools = [
    {
        "name": "search_database",
        "description": "Search the company database for information",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "SQL query to execute"
                },
                "database": {
                    "type": "string",
                    "description": "Database name"
                }
            },
            "required": ["query", "database"]
        }
    },
    {
        "name": "send_email",
        "description": "Send an email to a recipient",
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {
                    "type": "string",
                    "description": "Recipient email"
                },
                "subject": {
                    "type": "string",
                    "description": "Email subject"
                },
                "body": {
                    "type": "string",
                    "description": "Email body"
                }
            },
            "required": ["to", "subject", "body"]
        }
    }
]

Complex Input Schemas

{
    "name": "create_chart",
    "description": "Create a data visualization chart",
    "input_schema": {
        "type": "object",
        "properties": {
            "chart_type": {
                "type": "string",
                "description": "Type: 'bar', 'line', 'pie', 'scatter'"
            },
            "data": {
                "type": "array",
                "description": "Array of data points"
            },
            "options": {
                "type": "object",
                "description": "Chart configuration options"
            }
        },
        "required": ["chart_type", "data"]
    }
}

Nested Objects (Simplified)

{
    "name": "process_order",
    "description": "Process a customer order",
    "input_schema": {
        "type": "object",
        "properties": {
            "customer_id": {
                "type": "string",
                "description": "Customer identifier"
            },
            "items": {
                "type": "array",
                "description": "Array of order items with 'product_id', 'quantity', 'price'"
            },
            "shipping_address": {
                "type": "object",
                "description": "Address object with 'street', 'city', 'state', 'zip'"
            }
        },
        "required": ["customer_id", "items"]
    }
}

Tool Execution Service Pattern

class ToolExecutor:
    def __init__(self):
        self.tools = {
            "get_weather": self.get_weather,
            "search_database": self.search_database,
            "calculate": self.calculate
        }

    def execute(self, tool_name: str, tool_input: dict):
        """Execute a tool by name with given input"""
        if tool_name not in self.tools:
            return {"error": f"Unknown tool: {tool_name}"}

        try:
            return self.tools[tool_name](**tool_input)
        except Exception as e:
            return {"error": f"Tool execution failed: {str(e)}"}

    def get_weather(self, location: str, unit: str = "fahrenheit"):
        # Implementation
        pass

    def search_database(self, query: str, database: str):
        # Implementation
        pass

    def calculate(self, expression: str):
        # Implementation
        pass

Streaming Tool Use

from anthropic import Anthropic

client = Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1000,
    tools=tools,
    messages=messages
) as stream:
    for event in stream:
        if event.type == "content_block_start":
            if event.content_block.type == "tool_use":
                print(f"Using tool: {event.content_block.name}")
        elif event.type == "content_block_delta":
            if event.delta.type == "text_delta":
                print(event.delta.text, end="")

Async Tool Use

import asyncio
from anthropic import AsyncAnthropic

async def async_tool_conversation():
    client = AsyncAnthropic()

    response = await client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1000,
        tools=tools,
        messages=messages
    )

    for content in response.content:
        if content.type == "tool_use":
            # Async tool execution
            result = await execute_tool_async(content.name, content.input)
            # Process result

Best Practices

1. Clear Tool Descriptions

# Good
"description": "Search for products in the inventory database by name, category, or SKU. Returns matching products with details including price, stock level, and description."

# Bad
"description": "Search products"

2. Validate Tool Input

def execute_tool(tool_name: str, tool_input: dict):
    # Validate required parameters
    if tool_name == "send_email":
        required = ["to", "subject", "body"]
        missing = [field for field in required if field not in tool_input]
        if missing:
            return {"error": f"Missing required fields: {missing}"}

    # Execute tool
    return tool_functions[tool_name](**tool_input)

3. Error Handling

def safe_tool_execution(tool_name: str, tool_input: dict):
    try:
        result = execute_tool(tool_name, tool_input)
        return {"success": True, "data": result}
    except ValueError as e:
        return {"success": False, "error": f"Invalid input: {str(e)}"}
    except Exception as e:
        return {"success": False, "error": f"Execution failed: {str(e)}"}

4. Tool Result Formatting

# Always return structured data
def get_user_info(user_id: str):
    user = database.get_user(user_id)
    if not user:
        return {
            "found": False,
            "error": "User not found"
        }

    return {
        "found": True,
        "user": {
            "id": user.id,
            "name": user.name,
            "email": user.email,
            "created_at": user.created_at.isoformat()
        }
    }

Sequential vs Parallel Tool Use

Sequential (Default Behavior)

Claude typically uses tools one at a time:

# User: "Get weather in NYC and send it to john@example.com"
# Claude will:
# 1. Call get_weather("New York, NY")
# 2. Get result
# 3. Call send_email(...) with weather info

Encouraging Parallel Tool Use

system_prompt = """When multiple independent pieces of information are needed,
use multiple tools in a single response rather than sequentially. For example,
if asked for weather in multiple cities, call the weather tool multiple times
in one response."""

Tool Use with System Prompts

response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1000,
    system="""You are a helpful assistant with access to tools.

    When using tools:
    1. Explain what you're about to do before using a tool
    2. Use tools when they would provide helpful information
    3. Interpret tool results for the user
    4. Chain tools together when needed
    5. Handle errors gracefully

    Always provide a natural language response along with tool results.""",
    tools=tools,
    messages=messages
)

Common Patterns

Database Query Tool

{
    "name": "query_database",
    "description": "Execute a read-only SQL query on the specified database",
    "input_schema": {
        "type": "object",
        "properties": {
            "database": {
                "type": "string",
                "description": "Database name: 'users', 'products', 'orders'"
            },
            "query": {
                "type": "string",
                "description": "SQL SELECT query (read-only)"
            }
        },
        "required": ["database", "query"]
    }
}

API Integration Tool

{
    "name": "call_api",
    "description": "Make an HTTP request to an external API",
    "input_schema": {
        "type": "object",
        "properties": {
            "method": {
                "type": "string",
                "description": "HTTP method: GET, POST, PUT, DELETE"
            },
            "endpoint": {
                "type": "string",
                "description": "API endpoint URL"
            },
            "headers": {
                "type": "object",
                "description": "Request headers as key-value pairs"
            },
            "body": {
                "type": "object",
                "description": "Request body for POST/PUT requests"
            }
        },
        "required": ["method", "endpoint"]
    }
}

File Operation Tool

{
    "name": "file_operation",
    "description": "Read, write, or manipulate files",
    "input_schema": {
        "type": "object",
        "properties": {
            "operation": {
                "type": "string",
                "description": "Operation: 'read', 'write', 'append', 'delete'"
            },
            "path": {
                "type": "string",
                "description": "File path"
            },
            "content": {
                "type": "string",
                "description": "Content for write/append operations"
            }
        },
        "required": ["operation", "path"]
    }
}

Debugging Tool Use

Logging Tool Calls

def debug_tool_use(response):
    for i, content in enumerate(response.content):
        if content.type == "tool_use":
            print(f"Tool Call #{i+1}")
            print(f"  Name: {content.name}")
            print(f"  ID: {content.id}")
            print(f"  Input: {json.dumps(content.input, indent=2)}")
        elif content.type == "text":
            print(f"Text: {content.text}")

Testing Tools

def test_tool_definition(tool_def, test_cases):
    """Test a tool definition with various inputs"""

    for test in test_cases:
        response = client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1000,
            tools=[tool_def],
            messages=[{"role": "user", "content": test["query"]}]
        )

        # Check if tool was called
        tool_called = any(c.type == "tool_use" for c in response.content)

        print(f"Query: {test['query']}")
        print(f"Expected tool call: {test['should_call_tool']}")
        print(f"Actual tool call: {tool_called}")
        print(f"Match: {'✓' if tool_called == test['should_call_tool'] else '✗'}\n")

Performance Optimization

1. Minimize Tool Schema Complexity

  • Keep input schemas flat when possible
  • Avoid deeply nested objects
  • Use simple types

2. Tool Description Optimization

  • Front-load important information in descriptions
  • Include examples in descriptions when helpful
  • Specify units, formats, and constraints

3. Batch Operations

{
    "name": "batch_operation",
    "description": "Process multiple items in a single call",
    "input_schema": {
        "type": "object",
        "properties": {
            "items": {
                "type": "array",
                "description": "Array of items to process"
            }
        },
        "required": ["items"]
    }
}

Server-Side Tools (2024 Update)

Anthropic now provides server-side tools that execute on their infrastructure:

# Web search tool (server-side)
tools = [
    {
        "type": "web_search",
        "version": "web_search_20250305"  # Versioned for compatibility
    }
]

# These tools don't require implementation on your side
response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    tools=tools,
    messages=[{"role": "user", "content": "Search for the latest AI news"}]
)

Common Issues and Solutions

Issue: Tool Not Being Called

Solution: Improve tool description and ensure schema is correct

Issue: Wrong Parameters Passed

Solution: Add parameter validation and clearer descriptions

Issue: Tool Called Too Frequently

Solution: Add usage guidelines in system prompt

Issue: Complex Nested Data

Solution: Flatten schema or split into multiple simpler tools

References

Related Documents