Tool & Function Calling Cheat Sheet
Writing tool schemas a model actually uses correctly
A tool definition is a prompt. Its name, its description and its parameter names are the only things the model has to decide whether to call it.
Schema rules
- Name the tool for the action, in a verb form search_orders beats orders_api
- Describe WHEN to use it, not only what it does The description is a routing instruction
- Say explicitly when NOT to use it The single most effective line against wrong-tool calls
- Mark every genuinely required parameter required Optional-by-default means it will be omitted
- Use enums wherever the set is closed A free-string status will be invented eventually
- Describe each parameter, including its units and format "date (YYYY-MM-DD)" prevents a whole class of retries
- Keep the toolset under about ten Accuracy degrades well before the context does
The round trip
| Step | Who | Contains |
|---|---|---|
| 1. Request | You | messages + tool definitions |
| 2. Tool call | Model | A tool_use block with an id and arguments |
| 3. Execution | Your code | Validate the arguments before running anything |
| 4. Result | You | A tool_result referencing the same id |
| 5. Answer | Model | Prose, or another tool call |
Never trust the arguments
Tool arguments are model output, which makes them untrusted input in the security sense. Validate them against your schema server-side, apply the same authorisation you would to a user request, and never interpolate them into a query, a shell command or a file path. A prompt injected into retrieved content can reach your tools this way.
Code examples
A tool schema that routes correctly
The description is a routing instruction, not documentation. Saying when NOT to use it is the single most effective line.
{
"name": "search_orders",
"description": "Find a customer's orders by email or order number. Use this whenever the user asks about an order's status, contents or delivery date. Do NOT use it for refunds or cancellations — those go to manage_order.",
"input_schema": {
"type": "object",
"properties": {
"email": { "type": "string", "description": "Customer email. Provide this OR order_number." },
"order_number": { "type": "string", "description": "Order reference, format ORD-000000." },
"since": { "type": "string", "description": "Only orders on or after this date (YYYY-MM-DD)." },
"status": { "type": "string", "enum": ["pending", "shipped", "delivered", "cancelled"] }
},
"required": ["status"]
}
}
Frequently asked questions
How many tools can a model handle?
Accuracy starts degrading well before the context does — around ten is a practical ceiling. Beyond that, route to a smaller toolset first rather than expanding the list.
Do I need to validate the arguments?
Always. Tool arguments are model output, which makes them untrusted input. Content retrieved from elsewhere can carry an injected instruction that reaches your tools this way.
Was this cheat sheet useful?
Comments
No comments yet — be the first.
Keep going
Browse all
More cheat sheets
Need a different cheat sheet?
Tell us what you would like to see and we will build it — free.
Request a cheat sheet