AI School · Level 4 · Agents · 3 of 4

The tools: the contract

Léelo en español →

Reading time: about 20 minutes

An agent is only as good as its tools, and that is not a nice phrase: it is literally where the work is. The loop from the previous lesson is thirty lines and you never touch it again. Everything you write from here on is tools, and everything that breaks on you will be too.

A tool is two things, and the one that fails is almost always the second: a function that does the work and a description the model reads. The model cannot see your code. It sees a sentence, some field names and some types. If that is written badly, it does not matter how well the function is programmed.

What is inside

  1. The six rules of a description that works
  2. The parameter schema, field by field
  3. What it returns: shape, size and errors
  4. Tools that WRITE: the contract of four conditions
  5. Idempotency, with code
  6. Prepare and confirm: why they are two tools
  7. Limits go in the code, never in the prompt
  8. How many tools fit
  9. When the tool calls another system
  10. Scope: what the tool is allowed to see
  11. The ordering agent, end to end
  12. Testing a tool without spending a single call

1. The six rules of a description that works

They all come from the same place: the model chooses using what it reads. A description is not documentation for you — it is the interface.

BadGood
"Looks up stock." "Stock, minimum and days of cover for ONE product. Use it when asked how much is left or whether to order. The code must come from find_product."
"Sends an order to the supplier." "ACTUALLY sends an already prepared order. It can only be called with the identifier returned by prepare_order and after the user has said yes. Do not use it to calculate anything."

2. The parameter schema, field by field

The schema is not bureaucracy: it is the only thing keeping rubbish out of your function. And every field carries its own description, which the model also reads.

A complete schema{ name: 'prepare_order', description: 'Calculates the lines of an order for a supplier and returns a draft with an ' + 'identifier. It sends NOTHING. It is the mandatory step before confirm_order.', parameters: { type: 'object', properties: { supplier: { type: 'string', // ⚠️ enum: the closed list stops it inventing a supplier enum: ['artsana', 'kenvue', 'johnson'], description: 'Supplier the order goes to', }, cover_days: { type: 'integer', description: 'Days of sales to cover. Between 3 and 30. If not told, use 14', }, only_codes: { type: 'array', items: { type: 'string' }, description: 'Restrict to these codes. Empty = everything below its minimum', }, }, required: ['supplier'], }, }
enum is the most underrated tool there is. It turns "the model could write anything" into "the model can only write one of these three". Any time a field has a finite set of valid values — a supplier, a status, a document type — it takes an enum. It is free and it removes a whole family of failures.
And notice the list is LABS, not wholesalers. That is not an incidental detail: it is what makes this agent worth building. The wholesaler order is continuous — your dispensing software generates it against minimum levels and sends it several times a day — so there is nothing to decide and nothing to prepare. The direct order to a lab is the opposite: periodic, with a minimum order value, terms and volume rebates, and deciding what goes into it is exactly the sum an owner does by hand. An agent that duplicated the wholesaler order would not be redundant: it would be in the way.
And notice "If not told, use 14". Defaults get written in the field description, not in your head. Without that sentence the model invents a reasonable number — 7, 30, 45 — and every run comes out different with nothing having changed.
The schema does not validate for you. Writing between 3 and 30 does not stop a 900 arriving: that is a sentence, not a check. Real validation goes on the first line of your function, and this applies to everything that follows.

← Previous: your first agent Next: in production →