Lesson 9 of 30 ~15 min
Course progress
0%

Tool Calling Patterns

Naučte se efektivně definovat a používat nástroje pro Claude.

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.