Ever asked Claude to multiply two big numbers, only to have it confidently give you an answer that’s completely wrong when you check with a calculator?

Don’t blame the AI. Claude is fundamentally a language model — its superpower is understanding and generating text, not crunching numbers. It’s like that colleague at work who writes brilliant copy but ask them to do a spreadsheet and you’re setting them up to fail.

But smart people have workarounds. Can’t do math? Call a calculator. Can’t look up data? Call a database. That’s what we’re talking about today: Tool Use, also known as Function Calling. In prompt engineering, this is the technique that truly levels up AI programming. The idea is dead simple — teach AI to “make phone calls.” When it can’t handle something on its own, it picks up the phone, calls a specialist tool, gets the result, and carries on.


What Exactly Is Tool Use? An Ordering Takeout Story

Imagine you’re sitting in the office, your stomach is growling, and you’re craving some chicken rice. You can’t cook (just like Claude can’t actually run code), but you sure know how to order delivery:

  1. You tell the delivery app: I want chicken rice, medium spicy, one serving of rice (tool name and parameters)
  2. The app places the order, the restaurant starts cooking (tool executes)
  3. Food arrives, you eat (get the result, carry on with your day)

Tool Use follows the exact same flow. Claude won’t actually call a calculator or database directly, but it says: “I need to call the calculator tool with parameters 1984135 times 9343116.” Then your code runs the calculation, feeds the result back to Claude, and Claude tells the user the answer in plain language.

Break it down step by step:

  1. Claude states which tool it wants to call and what parameters to pass (placing the order)
  2. Your code executes the tool while Claude waits (waiting for delivery)
  3. You pass the result back to Claude, and it continues answering the user (food’s here, time to eat)

It’s really just a combo of substitution and prompt chaining that we learned before. Previously we stuffed text into prompts — now we’re stuffing tool execution results. Same playbook, different jersey.


Hands-On: Give Claude a Calculator

Enough theory — let’s write some code. The task is straightforward: give Claude a calculator tool so it can do its own math when a math problem comes up.

Step 1: Tell Claude What Tools Are Available

This is like your first day at a new job when the boss introduces the company directory: “Procurement? Call Zhang. Finance? Call Li. Tech? Call Wang.” You need to know who can help before you know who to call.

The system prompt has two parts. The first is the “general instructions” that explain the format and rules for tool calls:

system_prompt_tools_general_explanation = """You have access to a set of functions
you can use to answer the user's question.

You can invoke functions using this format:
<function_calls>
<invoke name="$FUNCTION_NAME">
<parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</parameter>
</invoke>
</function_calls>

Results will appear in a <function_results> block.
After getting results, you can continue answering the user's question."""

The second part is the “specific tool list” — the actual directory:

system_prompt_tools_specific_tools = """Available tools:
<tools>
<tool_description>
<tool_name>calculator</tool_name>
<description>
Basic arithmetic calculator supporting addition,
subtraction, multiplication, and division
</description>
<parameters>
<parameter>
<name>first_operand</name>
<type>int</type>
<description>First operand (before the operator)</description>
</parameter>
<parameter>
<name>second_operand</name>
<type>int</type>
<description>Second operand (after the operator)</description>
</parameter>
<parameter>
<name>operator</name>
<type>str</type>
<description>The operation to perform. Must be +, -, *, or /</description>
</parameter>
</parameters>
</tool_description>
</tools>
"""

# Combine them into the complete system prompt
system_prompt = system_prompt_tools_general_explanation + system_prompt_tools_specific_tools

Notice the structure of the tool description: name, what it does, parameter list (each with name, type, and description). The clearer you write it, the better Claude uses it. It’s like writing delivery notes — “medium spicy, no cilantro, extra garlic” is way more reliable than just “make it normal.”

Step 2: Let Claude Call the Tool When It Hits a Math Problem

multiplication_message = {
    "role": "user",
    "content": "Multiply 1,984,135 by 9,343,116"
}

stop_sequences = ["</function_calls>"]

# Claude's response
function_calling_response = get_completion(
    [multiplication_message],
    system_prompt=system_prompt,
    stop_sequences=stop_sequences
)
print(function_calling_response)

Key detail: stop_sequences=["</function_calls>"]. This means the moment Claude outputs the </function_calls> tag, it pauses immediately. Why pause? Because Claude has “placed its order” and is waiting for you to execute the tool. If you don’t pause it, it’ll just make up a result on its own — and that defeats the whole purpose.

Claude will respond with something like:

<function_calls>
<invoke name="calculator">
<parameter name="first_operand">1984135</parameter>
<parameter name="second_operand">9343116</parameter>
<parameter name="operator">*</parameter>
</invoke>

