Skip to main content

View Source Code

Check out the full source code for this example on GitHub.
This tutorial demonstrates how to build an Agent with Tool Calling using Tensorlake and the Anthropic API. This agent orchestrates a multi-step workflow where Claude decides which tools to call and in what order to answer user queries effectively.

Overview

The Agent with Tool Calling follows this pattern:
  1. User Query: The user asks a question that requires external data or actions (e.g., “What’s the weather like at my current location?”).
  2. Tool Selection: Claude analyzes the query and selects the appropriate tool(s) to call (e.g., get_ip_address, get_location_info).
  3. Tool Execution: The selected tool functions are executed within Tensorlake’s isolated environment.
  4. Information Synthesis: The tool outputs are fed back to Claude, which then synthesizes a final answer or decides to call more tools.

Prerequisites

  • Python 3.11+
  • Tensorlake Account and CLI installed.
  • Anthropic API Key

Implementation (app.py)

Here is the complete implementation for the Agent with Tool Calling.
import os
from typing import Dict, Any

from anthropic import Anthropic
from pydantic import BaseModel, Field
from tensorlake import application, function, Image

# Define the runtime environment
image = Image(name="agent-with-tools").run("pip install anthropic requests tensorlake pydantic")

class ToolInput(BaseModel):
    name: str
    arguments: Dict[str, Any]

@application()
@function(image=image, secrets=["ANTHROPIC_API_KEY"])
def agent_loop(query: str) -> str:
    """
    Main entry point for the Agent with Tool Calling.
    Orchestrates the conversation loop between Claude and the tools.
    """
    client = Anthropic()
    messages = [{"role": "user", "content": query}]
    
    # Define available tools for Claude
    tools = [
        {
            "name": "get_ip_address",
            "description": "Get the public IP address of the current execution environment.",
            "input_schema": {"type": "object", "properties": {}}
        },
        {
            "name": "get_location_info",
            "description": "Get location information based on an IP address.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "ip_address": {"type": "string", "description": "The IP address to lookup."}
                },
                "required": ["ip_address"]
            }
        },
        {
            "name": "get_weather_alerts",
            "description": "Get current weather alerts for a location.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City or location name."}
                },
                "required": ["location"]
            }
        }
    ]

    while True:
        # Ask Claude for the next step
        response = client.messages.create(
            model="claude-3-opus-20240229",
            max_tokens=1024,
            tools=tools,
            messages=messages
        )
        
        # If Claude decides to stop and give an answer
        if response.stop_reason == "end_turn":
            return response.content[0].text

        # If Claude wants to use a tool
        if response.stop_reason == "tool_use":
            tool_use = next(block for block in response.content if block.type == "tool_use")
            tool_name = tool_use.name
            tool_input = tool_use.input
            tool_use_id = tool_use.id

            print(f"Tool Call: {tool_name} with input: {tool_input}")
            
            # Execute the requested tool
            if tool_name == "get_ip_address":
                tool_result = get_ip_address()
            elif tool_name == "get_location_info":
                tool_result = get_location_info(tool_input["ip_address"])
            elif tool_name == "get_weather_alerts":
                tool_result = get_weather_alerts(tool_input["location"])
            else:
                tool_result = f"Error: Tool {tool_name} not found."

            # Add tool result to conversation history
            messages.append({"role": "assistant", "content": response.content})
            messages.append({
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": tool_use_id,
                        "content": str(tool_result)
                    }
                ]
            })

@function(image=image)
def get_ip_address() -> str:
    """Simulates getting the public IP address."""
    # In a real scenario, you might use `requests.get('https://api.ipify.org').text`
    return "203.0.113.1"

@function(image=image)
def get_location_info(ip_address: str) -> str:
    """Simulates getting location info for an IP."""
    return f"Location for {ip_address}: San Francisco, CA"

@function(image=image)
def get_weather_alerts(location: str) -> str:
    """Simulates getting weather alerts."""
    return f"No active weather alerts for {location}."

Running Locally

To test the agent locally, add this code block to the end of app.py:
if __name__ == "__main__":
    from tensorlake.applications import run_local_application
    
    # Run the application locally
    result = run_local_application(agent_loop, "What are the current weather alerts for my location?")
    print(f"Agent Output: {result}")
Then run the script:
export ANTHROPIC_API_KEY=your_key_here
python app.py

Deploying to Tensorlake

Deploy your agent to the cloud for production use:
tensorlake secrets set ANTHROPIC_API_KEY=your_key_here
tensorlake deploy app.py
Your agent is now live! It can autonomously chain tool calls to solve complex user requests, all running within secure, scalable Tensorlake functions.