Tool & Function Calling
Reviewed & published by Brayan K
Tool use (also called function calling) lets an AI ask your code to run a defined task and then continue with the result. You describe each tool; the model returns a structured call; your code runs it and hands back the answer.
Part of the free Prompt Engineering course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
This unlocks live data, private information, and real actions the model cannot do from memory alone. This lesson walks through the call, execute, observe loop.
What You'll Learn in This Lesson
- What tool use / function calling means
- Describing a tool: name, description, parameter schema
- How the model returns a structured tool call
- Your code executes it and returns the result
- The call, execute, observe loop in full
- When to use tools vs plain prompting
1 Describe the tool clearly
A tool is defined by three parts: a name, a description of what it does and when to use it, and a JSON schema of its parameters:
2 The call, execute, observe loop
The model does not run the tool itself. It asks; your code answers. The rhythm:
The loop repeats: the model may call another tool, or finish its answer once it has what it needs.
3 Tools vs plain prompting
Reach for a tool only when the model needs something beyond its own knowledge:
Plain prompting is enough
Try it for real
The loop above has one step the model does and three that you do. Here are your three in plain Python: read the structured call, check its arguments against the parameter schema, run the tool, and hand back the observe message. The five calls are hand-written in the shape a model returns — no model is called — so the checking and dispatching is what you study.
# Tool use with the model left out. The model's whole job is to emit a structured
# call; YOUR job is everything after it: check the call against the schema, run
# it, and hand back a result. The five calls below are hand-written in the shape
# a model returns, so the checking and dispatching is what you study.
import json
def get_weather(city, unit="celsius"):
table = {"Paris": 18, "Cairo": 34} # stands in for a live weather API
c = table.get(city)
if c is None:
return f"no data for {city}"
return f"{c}C, clear" if unit == "celsius" else f"{round(c * 9 / 5 + 32)}F, clear"
TOOLS = {
"get_weather": {
"run": get_weather,
"description": "Current weather for a city. Use for live conditions or temperature.",
"params": {
"city": {"type": str, "required": True},
"unit": {"type": str, "required": False, "enum": ["celsius", "fahrenheit"]},
},
},
}
def check_arguments(schema, args):
"""Compare the model's arguments with the parameter schema. Return problems."""
problems = []
for name, rule in schema.items():
if rule["required"] and name not in args:
problems.append(f"missing required '{name}'")
elif name in args and not isinstance(args[name], rule["type"]):
problems.append(f"'{name}' must be {rule['type'].__name__}")
elif name in args and "enum" in rule and args[name] not in rule["enum"]:
problems.append(f"'{name}' must be one of {rule['enum']}")
for name in args:
if name not in schema:
problems.append(f"unknown argument '{name}'")
return problems
def dispatch(call_json):
"""CALL -> EXECUTE -> the OBSERVE message you send back to the model."""
call = json.loads(call_json)
name, args = call["name"], call["arguments"]
if name not in TOOLS:
return {"role": "tool", "name": name, "content": f"error: no tool named {name}"}
problems = check_arguments(TOOLS[name]["params"], args)
if problems:
return {"role": "tool", "name": name, "content": "error: " + "; ".join(problems)}
return {"role": "tool", "name": name, "content": TOOLS[name]["run"](**args)}
model_calls = [
'{"name": "get_weather", "arguments": {"city": "Paris"}}',
'{"name": "get_weather", "arguments": {"city": "Cairo", "unit": "fahrenheit"}}',
'{"name": "get_weather", "arguments": {"city": "Cairo", "unit": "kelvin"}}',
'{"name": "get_weather", "arguments": {"unit": "celsius"}}',
'{"name": "send_email", "arguments": {"to": "boss@example.com"}}',
]
for raw in model_calls:
print("CALL ", raw)
print("OBSERVE", dispatch(raw))
print()
# Nothing above decided WHEN to call a tool - that is the model's job, guided by
# the description. Everything above is yours: the schema check is what turns a
# half-right call into an error message the model can read and fix.
# Run it. The first lines you should see are below; the rest follows.
# ✅ Expected output:
# CALL {"name": "get_weather", "arguments": {"city": "Paris"}}
# OBSERVE {'role': 'tool', 'name': 'get_weather', 'content': '18C, clear'}# 🎯 YOUR TURN — check the model's arguments against the schema before running the tool.
import json
def get_time(city):
return {"Paris": "14:05", "Tokyo": "21:05"}.get(city, "unknown city")
TOOLS = {"get_time": {"run": get_time, "params": {"city": {"type": str, "required": True}}}}
def dispatch(call_json):
call = json.loads(call_json)
name, args = call["name"], call["arguments"]
schema = TOOLS[name]["params"]
for param, rule in schema.items():
# 1) A required parameter the model left out is an error.
if rule["required"] and param ___ args:
# 👉 replace ___ with not in
return "error: missing " + param
# 2) A value that is present must have the type the schema says.
if param in args and not isinstance(args[param], rule[___]):
# 👉 replace ___ with "type"
return "error: wrong type for " + param
# 3) Run the tool with the arguments unpacked as keyword arguments.
return TOOLS[name]["run"](**___)
# 👉 replace ___ with args
print(dispatch('{"name": "get_time", "arguments": {"city": "Tokyo"}}'))
print(dispatch('{"name": "get_time", "arguments": {}}'))
print(dispatch('{"name": "get_time", "arguments": {"city": 42}}'))
# ✅ Expected output:
# 21:05
# error: missing city
# error: wrong type for cityCommon Mistakes (and the fix)
- Vague tool descriptions. — Say what it does AND when to use it.
- Loose or missing parameter schema. — List fields and types in JSON schema.
- Expecting the model to run the tool. — Your code executes it and returns the result.
- Using tools for tasks plain prompting handles. — Reserve tools for live data and real actions.
⏱ Test Yourself — Timed Quiz
10 quick questions, 12 seconds each. Instant feedback — beat the clock!
🎉 Lesson Complete
- ✅ Tool use lets the model ask your code to run a function
- ✅ Define tools with a name, description, and JSON-schema parameters
- ✅ The model returns a structured call; your code executes it
- ✅ Follow the call, execute, observe, continue loop
- ✅ Use tools for live data and real actions, not tasks prompting handles
Practice quiz
What is 'tool use' or 'function calling' with an AI?
- The model can request that your code run a defined tool and use the result
- The model fixes your hardware
- A way to delete tools
- A type of font
Answer: The model can request that your code run a defined tool and use the result. Tool use lets the model ask your code to run a function and continue with the result.
How do you describe a tool to the model?
- Only its color
- Just a single word
- A name, a description, and a JSON-schema of its parameters
- Nothing is needed
Answer: A name, a description, and a JSON-schema of its parameters. Tools are defined by name, description, and a parameter schema the model fills in.
When the model decides to use a tool, it returns…
- A random number
- A structured call naming the tool and its arguments
- A picture
- An error
Answer: A structured call naming the tool and its arguments. The model emits a structured tool call with the chosen arguments.
Who actually executes the tool?
- The model runs it itself secretly
- Nobody
- The user types it by hand
- Your code runs it and returns the result to the model
Answer: Your code runs it and returns the result to the model. Your application executes the function and feeds the result back to the model.
After your code returns a tool result, the model…
- Continues, using the result to finish its answer
- Starts over from scratch
- Stops forever
- Deletes the tool
Answer: Continues, using the result to finish its answer. The model incorporates the result and continues the conversation.
The basic loop of tool use is…
- encrypt, decrypt
- call, execute, observe, then continue
- guess, guess, guess
- sleep, wake, repeat
Answer: call, execute, observe, then continue. The model calls a tool, your code executes it, the model observes the result, and continues.
Why use a tool instead of plain prompting?
- It is always slower
- To use more emojis
- There is never a reason
- To access live data or real actions the model cannot do from memory alone
Answer: To access live data or real actions the model cannot do from memory alone. Tools fetch current data or take real actions the model cannot do on its own.
A clear tool description mainly helps the model…
- Look nicer
- Run faster hardware
- Decide WHEN to call the tool and HOW to fill its parameters
- Avoid all tools
Answer: Decide WHEN to call the tool and HOW to fill its parameters. Good descriptions guide correct tool selection and argument formatting.
Which task is a good fit for a tool rather than plain prompting?
- Brainstorming names
- Looking up today's live weather for a city
- Rephrasing a sentence
- Summarizing a pasted paragraph
Answer: Looking up today's live weather for a city. Live, external data like current weather is exactly what a tool provides.
The parameter schema for a tool is written in…
- JSON schema describing the expected fields and types
- Morse code
- A spreadsheet only
- Random text
Answer: JSON schema describing the expected fields and types. Tool parameters are described with a JSON schema of fields and types.
Continue this course
- Previous: Structured Output: JSON & Schemas
- Next: Retrieval-Augmented Generation (RAG) — Ground answers in your own documents with embeddings and retrieval
Frequently asked questions
What is tool use, in plain English?
Tool use, also called function calling, lets the AI ask your program to run a specific task and then use the result. You describe the tools available, such as 'get_weather' or 'search_orders.' When the model needs one, it does not run it itself; it returns a structured request naming the tool and its arguments. Your code runs the function, hands back the answer, and the model continues.
How do I define a tool?
A tool has three parts: a clear name, a description of what it does and when to use it, and a JSON schema listing its parameters and their types. The description matters a lot, it is how the model decides whether and when to call the tool, and the schema tells it exactly which arguments to provide.
What is the call, execute, observe loop?
It is the rhythm of tool use. The model emits a tool call with arguments. Your code executes the matching function. You return the result so the model can observe it. The model then continues, either answering or calling another tool. This loop repeats until the task is done.
When should I use a tool instead of just prompting?
Use a tool when the model needs something it cannot do from memory: live data (today's prices, current weather), private information (your database), or real actions (sending an email, booking a slot). For tasks the model can already handle, like rewriting text or summarizing a pasted document, plain prompting is simpler and faster.