The official Python library for the anthropic API
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive guide to using tools (function calling) with Claude for building agentic workflows.
Tools let Claude call functions you define, enabling it to take actions and retrieve information.
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[{
"name": "get_weather",
"description": "Get weather for a location",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state"}
},
"required": ["location"]
}
}],
messages=[{"role": "user", "content": "What's the weather in SF?"}]
)from anthropic import beta_tool
@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> dict:
"""
Get weather for a location.
Args:
location: City and state, e.g. San Francisco, CA
unit: Temperature unit (celsius or fahrenheit)
"""
# Implementation
return {"temperature": 72, "condition": "sunny", "unit": unit}
message = client.beta.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[get_weather],
messages=[{"role": "user", "content": "What's the weather in NYC?"}]
)# 1. Send initial request
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
messages=[{"role": "user", "content": "What's the weather in Paris?"}]
)
# 2. Extract tool use
tool_use = next(block for block in message.content if block.type == "tool_use")
# 3. Execute function
result = get_weather(location=tool_use.input["location"])
# 4. Send result back
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
messages=[
{"role": "user", "content": "What's the weather in Paris?"},
{"role": "assistant", "content": message.content},
{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(result)
}]
}
]
)@beta_tool
def get_weather(location: str) -> dict:
"""Get weather for location."""
return {"temp": 72, "condition": "sunny"}
@beta_tool
def get_time(timezone: str = "UTC") -> str:
"""Get current time in timezone."""
from datetime import datetime
return datetime.now().strftime("%H:%M")
for message in client.beta.messages.tool_runner(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[get_weather, get_time],
messages=[{"role": "user", "content": "What's the weather and time in SF?"}]
):
if message.stop_reason == "end_turn":
print(message.content[0].text)Let Claude decide whether to use tools:
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
tool_choice={"type": "auto"},
messages=[...]
)Require Claude to use at least one tool:
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
tool_choice={"type": "any"},
messages=[...]
)Require Claude to use a specific tool:
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
tool_choice={"type": "tool", "name": "get_weather"},
messages=[...]
)message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
tool_choice={"type": "none"},
messages=[...]
)Force sequential tool calls:
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
tool_choice={
"type": "auto",
"disable_parallel_tool_use": True
},
messages=[...]
)class Calculator:
def __init__(self):
self.memory = 0
@beta_tool
def calculate(self, expression: str) -> float:
"""Evaluate mathematical expression."""
result = eval(expression)
self.memory = result
return result
@beta_tool
def recall(self) -> float:
"""Recall last calculation result."""
return self.memory
calc = Calculator()
for message in client.beta.messages.tool_runner(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[calc.calculate, calc.recall],
messages=[{"role": "user", "content": "Calculate 5*8, then add 10"}]
):
if message.stop_reason == "end_turn":
print(message.content[0].text)@beta_tool
def divide(a: float, b: float) -> float:
"""Divide two numbers."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
# In tool result
try:
result = divide(10, 0)
tool_result = str(result)
is_error = False
except Exception as e:
tool_result = str(e)
is_error = True
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[...],
messages=[
...,
{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": tool_result,
"is_error": is_error
}]
}
]
)from anthropic import beta_async_tool
@beta_async_tool
async def fetch_data(url: str) -> dict:
"""Fetch data from URL."""
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
# Use with async tool runner
async for message in client.beta.messages.tool_runner(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[fetch_data],
messages=[...]
):
if message.stop_reason == "end_turn":
print(message.content[0].text)@beta_tool
def search_database(
query: str,
limit: int = 10,
category: str | None = None
) -> list[dict]:
"""
Search database for items matching query.
Args:
query: Search keywords or phrase
limit: Maximum results to return (1-100)
category: Optional category filter (e.g., "electronics", "books")
Returns:
List of matching items with id, name, price
"""
...@beta_tool
def set_temperature(degrees: float, unit: str = "celsius") -> dict:
"""Set thermostat temperature."""
if unit not in ["celsius", "fahrenheit"]:
raise ValueError(f"Invalid unit: {unit}")
if degrees < -50 or degrees > 50:
raise ValueError(f"Temperature out of range: {degrees}")
# Set temperature
return {"status": "success", "temperature": degrees, "unit": unit}@beta_tool
def get_user_info(user_id: str) -> dict:
"""Get user information."""
return {
"id": user_id,
"name": "Alice Smith",
"email": "alice@example.com",
"created_at": "2024-01-15"
}