anth-core-workflow-a

Build Claude tool use (function calling) workflows with the Messages API. Use when implementing tool use, function calling, agent loops, or building AI assistants that interact with external systems. Trigger with phrases like "claude tool use", "anthropic function calling", "claude tools", "agent loop anthropic", "tool_use blocks".

claude-code
5 Tools
anthropic-pack Plugin
saas packs Category

Allowed Tools

ReadWriteEditBash(npm:*)Grep

Provided by Plugin

anthropic-pack

Claude Code skill pack for Anthropic (30 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the anthropic-pack plugin:

/plugin install anthropic-pack@claude-code-plugins-plus

Click to copy

Instructions

Anthropic Core Workflow A — Tool Use (Function Calling)

Overview

Implement Claude's tool use capability where the model can call functions you define. Claude returns tooluse content blocks with structured JSON inputs; your code executes the function and returns toolresult blocks. This is the foundation for building AI agents.

Prerequisites

  • Completed anth-install-auth setup
  • Understanding of the Messages API request/response cycle
  • Functions or APIs you want Claude to call

Instructions

Step 1: Define Tools


import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_weather",
        "description": "Get current weather for a city. Use when the user asks about weather conditions.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name, e.g. 'San Francisco, CA'"
                },
                "units": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Temperature units"
                }
            },
            "required": ["city"]
        }
    },
    {
        "name": "search_database",
        "description": "Search product database by query string. Returns matching products.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "max_results": {"type": "integer", "default": 10}
            },
            "required": ["query"]
        }
    }
]

Step 2: Send Request with Tools


message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}]
)

# Claude responds with stop_reason="tool_use"
# message.content contains both text and tool_use blocks:
# [
#   {"type": "text", "text": "I'll check the weather for you."},
#   {"type": "tool_use", "id": "toolu_01A...", "name": "get_weather",
#    "input": {"city": "Tokyo", "units": "celsius"}}
# ]

Step 3: Execute Tool and Return Result


def execute_tool(name: str, input_data: dict) -> str:
    """Route tool calls to actual implementations."""
    if name == "get_weather":
        # Call your weather API
        return '{"temp": 22, "condition": "partly cloudy", "humidity": 65}'
    elif name == "search_database":
        return '{"results": [{"name": "Widget A", "price": 29.99}]}'
    raise ValueError(f"Unknown tool: {name}")

# Extract tool_use blocks and execute
tool_results = []
for block in message.content:
    if block.type == "tool_use":
        result = execute_tool(block.name, block.input)
        tool_results.append({
            "type": "tool_result",
            "tool_use_id": block.id,  # Must match the tool_use block id
            "content": result
        })

# Continue conversation with tool results
follow_up = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[
        {"role": "user", "content": "What's the weather in Tokyo?"},
        {"role": "assistant", "content": message.content},
        {"role": "user", "content": tool_results}
    ]
)

print(follow_up.content[0].text)
# "The current weather in Tokyo is 22°C and partly cloudy with 65% humidity."

Step 4: Agentic Loop (Multiple Tool Calls)


def run_agent(user_message: str, tools: list, max_turns: int = 10) -> str:
    """Run an agentic loop that handles multiple sequential tool calls."""
    messages = [{"role": "user", "content": user_message}]

    for _ in range(max_turns):
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

        # If Claude is done (no more tool calls), return final text
        if response.stop_reason == "end_turn":
            return next(
                (b.text for b in response.content if b.type == "text"), ""
            )

        # Process tool calls
        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})

    return "Max turns reached"

Output

  • Tool definitions with JSON Schema input validation
  • Agent loop handling sequential tool calls
  • Proper tooluse / toolresult message threading

Error Handling

Error Cause Solution
invalidrequesterror: tool schema invalid Malformed input_schema Validate against JSON Schema spec
tooluseid mismatch Result ID doesn't match tool_use ID Copy block.id exactly
Claude ignores tools Description too vague Add clear "Use when..." descriptions
Infinite loop Claude keeps calling tools Add maxturns guard + toolchoice: {"type": "auto"}

Tool Choice Options


# Let Claude decide (default)
tool_choice={"type": "auto"}

# Force Claude to use a specific tool
tool_choice={"type": "tool", "name": "get_weather"}

# Force Claude to use any tool (must call at least one)
tool_choice={"type": "any"}

Resources

Next Steps

For streaming with tools, see anth-core-workflow-b.

Ready to use anthropic-pack?