Tool Use and Function Calling
A model can only write text. Tool use, also called function calling, lets it ask your program to run a function and send back the result. This is the mechanism that turns a model into something that can act.
How it works
- You describe the available tools to the model.
- The user asks something.
- The model replies either with an answer, or with a request to call a tool with particular arguments.
- Your code runs the tool. The model never executes anything itself.
- You send the result back to the model.
- The model uses the result to answer, or asks for another tool.
Defining a tool
A tool definition has a name, a description and a schema for its inputs, written as JSON Schema.
{
"name": "get_order_status",
"description": "Look up the current status of a customer order. Use this
whenever the customer asks where an order is or when it will arrive.
Returns the status, the carrier and the expected delivery date.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order number, for example A-10432"
}
},
"required": ["order_id"]
}
}
The description is a prompt
The model chooses tools by reading their descriptions. Write each one as you would explain the tool to a new colleague:
- what it does,
- when to use it and when not to,
- what each parameter means, with an example,
- what it returns.
Vague descriptions are the most common cause of a model choosing the wrong tool or passing the wrong arguments.
The exchange in code
This example uses a scripted stand-in for the model so that it runs in your browser. The stand-in returns the same kinds of message a real model would.
import json
# 1. the tools, as ordinary functions
ORDERS = {"A-10432": {"status": "in transit", "carrier": "Swiftline", "expected": "2026-10-14"}}
def get_order_status(order_id):
return ORDERS.get(order_id, {"error": f"no order found with id {order_id}"})
TOOLS = {"get_order_status": get_order_status}
# 2. a scripted stand-in for the model
def fake_model(messages):
last = messages[-1]
if last["role"] == "user":
return {"type": "tool_call", "name": "get_order_status", "arguments": {"order_id": "A-10432"}}
result = json.loads(last["content"])
return {"type": "text", "text": f"Your order is {result['status']} with {result['carrier']} "
f"and should arrive on {result['expected']}."}
# 3. the exchange
messages = [{"role": "user", "content": "Where is my order A-10432?"}]
reply = fake_model(messages)
print("model asks for:", reply)
result = TOOLS[reply["name"]](**reply["arguments"])
print("tool returned: ", result)
messages.append({"role": "tool", "content": json.dumps(result)})
print("model answers: ", fake_model(messages)["text"])
With a real model, fake_model is replaced by an API call that includes the tool definitions. The structure of the exchange is the same.
Validate before you run
The arguments come from a model. Treat them as untrusted input.
def safe_call(tools, name, arguments, allowed_statuses=None):
if name not in tools:
return {"error": f"unknown tool: {name}"}
order_id = arguments.get("order_id")
if not isinstance(order_id, str) or not order_id.startswith("A-"):
return {"error": "order_id must be a string such as A-10432"}
return tools[name](order_id)
tools = {"get_order_status": lambda order_id: {"status": "in transit"}}
print(safe_call(tools, "get_order_status", {"order_id": "A-10432"}))
print(safe_call(tools, "get_order_status", {"order_id": 10432}))
print(safe_call(tools, "delete_everything", {}))
Return errors as results
When a tool fails, send the error back to the model as the result, with a message that explains what went wrong. The model can often correct its input and try again. An exception that crashes the program teaches it nothing.
Designing good tools
- Give each tool one clear purpose, and a name that says what it does.
- Avoid overlap. Two tools that do nearly the same thing confuse the choice.
- Return only what is useful. A large result fills the context window. Summarise or let the model ask for detail.
- Make inputs hard to get wrong. Prefer a fixed list of allowed values to free text.
- Prefer a few capable tools to dozens of narrow ones.
- Separate reading from changing. A tool that only reads is safe to call freely. A tool that changes something deserves more care, which a later lesson covers.
Common kinds of tool
| Kind | Examples |
|---|---|
| Information | Web search, database queries, document retrieval |
| Computation | A calculator, running code |
| Action | Sending a message, creating a ticket, updating a record |
| Environment | Reading and writing files, using a browser |
Practice
Write a tool definition for search_products, which takes a search phrase and an optional maximum price. Make the description clear enough that a model would know when to use it.