Write Tool Definitions as Hostile API Contracts, Not Friendly Docs
Most tool failures in agent systems are not model failures. They are contract failures caused by vague tool definitions that a probabilistic reader interprets too broadly, too narrowly, or at the wrong time. This guide shows how to write tool definitions as enforceable API contracts, with concrete patterns, examples, and review checks your team can apply this week.
Nesqual Tech AI
A single vague tool description can turn a reliable agent into an expensive intern with production access. In one 2026 enterprise support rollout, a team saw 18% of tool calls fail validation not because the model was weak, but because customer_id was described as "the customer reference" in one place and treated as an internal UUID everywhere else.
That is the core mistake: teams write tool definitions as if a cooperative human will infer intent. Your real reader is a model that will misinterpret ambiguous wording, overgeneralize examples, and optimize for plausible completion under uncertainty. If you want predictable behavior, treat tool definitions as API contracts for a reader who will get them wrong unless you make getting them right easier.
Why vague tool definitions fail under real traffic
Tool calling looks clean in demos because the prompts are clean, the data is curated, and the operator knows what should happen. Production traffic is messy. Users omit context, mix identifiers, ask for multiple actions at once, and phrase requests in ways your examples did not anticipate.
When that happens, the model falls back to the only thing it has: your tool definition. If the definition is broad, underspecified, or inconsistent with backend behavior, the model fills gaps with guesses.
The three failure modes you can expect
- Over-invocation: the model calls a tool when it should ask a clarifying question.
- Under-specification: the model calls the right tool with missing or malformed arguments.
- Semantic drift: the model maps user language to the wrong field or wrong operation.
A real example from a procurement assistant makes this concrete. The tool create_vendor had a field named tax_id described as "vendor tax number if available." In Germany, users supplied VAT IDs. In the US, they supplied EINs. In Brazil, they supplied CNPJ. Backend validation accepted only region-specific normalized formats. Result: 11.7% failure rate on first-pass tool calls and a median retry loop of 2.4 turns.
The fix was not a stronger model. It was a stronger contract:
- Rename
tax_idtotax_identifier - Add
country_code - Define accepted formats by country
- State when the model must ask a clarifying question
- Provide one positive and one negative example
Within two weeks, first-pass validation failures dropped to 2.1%, and median task completion time fell from 41 seconds to 26 seconds.
Treat the definition like a contract, not a tooltip
A good tool definition does four jobs at once: it defines intent, constrains inputs, explains boundaries, and tells the model when not to call the tool. Most teams only do the first job.
What a robust tool contract must specify
For each tool, define:
- Purpose: the exact job this tool performs
- Preconditions: what must be true before invocation
- Required arguments: names, types, formats, allowed ranges
- Disambiguation rules: what to do when input is incomplete or ambiguous
- Failure semantics: common backend errors and how to avoid them
- Non-goals: adjacent tasks this tool must not be used for
Here is a weak definition that looks harmless but causes drift:
{
"name": "refund_order",
"description": "Refund an order for a customer.",
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number" }
},
"required": ["order_id"]
}
}
Now compare it with a contract-oriented version:
{
"name": "refund_order",
"description": "Issue a refund for a captured payment on a completed order. Use only when the user explicitly requests a refund or approves one after options are explained. Do not use for cancellations before shipment, exchanges, goodwill credits, or subscription proration.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Commerce order ID in format ord_########. Never use payment ID, shipment ID, or external marketplace ID. If the user provides another identifier, ask for the order ID or resolve it with `lookup_order`."
},
"amount": {
"type": "number",
"description": "Refund amount in major currency units. Omit for full refund. For partial refund, amount must be > 0 and <= captured amount remaining."
},
"reason_code": {
"type": "string",
"enum": ["damaged", "not_as_described", "customer_changed_mind", "duplicate_order", "fraud_suspected"],
"description": "Required for partial refunds and any refund over 250.00."
}
},
"required": ["order_id"]
}
}
The second version does not just describe the tool. It narrows the model's decision surface.
Write for the likely misread
Assume the model will:
- confuse similar IDs
- infer optional fields as mandatory if examples overemphasize them
- treat broad verbs like "manage," "handle," or "process" as permission to overuse the tool
- ignore hidden backend constraints unless they appear in the tool description or schema
That means your wording should answer the question, "How could this be used incorrectly?" before it answers, "What does this do?"
Design schemas that make the right call easier than the wrong one
Natural-language descriptions matter, but schema design does more work than many teams realize. Good schemas reduce ambiguity before the model starts reasoning.
Prefer explicit enums and discriminators
If your backend supports six action types, do not hide them in prose. Put them in the schema.
name: manage_subscription
description: Modify an existing subscription. Use only after the customer identity and target subscription are confirmed.
input_schema:
type: object
properties:
subscription_id:
type: string
description: "Format sub_########. Required for all actions."
action:
type: string
enum: ["pause", "resume", "cancel_end_of_term", "cancel_immediately", "upgrade", "downgrade"]
description: "Choose exactly one action. If the user says 'cancel' without timing, ask whether they want immediate cancellation or end-of-term cancellation."
plan_code:
type: string
description: "Required only for upgrade or downgrade."
required: ["subscription_id", "action"]
This single discriminator often cuts invalid tool calls sharply. In a SaaS billing workflow we reviewed, replacing a free-text operation field with an enum reduced schema validation failures from 9.4% to 1.8% on a 50,000-call test set.
Encode formats where possible
If a field has a stable pattern, enforce it.
- Use
patternfor IDs like^ord_[0-9]{8}$ - Use
minimumandmaximumfor bounded values - Use arrays with
minItemsandmaxItemswhen count matters - Separate user-facing labels from system identifiers
A common anti-pattern is a generic field like id. That invites confusion between CRM IDs, billing IDs, and external references. Use account_id, invoice_id, workspace_id, and ticket_id instead.
Make clarifying questions part of the contract
If ambiguity should block execution, say so explicitly. Many teams assume the orchestration layer will handle this. In practice, the model often tries a best-effort call first.
Use language like:
- "If the user provides a name instead of
account_id, do not guess; ask for the account ID or callsearch_accounts." - "If multiple records match, do not select one arbitrarily. Ask the user to confirm."
- "If the request implies a destructive action and
confirm=trueis absent, ask for confirmation."
Examples beat explanations when edge cases matter
Examples anchor behavior faster than long prose, especially for edge cases. But examples can also bias the model in bad ways if they are too narrow.
Include one positive, one negative, one ambiguous example
For each tool, add:
- a correct invocation example
- a case where the tool should not be used
- a case that requires clarification first
Here is a compact internal spec pattern that works well in 2026 agent stacks using OpenAI Responses API, Anthropic tool use, or gateway-normalized tool schemas.
tool: close_security_incident
when_to_use:
- "Use when the user explicitly asks to close an incident and provides an incident ID."
- "Use when all mandatory closure fields are available: incident_id, resolution_code, summary."
when_not_to_use:
- "Do not use to mute alerts, suppress detections, or archive tickets."
- "Do not use if the incident is still in status 'investigating'."
clarify_first:
- "If the user says 'close the phishing case' without an incident ID and multiple incidents match, ask which one."
examples:
positive:
user: "Close incident inc_10482 as resolved. User confirmed it was a false positive from the mail gateway rule update."
tool_call:
incident_id: "inc_10482"
resolution_code: "false_positive"
summary: "Mail gateway rule update triggered benign detections; user confirmed no malicious activity."
negative:
user: "Stop these alerts from firing again."
assistant: "Use alert tuning workflow, not close_security_incident."
ambiguous:
user: "Close the payroll phishing case."
assistant: "I found two matching incidents. Which incident ID should I close: inc_10482 or inc_10511?"
This pattern is effective because it teaches boundaries, not just syntax.
Keep examples representative, not aspirational
If all your examples show perfect user input, your model will overfit to ideal conditions. Include messy but realistic phrasing:
- shorthand IDs copied from dashboards
- mixed locale formats for dates and currency
- partial user intent like "cancel it next month"
- requests with embedded policy conflicts
One fintech team improved successful first-turn tool selection by 7.9 percentage points after replacing polished examples with 40 examples sampled from actual support logs.
Build a review process that catches ambiguity before production
Tool definitions deserve the same rigor you apply to public APIs. Yet many teams still review them informally inside prompt files.
Use a contract review checklist
Before shipping a tool, ask:
- Can a model confuse this tool with a neighboring tool?
- Are all identifiers named specifically enough to avoid collisions?
- Does the description state when not to call the tool?
- Are hidden backend constraints surfaced in the schema or description?
- Does the tool define what to do under ambiguity?
- Are examples realistic and varied?
- Are destructive actions gated by explicit confirmation?
A practical governance pattern is to store tools in versioned JSON or YAML, run schema linting in CI, and replay a regression set of user utterances before merge.
#!/usr/bin/env bash
set -euo pipefail
ajv validate -s schemas/refund_order.schema.json -d testcases/refund_order.valid.json
ajv validate -s schemas/refund_order.schema.json -d testcases/refund_order.invalid.json --all-errors || true
python scripts/replay_tool_selection.py --tool-dir tools/ --dataset datasets/ambiguous_utterances_2026.jsonl --report reports/tool_regression.html
In one enterprise platform team, this lightweight pipeline caught 34 regressions in a quarter, including two cases where a renamed enum silently broke downstream routing.
Measure the right metrics
Do not stop at "tool call success rate." Track:
- selection precision: was the right tool chosen?
- argument validity rate: did the call pass schema and business validation?
- clarification rate: did the model ask when it should have?
- destructive-action false positives: did the model act without required confirmation?
- median turns to completion: did your contract reduce retries?
For mature internal assistants in 2026, a realistic target is:
-
97% schema-valid arguments on high-volume tools
- <2% destructive-action false positives
- 10-20% clarification rate on inherently ambiguous workflows
- p95 tool-selection latency under 350 ms excluding backend execution
Common Pitfalls
The same mistakes show up across teams, vendors, and frameworks.
Pitfall 1: Descriptions that are broader than the backend
If your description says "update a customer record" but the API only updates billing preferences, the model will attempt unsupported changes.
Avoid it: match the description to actual capability and list non-goals explicitly.
Pitfall 2: Optional fields that are operationally required
A field may be optional in JSON Schema but required in practice for policy or routing. Example: region omitted for data residency decisions.
Avoid it: either make it required or state the conditional rule in the field description and examples.
Pitfall 3: Generic parameter names
Fields like id, type, value, and status invite semantic drift.
Avoid it: use domain-specific names and narrow enums.
Pitfall 4: No guidance for ambiguity
Without explicit instructions, the model often guesses. Guessing is cheap in demos and expensive in production.
Avoid it: add "ask first" rules for missing IDs, multiple matches, and destructive actions.
Pitfall 5: Examples that accidentally teach the wrong norm
If every refund example includes amount, the model may assume partial refunds are standard and omit full-refund behavior.
Avoid it: balance examples across common paths and edge cases.
Pitfall 6: Contract drift after backend changes
A backend team adds a new enum, changes an ID format, or tightens validation. The tool definition stays stale.
Avoid it: version tool specs with backend releases and fail CI when schemas diverge from service contracts.
Key Takeaways
- Write tool definitions as hostile-reader contracts: define purpose, boundaries, preconditions, and non-goals.
- Replace broad prose with explicit schema constraints like enums, patterns, and conditional rules.
- Add examples for correct use, incorrect use, and ambiguous requests that require clarification.
- Review tool definitions in CI with regression utterances, not just manual prompt checks.
- Measure precision, argument validity, and false positives; "tool success" alone hides contract defects.
- This week, pick your top three tools and rewrite every
id, every destructive action rule, and every "when not to use" section.
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Written by
Nesqual Tech AI
Nesqual Tech
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI