The Intern Who Couldn’t Read
Let’s talk about Steve. We hired Steve as our new customer support intern. Great attitude, works hard, always smiling. One problem: Steve is a disaster.
His only job is to answer one question: “Where’s my order?” He has a single spreadsheet with two columns: order_id and status. When a customer emails with an order number, Steve finds the row and replies with the status.
On Monday, he told a customer their order was “Delivered” when it was “Processing.” On Tuesday, he mixed up order #8675 with #8765 and promised a refund for an order that was already on a truck. By Wednesday, my inbox was a war zone of angry customers. Steve felt terrible. I felt like pulling my hair out.
The problem wasn’t Steve. The problem was the process. It was manual, boring, and begging for human error. So, we fired Steve. Kidding. We promoted Steve to a job that requires creativity. And we gave his old job to a robot that literally cannot misread a spreadsheet. That robot is what you’re here to build today.
Why This Matters
Most people think of AI as a very smart, very fast search engine. You ask it a question, it gives you an answer. That’s a toy.
Today, we turn the toy into a tool. We’re building the bridge between the AI’s “brain” and the real world. This technology, called Function Calling or Tool Use, lets the AI ask for real-world information or trigger real-world actions.
Instead of just talking about a customer’s order, it can check the database. Instead of writing an email about a new user, it can create the user in your CRM. It replaces the error-prone, manual work that interns like Steve get stuck with. This is how you automate business processes, reduce errors to zero, and build systems that scale while you sleep.
What This Tool / Workflow Actually Is
Anthropic Claude’s Tool Use feature is a way to make the AI request structured data to perform an action. Here’s the key concept everyone gets wrong: The AI does not run the code.
Think of it like this: You give the AI a menu of special abilities, or “tools.” When a user asks something, the AI checks its menu. If a tool can help, it doesn’t perform the action itself. Instead, it taps you on the shoulder and hands you a perfectly filled-out order form.
The order form says, “Hey, I need you to run the get_order_status tool with this exact ID: 'XYZ-123'.”
Your application code takes that form, runs the *actual* function, gets the result (e.g., “Shipped”), and hands the result back to the AI. The AI then uses that fresh information to give the user a friendly, natural language answer.
What it does: It intelligently structures user requests into machine-readable instructions (JSON).
What it does NOT do: It does not have access to your computer, it cannot execute your Python functions, and it cannot browse the web or access your database on its own.
Prerequisites
This is where people get nervous. Don’t be. If you can copy and paste, you can do this.
- An Anthropic API Key: You need an account with Anthropic to use the Claude API. If you don’t have one, get one from their website. It’s mostly free to start.
- Basic Python: I mean basic. We’ll be using Python, a language so friendly it practically apologizes for being a programming language. You don’t need to be an expert. I’ll provide every line of code.
- A place to run Python: The easiest is Google Colab (it’s free and runs in your browser). Or you can run it on your own computer if you have Python installed.
That’s it. No servers, no complex software. Just you, me, and a few lines of code.
Step-by-Step Tutorial
Let’s build the robot that replaces manual order lookups. I’ll explain each step and why it exists.
Step 1: Setup Your Python Environment
First, we need to install the official Anthropic library and configure our API key. Run this command in your terminal or a Colab cell:
pip install anthropic
Now, let’s write the setup code. Replace 'YOUR_API_KEY' with your actual key.
import anthropic
client = anthropic.Anthropic(
# This defaults to getting the key from the ANTHROPIC_API_KEY environment variable
api_key="YOUR_API_KEY",
)
Step 2: Define Your Tool for the AI
This is the most important step. We have to create the “menu” that we give to the AI. This is a JSON object that describes our tool. The description field is critical—it’s how Claude knows *when* to use the tool.
# This is our fake database of orders
FAKE_ORDER_DB = {
"ABC-123": {"status": "Shipped", "tracking_number": "TN987654321"},
"DEF-456": {"status": "Processing", "expected_ship_date": "2024-08-15"},
"GHI-789": {"status": "Delivered", "signed_by": "Jane Doe"},
}
# The function our code will actually run
def get_order_status(order_id):
print(f"--- Searching for order: {order_id} ---")
return FAKE_ORDER_DB.get(order_id, {"status": "Not Found"})
# The tool definition we show to Claude
order_status_tool = {
"name": "get_order_status",
"description": "Get the current status of a customer's order given an order ID. Use this tool anytime a user asks about their order.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The unique identifier for the order, e.g., ABC-123"
}
},
"required": ["order_id"]
}
}
Step 3: The First API Call (User Asks a Question)
Now, a user asks about their order. We send their question, plus our tool menu, to Claude.
user_message = "Hey, can you tell me where my order ABC-123 is?"
print(f"User: {user_message}")
message = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[{"role": "user", "content": user_message}],
tools=[order_status_tool] # Here's our tool menu!
)
print(f"\
API Response Stop Reason: {message.stop_reason}")
If you run this, you’ll see the output is tool_use. The AI didn’t answer. It’s handing us that order form we talked about.
Step 4: Handle the AI’s Request
The AI’s response contains instructions. Our job is to find those instructions, run our real function, and prepare the result to send back.
tool_call = None
if message.stop_reason == "tool_use":
# Find the tool use block
tool_call = next((block for block in message.content if block.type == 'tool_use'), None)
if tool_call:
tool_name = tool_call.name
tool_input = tool_call.input
tool_use_id = tool_call.id
print(f"\
Claude wants to use the tool: '{tool_name}' with input: {tool_input}")
# Here's where we call our *actual* Python function
tool_result = get_order_status(order_id=tool_input.get("order_id"))
print(f"--- Tool result: {tool_result} ---")
else:
# The AI just answered normally, no tool was needed.
print("\
AI did not use a tool.")
Step 5: The Second API Call (Sending the Result Back)
The final step. We go back to Claude with everything that’s happened so far: the user’s original question, the AI’s decision to use a tool, and the result we got from running it. This gives the AI all the context it needs to form a perfect final answer.
# Construct the conversation history
conversation = [
{"role": "user", "content": user_message},
{"role": "assistant", "content": message.content}, # Claude's first response (the tool_use request)
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": str(tool_result)
}
]
}
]
# Send the result back to Claude
final_response = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=conversation,
tools=[order_status_tool]
)
final_answer = final_response.content[0].text
print(f"\
Final AI Answer: {final_answer}")
The output will be something beautiful and simple like: “Of course! The status for your order ABC-123 is ‘Shipped’, and the tracking number is TN987654321.”
Complete Automation Example
Here is the entire script from start to finish. You can copy, paste, and run this in a single file. Change the order_id_to_check to see different results.
import anthropic
# 1. CONFIGURE THE CLIENT
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# 2. DEFINE YOUR FUNCTION AND TOOL
FAKE_ORDER_DB = {
"ABC-123": {"status": "Shipped", "tracking_number": "TN987654321"},
"DEF-456": {"status": "Processing", "expected_ship_date": "2024-08-15"},
}
def get_order_status(order_id):
print(f"--- LOG: Calling our real database for order {order_id}... ---")
return FAKE_ORDER_DB.get(order_id, {"status": "Not Found"})
order_status_tool = {
"name": "get_order_status",
"description": "Get the status of a customer's order. Use this for any questions about order status, tracking, or delivery.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "The order ID, e.g., ABC-123"}
},
"required": ["order_id"]
}
}
# 3. KICK OFF THE WORKFLOW
user_message = "what is the status of my order DEF-456?"
print(f"User: {user_message}")
# First call to Claude: Let it decide to use the tool
initial_response = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[{"role": "user", "content": user_message}],
tools=[order_status_tool]
)
# 4. HANDLE THE TOOL USE
if initial_response.stop_reason == "tool_use":
tool_call = next(block for block in initial_response.content if block.type == 'tool_use')
tool_name = tool_call.name
tool_input = tool_call.input
tool_use_id = tool_call.id
print(f"Claude wants to run '{tool_name}' with input {tool_input}")
# Call your actual function
tool_result = get_order_status(order_id=tool_input.get("order_id"))
# Second call to Claude: Send the result back
final_response = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[
{"role": "user", "content": user_message},
{"role": "assistant", "content": initial_response.content},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": str(tool_result) # Content must be a string
}
]
}
],
tools=[order_status_tool]
)
final_answer = final_response.content[0].text
print(f"\
Final Answer: {final_answer}")
else:
# This happens if the AI can answer without the tool
final_answer = initial_response.content[0].text
print(f"\
Final Answer (no tool used): {final_answer}")
Real Business Use Cases
This pattern is everywhere. Once you see it, you can’t unsee it.
- SaaS Onboarding: A chatbot asks a new user for their company name and domain. It then uses a
create_new_account(company_name, domain)tool to provision a new workspace for them instantly. - Financial Services: A client asks a robo-advisor, “What’s my portfolio balance and how did Apple do today?” The AI uses two tools:
get_portfolio_balance(client_id)andget_stock_price(ticker='AAPL'), then combines the results into one summary. - Real Estate: A potential buyer tells a website, “I’m looking for a 3-bedroom house in Brooklyn under $1M.” The site uses a
search_property_listings(city, bedrooms, max_price)tool to query its database and display matching homes. - Internal IT Support: An employee types into Slack, “My laptop is making a weird noise.” The AI bot uses a
create_support_ticket(employee_name, issue_description)tool to automatically log the problem in Jira or ServiceNow. - Lead Qualification: A visitor on a marketing site says, “I want a demo for my 50-person sales team.” The AI uses a
update_crm_lead(email, company_size, interest)tool to update their record in Salesforce, tag them as a high-priority lead, and alert the sales team.
Common Mistakes & Gotchas
- Bad Descriptions: The tool’s
descriptionis for the AI, not you. Be painfully explicit. Bad: “Gets orders.” Good: “Use this function to retrieve the complete status, including tracking number and delivery date, for a customer’s order using their unique order ID.” - Ignoring Non-Tool Responses: Sometimes Claude will just answer the user’s question without using a tool (e.g., if they just say “hello”). Your code needs to handle this gracefully and not crash if a
tool_useblock isn’t found. - Data Security: Never, ever create a tool that does something destructive like
delete_database(confirm=True). And always treat inputs from the AI as untrusted. Sanitize and validate them before executing anything. The AI is smart, but it’s not security-audited. - Forgetting to Send the Result: The most common mistake. You run your function and then… nothing. You MUST make the second API call to send the result back to Claude. Otherwise, the AI is left hanging, forever waiting for the information it asked for.
How This Fits Into a Bigger Automation System
What we built today is a single gear in a much larger machine. It’s a critical one, but it’s just the start.
- CRM Integration: Imagine the
get_order_statustool doesn’t just read a fake database, but makes a real API call to your Shopify, Salesforce, or custom internal CRM. - Email/SMS: You could have another tool called
send_customer_update(order_id, message). The AI could check the status, then use this second tool to automatically text the customer an update. - Voice Agents: Connect this system to a voice API like Twilio. The user calls a number, their speech is converted to text, fed into our script, and the final text answer is converted back to speech. You’ve just built an AI-powered phone agent.
- Multi-Agent Workflows: One agent (a “Triage Bot”) could handle initial user chat. If it decides the user needs an order status, it doesn’t call the tool itself. It passes the task to a specialized “Order Bot” that only has access to order-related tools. This is how you build secure and robust systems.
What to Learn Next
Congratulations. You just gave your AI hands. It can now interact with the world beyond simple text. You’ve built a real, working automation that is more reliable than any human intern for that specific task.
But right now, our robot only knows how to use one tool—a hammer. What happens when a problem requires a hammer, a screwdriver, AND a wrench?
In the next lesson in this course, we’re going to give our AI a full toolbox. You’ll learn how to make it intelligently choose between multiple tools, and even chain them together to solve complex, multi-step problems. Get ready, because we’re about to go from building a digital intern to building a digital assembly line.
Stay sharp. I’ll see you in the next class.
“,
“seo_tags”: “Claude API, AI Automation, Function Calling, Tool Use, Python, Anthropic, Business Automation, API Tutorial”,
“suggested_category”: “AI Automation Courses