See? Claude figured out on its own that it should use the calculator tool, and filled in the parameters correctly. It’s not doing math — it’s placing an order.

Step 3: Execute the Tool, Get the Result

Now it’s your code’s turn to shine. Define a real calculation function:

def do_pairwise_arithmetic(num1, num2, operation):
    if operation == '+':
        return num1 + num2
    elif operation == "-":
        return num1 - num2
    elif operation == "*":
        return num1 * num2
    elif operation == "/":
        return num1 / num2
    else:
        return "Error: Operation not supported."

Then extract the parameters from Claude’s response and call the function:

def find_parameter(message, parameter_name):
    """Extract a parameter value from Claude's response"""
    parameter_start_string = f'name="{parameter_name}">'
    start = message.index(parameter_start_string)
    start = start + len(parameter_start_string)
    end = start
    while message[end] != "<":
        end += 1
    return message[start:end]

# Extract the three parameters
first_operand = find_parameter(function_calling_response, "first_operand")
second_operand = find_parameter(function_calling_response, "second_operand")
operator = find_parameter(function_calling_response, "operator")

# Actually run the calculation
result = do_pairwise_arithmetic(int(first_operand), int(second_operand), operator)
print(f"Result: {result:,}")
# Output: 18,535,584,938,460

That number is precise — it’s not Claude making it up. The calculation was done by Python, not guessed by a language model.

Step 4: Feed the Result Back to Claude

We have our result, but we need to package it in the agreed format so Claude can recognize it. Like a package needs a tracking number, results need their “labels”:

def construct_function_results(invoke_results):
    """Package tool results in a format Claude can recognize"""
    constructed_prompt = (
        "<function_results>\n"
        + '\n'.join(
            f"<result>\n<tool_name>{res['tool_name']}</tool_name>\n"
            f"<stdout>\n{res['tool_result']}\n</stdout>\n</result>"
            for res in invoke_results
        ) + "\n</function_results>"
    )
    return constructed_prompt

# Package the result
formatted_results = [{
    'tool_name': 'calculator',
    'tool_result': result
}]
function_results = construct_function_results(formatted_results)

Finally, stitch together the full conversation (user question + Claude’s tool call + tool result) and let Claude continue answering:

# Append the truncated closing tag to Claude's first response
full_first_response = function_calling_response + "</function_calls>"

# Build the complete conversation chain
messages = [
    multiplication_message,                                # User's question
    {"role": "assistant", "content": full_first_response}, # Claude calls tool
    {"role": "user", "content": function_results}          # Tool returns result
]

# Claude's final answer
final_response = get_completion(messages, system_prompt=system_prompt)
print(final_response)

Claude responds with something like:

1,984,135 multiplied by 9,343,116 equals 18,535,584,938,460.

This time the answer is dead accurate, because the calculator did the math — Claude just handled understanding the question and communicating the result.


Where Claude Gets Smart: Knowing When NOT to Use a Tool

You might wonder: now that Claude has a calculator, does it try to use it for everything?

Nope. Check this out:

non_multiplication_message = {
    "role": "user",
    "content": "What's the capital of France?"
}

function_calling_response = get_completion(
    [non_multiplication_message],
    system_prompt=system_prompt,
    stop_sequences=stop_sequences
)
print(function_calling_response)

Claude just answers directly: “The capital of France is Paris.” No calculator call at all.

That’s the right behavior. Telling your colleague “come to me if you have questions” doesn’t mean they bug you about every little thing. Claude works the same way — no tool needed, no tool called. Only reaches for it when it actually matters.


Advanced Exercise: Give Claude a Mini Database

A calculator alone is too boring. Let’s try something more realistic — give Claude a database so it can look up users, look up products, and add records.

First, prepare the database (really just a Python dictionary — the world’s smallest “database”):

db = {
    "users": [
        {"id": 1, "name": "Alice", "email": "alice@example.com"},
        {"id": 2, "name": "Bob", "email": "bob@example.com"},
        {"id": 3, "name": "Charlie", "email": "charlie@example.com"}
    ],
    "products": [
        {"id": 1, "name": "Widget", "price": 9.99},
        {"id": 2, "name": "Gadget", "price": 14.99},
        {"id": 3, "name": "Doohickey", "price": 19.99}
    ]
}

Then write four operation functions:

def get_user(user_id):
    """Look up a user by ID"""
    for user in db["users"]:
        if user["id"] == user_id:
            return user
    return None

def get_product(product_id):
    """Look up a product by ID"""
    for product in db["products"]:
        if product["id"] == product_id:
            return product
    return None

def add_user(name, email):
    """Add a new user"""
    user_id = len(db["users"]) + 1
    user = {"id": user_id, "name": name, "email": email}
    db["users"].append(user)
    return user

