Topic 7.3
Describing Tools Well
In one line
The model chooses and fills in tools using only their names, descriptions and JSON Schema parameters. Clear names, descriptions that say when to use the tool, and tight schemas (types, enums, required fields) are the main way to make tool use reliable.
Think of it like this
The labels on a drawer of kitchen tools. A drawer labelled 'stuff' makes everyone guess. Labels reading 'tin opener: for cans only' and 'bottle opener: for caps' make nobody guess wrong. The model cannot see your code. It sees the labels you wrote, and nothing else.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- JSON Schema
- A standard way to describe the shape of JSON: types, required fields, allowed values and ranges.
- Description
- The plain-English text that tells the model what a tool does and when to use it.
- required
- The list of argument names the model must always supply.
- enum
- A fixed list of allowed values for an argument, such as celsius or fahrenheit.
- Strict mode
- A provider option that forces a tool's arguments to match its schema exactly. Support varies by provider.
- Tool list
- The
toolsarray in the request. It is sent, and billed as input, on every call.
Step by step
01Step 1: the model sees only text
The model gets the tool's name, description and schema as part of its input. Nothing else about your function reaches it. Write them as if for a new colleague who cannot read your code.
02Step 2: build the definition
The helper tool(name, description, properties, required) returns the exact shape the API expects. The first example prints it compactly so you can see every field and its size.
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city. Use it for questions about temperature or sky today.",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "City name, for example Pune" },
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["city"]
}
}
}03Step 3: vague versus clear
The second example scores each tool by words shared with the request. With descriptions like 'Converts things.' nothing matches. With descriptions that name what the tool does, the right tool wins. A real model is cleverer, but it also needs something to go on.
04Step 4: narrow the arguments
Use enum where the choices are fixed, required for what you cannot default, and describe formats ('ISO date, for example 2026-10-10'). Each constraint removes a way to be wrong.
05Step 5: test with a real model
In the lab, run the request, then replace the description with 'Does stuff.' and run again. Then try a different wording. Note which wordings still work: those are the ones you can trust a little more.
Try it yourself
- 1
Estimate the cost of ten tools
In the first example, copy the
get_weatherdefinition nine times (different names) and print the total characters. Divide by 4. How many tokens does a 10-tool list add to every request, and what does that cost at 10,000 requests a day with an example price of 0.10 dollars per million input tokens? - 2
Add a third tool to the toy chooser
Add
get_weatherwith the description 'Get the weather for a city today.' to the CLEAR list and add the request 'Weather in Pune today' to the loop. Predict the scores before you run. - 3
Make the lab fail
In the lab, give both tools the same description and send. What does the model do? When two tools look the same to you, they look the same to the model.
Code & diagrams
The characters-per-token rule is a rough estimate (Topic 1.2). Your provider's usage field gives the real count.
Expected output
{"type":"function","function":{"name":"get_weather","description":"Get the current weather for a city. Use it for questions about temperature or sky today.","parameters":{"type":"object","properties":{"city":{"type":"string","description":"City name, for example Pune"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"Temperature unit. Default celsius."}},"required":["city"]}}}
required: city
characters: 401
about 100 tokens, sent with every requestA toy chooser that counts shared words. Real models compare meaning, but they depend on the description in the same way.
Expected output
vague descriptions:
'What is 250 euros in rupees today?' -> no clear choice (score 0)
'Find news about the Pune metro' -> no clear choice (score 0)
clear descriptions:
'What is 250 euros in rupees today?' -> convert_currency (score 2)
'Find news about the Pune metro' -> search_web (score 2)Try: Send as it is: the model should call convert_currency. Then edit the tool list (use the request editor) so convert_currency has the description 'Does stuff.' and send again. Does it still pick the right tool? Try renaming it to 'tool1'. What do you learn about how much the model relies on names and descriptions?
Goals
- The model calls convert_currency
Sign in to send this request to a real model (free).
Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Empty descriptions
In the second example, change every description in the CLEAR list to an empty string "" and run the Python version.
Myth vs fact
Myth
The model reads my function's code or docstring.
Fact
It sees only what you put in the request: the name, description and schema. A docstring helps only if you copy it into the description.
Myth
A longer description is always better.
Fact
Length costs tokens on every request. Say what it does, when to use it and the limits, then stop.
Myth
If the schema says integer, the model will always send an integer.
Fact
Models usually follow schemas but can send a string or an out-of-range value. Always validate (Topic 7.4).
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Put the most important sentence first and avoid ambiguity between tools: if two tools overlap, say which to prefer. Many 'wrong tool' bugs are two tools whose descriptions both claim the same job.
- ▸
Keep tool lists stable between requests. Providers that cache a repeated prompt prefix (Topic 6.6) can reuse the tool list only if it is identical, so reordering or regenerating it per request costs money.
- ▸
Model the user's task, not your API: one
create_tickettool with clear arguments beats five thin wrappers around endpoints. Fewer, richer tools mean fewer chances to pick wrongly.
Remember this
- 1
Why this exists. When the model decides whether to call a tool and with what arguments, it reads three things you supplied in the request: the tool's name, its description and its parameters (a JSON Schema). It has never seen your function body. So the quality of tool use is mostly the quality of this text. Most 'the model keeps choosing the wrong tool' bugs are description bugs.
- 2
Names. Use a verb and a noun,
get_weather,search_orders,create_ticket. Be specific:searchandlookupcollide with each other. Stick to letters, digits, underscores and hyphens, up to 64 characters: OpenAI-style APIs restrict function names to that pattern (^[a-zA-Z0-9_-]{1,64}$), so a dot or space can make the request fail. Name by what the tool does for the user, not by your internal class name. - 3
Descriptions say when to use the tool, and when not to. One or two sentences: what it does, what it returns, when to prefer it, and any limit ('only covers the last 30 days'). Mention neighbours: 'Use
search_ordersto find an order id first; this tool needs the id.' Include units and formats. The first example prints a real tool definition and counts its size. - 4
Parameters are a JSON Schema. An object with
properties(each with atypeand a shortdescription), arequiredlist, and extras that narrow the choices:enumfor a fixed set of values,minimumandmaximumfor ranges,maxLengthfor text. The tighter the schema, the fewer wrong arguments the model will produce, and the easier your validation (Topic 7.4). Phase 4 covers JSON Schema in depth. Some providers also offer a strict mode that forces arguments to match the schema. OpenAI's, for example, asks for"strict": trueon the function,additionalProperties: falseon every object and every property listed inrequired. Support and rules differ by provider, so read yours. - 5
Every tool costs tokens, every request. The tool list is sent as input on each call, so long descriptions and many tools add cost and latency, and dilute the model's attention. Keep the list to the tools the task needs (pick them per request if you have many), and keep each description tight. The first example estimates the size with the 4-characters-per-token rule of thumb from Topic 1.2.
- 6
You can only measure by trying. Treat tool descriptions like prompts (Topic 3.8): write a small set of requests with the tool you expect, run them against a real model, and re-run after every change. The second example is a toy that picks a tool by word overlap with the description. Real models match meaning, not words, but the lesson transfers: vague descriptions give them nothing to match. The lab lets you edit a real description and see whether the choice changes.
Explain it without notes
What does the model actually see of a tool, and what follows for how you write them?
How do enum, required and description on a parameter each reduce errors?
What is the cost of a long tool list and how do you keep it under control?
Practice
Write make_tool(name, description, properties, required) that returns the tool definition dict in the API shape, and print its function name.
Write tokens_estimate(tools) that returns the estimated tokens of a list of tool dicts as the length of their compact JSON divided by 4 (integer division).
Trade-offs
- ↔
Detailed descriptions improve choices and cost input tokens on every request.
- ↔
Tight schemas (enums, ranges) prevent bad arguments and make the tool less flexible when the real world has more cases.
- ↔
Many small tools are easy to describe and hard to choose between; a few richer tools are the reverse.
Done when you can
Done when you can write a tool definition (name, description, parameters) from memory.
Done when each of your descriptions says when to use the tool and what it returns.
Done when parameters use
enum,requiredand descriptions with formats where they apply.Done when you can estimate the token cost of a tool list.
Done when you have tested a description change against a real model.