Day 2: Instrument the Tool-Calling Interface
Why tools need contracts
On Day 1 the dispatcher ran SQL directly. That is fine while the only caller is your own regex. From Day 3 on, the caller is a model, and a model will eventually send {"order_id": 1005} (a number), "ORD-1" (half an id), an amount of -40, or a tool name it invented. In production the cheapest place to stop that is the boundary between "the model decided" and "the database changed". This lesson builds that boundary: a tool registry where every tool declares its arguments and its result, and nothing runs until both check out.
What you build
supportdesk/tools.py adds three things to the project:
A small schema validator. A subset of JSON Schema that the standard library can check in a few lines:
type,required,enum,minimum/maximum,patternandmaxLength, plus "no extra fields". A failure raisesToolValidationErrorwith the field name, so the caller (and later the model) knows exactly what to fix.Three tools.
get_order_status(order_id)returns status, item, dates and price.check_stock(product)returns stock and price.process_refund(order_id, amount, reason, idempotency_key)writes to a newrefundstable.An audit trail. Every call, good or bad, becomes a row in
tool_calls: tool, arguments, ok, error, latency.
The registry is the only door:
Validating the result too sounds paranoid until a schema migration renames a column and your agent starts telling customers their order is None.
The HTTP API gets GET /tools (names and argument schemas) and POST /tools/NAME. Bad arguments return 400 with the field; arguments that are valid but break a business rule (refunding an order that hasn't shipped) return 422. The Day 1 /chat endpoint keeps working, now going through the same tools.
Refunds must be safe to repeat
process_refund takes an idempotency_key. The first call with a key creates a refund; any later call with the same key returns the first result with "duplicate": true and changes nothing. The key has a UNIQUE constraint in SQLite, so even two threads racing can't both insert.
Read the full lesson free
This lesson is one of the first 3 in its course, free with an account β the full article, implementation guide and scripts. No card needed.
Already a member? Sign in