Claude for Developers

Unlock Programmatic Tool Calling in Claude: Build Smarter AI Agents with Full Control

Discover how to take charge of tool use in Claude's API with programmatic calling. Gain precise control for complex workflows, multi-step reasoning, and custom agent behaviors beyond natural tool use.

J

Jennifer Yu

Workflow Automation Specialist

November 29, 2025 min read
Share:

Why Programmatic Tool Calling is a Game-Changer for Claude Developers

Imagine building AI agents that don't just react but execute your exact vision. Programmatic tool calling lets you dictate when and how Claude invokes tools, moving beyond the model's autonomous decisions. This approach shines in scenarios needing intricate logic, error handling, or integration with external systems. Whether you're crafting a data analyst bot or a multi-tool orchestrator, it empowers you to create robust, predictable applications.

In traditional "natural" tool use, Claude decides tool activation based on prompts. But programmatic control flips the script: you inspect responses, trigger tools yourself, and feed results back seamlessly. This method supports streaming for real-time apps and handles parallel tool requests effortlessly.

Key Benefits at a Glance

  • Precision Control: Orchestrate tools in custom sequences, like validating inputs before execution.
  • Complex Workflows: Perfect for agents chaining multiple tools or requiring human-in-the-loop approvals.
  • Streaming Compatibility: Works flawlessly with live UIs, updating as tools process.
  • Error Resilience: Catch and retry tool failures without derailing the conversation.

Let's dive deep into implementation with practical steps and code examples using the Anthropic Python SDK. (Note: No direct GitHub links to external repos in the source, but the SDK is key.)

Step 1: Define Your Tools with Precision

Start by crafting tools Claude can understand. Each tool needs a unique name, a clear description, and an input_schema following JSON Schema standards. This ensures reliable parsing and execution.

Pro Tip: Descriptions should guide Claude on when to suggest the tool, even if you're calling it programmatically. Use strict schemas to prevent invalid inputs.

Here's a practical example for a math calculator and weather checker:

import json
from typing import Any, Dict
from pydantic import BaseModel  # Optional for schema validation

# Tool 1: Calculator
calculator_schema = {
    "type": "object",
    "properties": {
        "expression": {
            "type": "string",
            "description": "Mathematical expression to evaluate, e.g., '2 + 2 * 3'"
        }
    },
    "required": ["expression"]
}

# Tool 2: Weather API Mock
tools = [
    {
        "name": "calculator",
        "description": "Solve complex math problems step-by-step.",
        "input_schema": calculator_schema
    },
    {
        "name": "get_weather",
        "description": "Fetch current weather for a city.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name"}
            },
            "required": ["city"]
        }
    }
]

Real-World Application: In a financial dashboard agent, define tools for stock quotes, risk calculations, and portfolio summaries. Schemas enforce data types, reducing API errors.

Step 2: Kick Off the Conversation

Send your initial user message with tools attached. Use the messages.create endpoint for streaming support.

from anthropic import Anthropic

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

stream = client.messages.create(
    model="claude-3-5-sonnet-20240620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "What's the weather in Paris and what's 15% of 250?"}],
    tools=tools,
    stream=True
)

Claude responds with content and potential tool_use blocks if tools fit. You're now ready to intercept.

Deep Dive: Even in programmatic mode, include tools in every API call. Claude might still generate text suggestions, but you control execution.

Step 3: Detect and Extract Tool Requests in the Stream

Parse the streaming response for tool_use events. Watch content_block_delta where type is tool_use.

message = {"role": "assistant", "content": []}
tool_uses = []

for text_delta in stream:
    if text_delta.type == "content_block_delta":
        delta = text_delta.content_block_delta
        if delta.type == "tool_use":
            # Update ongoing tool_use
            tool_id = delta.tool_use.id
            tool_input = json.loads(delta.tool_use.input.json())  # Parse input
            tool_uses.append({"id": tool_id, "name": delta.tool_use.name, "input": tool_input})
        # Append text deltas to message.content

print(f"Tool requests: {tool_uses}")

Handling Parallels: Claude can request multiple tools simultaneously (e.g., weather + calc). Collect all before proceeding.

Pitfall Alert: Inputs are JSON strings—always parse them safely to avoid injection risks.

Step 4: Execute Tools Locally or Remotely

Now, run the tools yourself. Mock for demos, integrate real APIs for production.

def execute_calculator(expression: str) -> str:
    try:
        result = eval(expression)  # Use safe eval in prod!
        return json.dumps({"result": result})
    except Exception as e:
        return json.dumps({"error": str(e)})

def get_weather(city: str) -> str:
    # Mock API call
    return json.dumps({"temperature": 22, "condition": "sunny"})

# Execute pending tools
tool_results = []
for tool_use in tool_uses:
    if tool_use["name"] == "calculator":
        result = execute_calculator(tool_use["input"]["expression"])
    elif tool_use["name"] == "get_weather":
        result = get_weather(tool_use["input"]["city"])
    tool_results.append({
        "type": "tool_result",
        "tool_use_id": tool_use["id"],
        "content": result
    })

Enhancement Idea: Add logging, retries, or caching. For security, validate inputs against schemas using libraries like pydantic.

Example Output Handling: Results become structured data Claude can reason over, enabling follow-ups like "Compare Paris weather to average."

Step 5: Loop Back Results and Continue the Conversation

Append tool results to the message history and resend. This creates a natural back-and-forth.

message["content"].extend(tool_results)

# Send updated message
response = client.messages.create(
    model="claude-3-5-sonnet-20240620",
    max_tokens=1024,
    messages=[message],  # Now includes tool results
    tools=tools
)

print(response.content[0].text)  # Claude's final reasoned response

Streaming Loop: For interactive apps, wrap in a loop: stream → extract tools → execute → append → repeat until no more tools.

Advanced Techniques and Best Practices

Managing Multi-Turn Interactions

Build agents with persistent history. Track tool_use_ids uniquely across turns.

Error Handling in Action

If a tool fails:

tool_results.append({
    "type": "tool_result",
    "tool_use_id": tool_id,
    "content": "Error: API unavailable. Please try later."
})

Claude adapts gracefully.

Parallel Execution Optimization

Use asyncio for concurrent tool runs:

import asyncio

async def run_tools(tool_uses):
    tasks = [execute_tool(tool) for tool in tool_uses]
    return await asyncio.gather(*tasks)

Real-World Use Case: E-commerce agent: Query inventory (tool1), check prices (tool2), apply discounts (tool3)—all parallel for speed.

Common Gotchas

  • Streaming Sync: Ensure deltas accumulate fully before acting.
  • Schema Evolution: Update descriptions as tools change.
  • Token Limits: Tool inputs/outputs count toward context.

Scaling to Production Agents

Programmatic calling excels in frameworks like LangChain or custom loops. Combine with webhooks for serverless tools or databases for stateful agents.

Metrics to Track: Tool success rate, latency, fallback to text-only.

By mastering this, you'll craft AI that rivals top agents—reliable, efficient, and tailored. Experiment with the SDK today and watch your apps evolve!

(Word count: ~1250)

<div style="text-align: center; margin-top: 2rem;"> <a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a> </div>
The #1 Newsletter in AI

Stay ahead of the AI curve

The most important updates, news, and content — delivered in one weekly newsletter.

No spam. Unsubscribe anytime. Privacy policy

Claude API
Tool Calling
AI Agents
Anthropic SDK
Streaming Tools
ai-agents
J

About Jennifer Yu

Workflow Automation Specialist

Jennifer covers workflow strategy, no-code platforms, and clear implementation guidance for teams adopting automation.

Comments (0)