Forward-deployed / Learning zone
Tool callinga Generative AI module
Lesson 02

Tool contracts & reliability

TL;DR

A tool is only as trustworthy as the promise behind it: what it accepts, what it actually does, and whether calling it twice by accident is safe. Writing that promise down as a schema is engineering work, but the shape of the promise — how many tools to expose, how broad each one is, and whether the underlying action can be safely retried — is a product decision, made before any code gets written. Get the shape wrong and no amount of careful engineering underneath it fixes the result: a model that picks the wrong tool, or a retry that quietly repeats a real-world action.

🎯 For the product leader

Why it matters — A tool's contract determines how often the model uses it correctly. A vague or overlapping toolbox produces wrong tool calls no matter how good the model is.

What it changes in your decisions — How many tools a feature exposes, at what granularity, and whether "safe to retry automatically" was a deliberate design choice or an assumption nobody checked.

Ask yourself — "If this tool call times out and we retry it automatically, what's the worst that happens?"

Risk if ignored — A retry after a network blip double-charges a customer or sends a duplicate email — not because the model made a mistake, but because nobody decided whether the underlying action was safe to repeat.

The mental model: every tool call passes four checkpoints

Tool contract

Four checkpoints · each a product decision hiding as a technical detail

A vague description, an unsafe repeat, an opaque error — each is a product bug wearing an engineering costume.

01
Name & description
Does the model know when to use it?
→
02
Schema
Are the arguments well-typed and scoped?
→
03
Idempotency
Is a repeat call safe?
→
04
Error design
Can the model recover from a failure?
The granularity decision · how many tools, how big each one is
❌ Thin wrappers

list_calendars → get_availability → create_event → send_invite

Model picks a plausible-sounding call, not the correct one.

vs.
✓ Task-shaped tools

book_meeting(person, topic, week)

Matches how someone would describe the task, not the API layout.

Fewer, better-scoped tools beat many thin ones — every extra tool is a chance for the model to pick the wrong one under pressure.

Each checkpoint is a place a product decision hides inside what looks like a purely technical detail. A vague description is a product problem — the model can't tell when to use the tool. A tool that isn't safely repeatable is a product problem — a retry becomes a silent double action. An opaque error is a product problem — it produces a model that gets stuck instead of one that recovers.

The granularity decision: how many tools, how big each one is

A toolbox with dozens of thin, near-identical wrappers around individual API endpoints reliably confuses a model — it picks the plausible-sounding one, not the correct one. The fix isn't a smarter model; it's fewer, better-scoped tools that match how someone would describe the task, not how the API happens to be laid out. book_meeting(person, topic, week) beats making the model chain list_calendars → get_availability → create_event → send_invite across four separate calls it can fumble one of. This is a product call — what capability to expose, and at what altitude — even though implementing the schema itself is engineering. The full craft of tool design, including how to write descriptions a model reads well, is developed in Tools & function calling.

Idempotency: a promise, not an implementation detail

Models retry. Networks fail and retry. Agents re-issue a call that looked like it didn't go through. None of that is a bug — it's normal operation — which means every tool with a real-world side effect needs an answer to one question before launch: is calling this twice safe? set_status(order, shipped) is naturally safe to repeat; increment_balance( +10) is not, and needs to become something like apply_transaction(txn_id, +10), keyed so a repeat is a no-op instead of a second charge. This is worth a product leader's attention specifically because it's invisible until it fails — a tool works perfectly in every demo and only shows the gap the first time a real retry hits it in production. The engineering pattern (idempotency keys, separating reads from writes) is developed in full in Function calling reliability.

Errors are part of the product, not an engineering afterthought

A tool that fails with an opaque "error 500" produces a model that either gives up or retries the same broken call. A tool that fails with "date must be YYYY-MM-DD, e.g. 2026-07-01" produces a model that corrects itself and moves on. The difference between those two failure messages is a UX decision as real as any error message a human would see — it just has an unusual reader. Reviewing a feature's tool errors the way you'd review its user-facing error copy catches this before the failure mode shows up as a stuck agent in production.

Failure modes

Practitioner checklist