Tool calling umožňuje Claude provádět akce v reálném světě. Pojďme se podívat na best practices.
Základní tool calling
from anthropic import Anthropic
client = Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get current weather for a location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g., 'Prague'"
},
"units": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature units"
}
},
"required": ["location"]
}
}
]
response = client.messages.create(
model="claude-opus-4-5-20250101",
max_tokens=1000,
tools=tools,
messages=[{
"role": "user",
"content": "What's the weather in Prague?"
}]
)
# Claude vrátí tool_use block
for block in response.content:
if block.type == "tool_use":
print(f"Tool: {block.name}")
print(f"Input: {block.input}")
Tool Execution Loop
def execute_tool(name: str, input_data: dict) -> str:
"""Execute a tool and return result"""
if name == "get_weather":
# Skutečné volání weather API
return get_weather_api(input_data["location"])
elif name == "search_database":
return search_db(input_data["query"])
else:
return f"Unknown tool: {name}"
def run_agent(user_message: str, tools: list):
messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="claude-opus-4-5-20250101",
max_tokens=4000,
tools=tools,
messages=messages
)
# Přidej assistant response
messages.append({
"role": "assistant",
"content": response.content
})
# Najdi tool_use bloky
tool_uses = [b for b in response.content if b.type == "tool_use"]
if not tool_uses:
# Žádné další nástroje - konec
break
# Execute tools a přidej výsledky
tool_results = []
for tool_use in tool_uses:
result = execute_tool(tool_use.name, tool_use.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": result
})
messages.append({
"role": "user",
"content": tool_results
})
# Vrať finální text response
return next(b.text for b in response.content if b.type == "text")
Efektivní tool design
Pravidlo 1: Jasné descriptions
# ❌ Špatně
{
"name": "query",
"description": "Query database"
}
# ✅ Dobře
{
"name": "search_customers",
"description": "Search for customers by name, email, or ID. Returns up to 10 matching customers with their contact info and order history.",
"input_schema": {...}
}
Pravidlo 2: Striktní schema
# ❌ Příliš volné
{
"input_schema": {
"type": "object",
"properties": {
"data": {"type": "object"} # Příliš vágní
}
}
}
# ✅ Specifické
{
"input_schema": {
"type": "object",
"properties": {
"customer_id": {
"type": "integer",
"description": "Unique customer ID"
},
"include_orders": {
"type": "boolean",
"default": false,
"description": "Include order history"
}
},
"required": ["customer_id"]
}
}
Pravidlo 3: Atomické nástroje
# ❌ Příliš mnoho funkcí v jednom
{
"name": "manage_user",
"description": "Create, read, update, or delete a user"
}
# ✅ Oddělené nástroje
tools = [
{"name": "create_user", "description": "Create a new user"},
{"name": "get_user", "description": "Get user by ID"},
{"name": "update_user", "description": "Update user details"},
{"name": "delete_user", "description": "Delete a user"}
]
Error handling
def execute_tool_safe(name: str, input_data: dict) -> str:
try:
result = execute_tool(name, input_data)
return json.dumps({"success": True, "data": result})
except PermissionError as e:
return json.dumps({
"success": False,
"error": "permission_denied",
"message": str(e)
})
except ValidationError as e:
return json.dumps({
"success": False,
"error": "invalid_input",
"message": str(e)
})
except Exception as e:
return json.dumps({
"success": False,
"error": "internal_error",
"message": "An unexpected error occurred"
})
Parallel tool calling
Claude může volat více nástrojů současně:
response = client.messages.create(
model="claude-opus-4-5-20250101",
max_tokens=1000,
tools=tools,
tool_choice={"type": "any"}, # Povolit multiple tools
messages=[{
"role": "user",
"content": "Get weather in Prague and search for hotels there"
}]
)
# Response může obsahovat multiple tool_use bloky
# Můžete je execute paralelně
import asyncio
async def execute_tools_parallel(tool_uses):
tasks = [
execute_tool_async(t.name, t.input)
for t in tool_uses
]
return await asyncio.gather(*tasks)
Tool choice kontrola
# Claude vybere automaticky
tool_choice={"type": "auto"}
# Musí použít specifický nástroj
tool_choice={"type": "tool", "name": "get_weather"}
# Musí použít alespoň jeden nástroj
tool_choice={"type": "any"}
# Nesmí použít nástroje (jen odpověď)
tool_choice={"type": "none"}
V další lekci se podíváme na multi-step orchestration.