def add_product(name, price):
    """Add a new product"""
    product_id = len(db["products"]) + 1
    product = {"id": product_id, "name": name, "price": price}
    db["products"].append(product)
    return product

Now here’s the key part — you need to write a system prompt that gives Claude the “user manual” for all four tools. Spell out the name, purpose, parameters, and types for each one.

system_prompt_tools_specific_tools_sql = """Available tools:
<tools>
<tool_description>
<tool_name>get_user</tool_name>
<description>Look up user info by user ID</description>
<parameters>
<parameter>
<name>user_id</name>
<type>int</type>
<description>The user ID to look up</description>
</parameter>
</parameters>
</tool_description>

<tool_description>
<tool_name>get_product</tool_name>
<description>Look up product info by product ID</description>
<parameters>
<parameter>
<name>product_id</name>
<type>int</type>
<description>The product ID to look up</description>
</parameter>
</parameters>
</tool_description>

<tool_description>
<tool_name>add_user</tool_name>
<description>Add a new user to the database</description>
<parameters>
<parameter>
<name>name</name>
<type>str</type>
<description>The user's name</description>
</parameter>
<parameter>
<name>email</name>
<type>str</type>
<description>The user's email address</description>
</parameter>
</parameters>
</tool_description>

<tool_description>
<tool_name>add_product</tool_name>
<description>Add a new product to the database</description>
<parameters>
<parameter>
<name>name</name>
<type>str</type>
<description>The product name</description>
</parameter>
<parameter>
<name>price</name>
<type>float</type>
<description>The product price</description>
</parameter>
</parameters>
</tool_description>
</tools>
"""

Test it with a few examples:

examples = [
    "Add a user named Deborah to the database.",
    "Add a product called Thingo.",
    "Tell me the name of User 2.",
    "Tell me the name of Product 3."
]

Claude will call add_user, add_product, get_user, and get_product respectively, with all the parameters filled in correctly. All you need to do is parse the parameters, call the corresponding Python functions, and feed the results back.


Common Pitfalls and How to Avoid Them

Sloppy Tool Descriptions

Claude picks tools and fills parameters based entirely on your tool descriptions. Vague descriptions lead to wrong tool picks and wrong parameters.

Write tool descriptions like product manuals. Clear names, precise functionality, parameter descriptions with types and valid ranges. Don’t cut corners — this is where the real work happens in the entire Tool Use pipeline.

Forgetting to Set stop_sequences

Without stop_sequences, Claude finishes outputting the tool call format and then keeps going, making up a fake result on its own. That completely defeats the purpose of Tool Use.

stop_sequences=["</function_calls>"] — add it every single time. This tells Claude “stop here and wait for the real result.”

Wrong Result Format

Claude recognizes the <function_results> tag. If you don’t return results in the right format, Claude can’t read them and will either throw errors or start hallucinating.

Stick strictly to the template for packaging results — tool name and execution result are both mandatory. Use the construct_function_results function we wrote above; don’t reinvent the wheel.

Fragile Parameter Parsing

The example uses string searching to extract parameters. It works, but it’s brittle. If Claude’s response format varies slightly (extra spaces, different line breaks), parsing could blow up.

For production, use an XML parsing library to extract parameters, or better yet, use Anthropic’s official Tool Use API. It returns structured JSON — no manual parsing needed.


Cheatsheet: Tool Use Core Flow

Remember this flowchart:

User asks a question
    |
    v
Claude analyzes: Do I need a tool?
    |           |
   No          Yes
    |           |
 Answer      Output tool call (name + params)
 directly        |
                 v
             Your code executes the tool
                 |
                 v
             Return result to Claude in the right format
                 |
                 v
             Claude uses the result to answer the user

One-liner version: Claude places the order, your code does the legwork, result comes back and Claude keeps talking.


Wrap-Up

Let’s recap: Claude doesn’t actually execute tools — it just says “I want to call xxx with parameters yyy,” and your code does the actual work. Clear tool descriptions mean accurate calls; vague descriptions mean wild guesses. The whole flow is Claude placing orders, code running errands, results coming back — fundamentally a combination of substitution and prompt chaining.

What to Try Next

  • Give Claude a weather lookup tool so it can answer “What’s the weather like in New York today?”
  • Combine multiple tools so Claude can call different ones in a single conversation to handle complex tasks
  • Check out Anthropic’s official Tool Use API — way more convenient than hand-parsing XML, with structured JSON responses and built-in parameter extraction and error handling

What tool would you most want to give your AI? Calculator, database, or maybe the ability to send emails? Drop a comment below.


If this was helpful, give it a like or share it with someone learning AI development. Follow Dream Beast Programming for more content on search and retrieval-augmented generation coming up next. Questions? Hit the comments anytime.