← Contents Volume IX · Lecture 20

Volume IX · Designing the Tools

20

Writing a Tool a Model Won't Misuse

Lecture 13 described function calling as a JSON contract — a schema, a stop reason, a result block passed back into the conversation. That lecture was about what makes the contract valid. This one is about what makes it good — because a schema can be perfectly valid JSON and still be a trap: an ambiguous parameter name, an error message the model can't act on, a response so verbose it burns the context window on noise. Anthropic's engineering write-up on this frames tools as "a fundamentally new software paradigm: contracts between deterministic systems and non-deterministic agents" — and a contract with an unreliable party needs to be written more carefully, not less.

The mental model

Every dimension of a tool's design — its description, its errors, its scope, its namespace, its response format — is a lever on whether the model uses it correctly, and each lever has been measured to matter: precise descriptions moved a real SWE-bench state-of-the-art result, and a single response format choice cut token cost by roughly two-thirds in a disclosed example.

Describe it like you're briefing a new hire

"Writing effective tools for AI agents—using AI agents" (anthropic.com/engineering/writing-tools-for-agents) gives a concrete heuristic for description quality: "think of how you would describe your tool to a new hire on your team." A new hire has none of the implicit context that lives in your head — they need the ambiguity resolved in words, not assumed. The same discipline applies to parameter names: user_id is unambiguous, user is not, and the model has no way to ask a clarifying question mid-call the way a new hire could ask you one at their desk. The post states this is not a cosmetic concern — precise refinements to tool descriptions were part of how Claude Sonnet 3.5 reached a state-of-the-art SWE-bench result. Description quality is measured to move outcomes, not just readability.

An error message either teaches or it wastes a turn

When a tool call fails, what comes back matters as much as whether it failed at all. A cryptic error code or a raw stack trace gives the model nothing to act on except a guess. The guidance here is to make error messages actionable — describe what went wrong in terms the model can use to correct itself, and where possible, show a corrected example input alongside the error rather than just the failure. An error message that teaches turns a failed call into a recoverable one; an error message that doesn't just burns a turn on a retry the model has no better information for.

Consolidate — three thin tools becoming one that thinks

The post argues against 1:1 wrapping of every API endpoint as its own tool, on the grounds that more tools is not more capability — it's more surface area for the model to choose wrong across. The worked example: collapsing separate list_users, list_events, and create_event tools into a single schedule_event tool that internally handles availability checking itself. The model no longer has to orchestrate three calls correctly in the right order and reason about their interaction — the tool absorbed that reasoning, and the model just states the intent.

CONSOLIDATION — THREE THIN TOOLS, ONE THAT THINKS list_users list_events create_event must sequence all three calls schedule_event handles availability checking internally model states intent, not orchestration
Figure 20a The consolidated tool does not do less work — it does the same work, but the coordination logic moved from the model's context window into the tool's own implementation, where it can't be gotten wrong by a bad orchestration decision.

Namespacing groups tools the way a filesystem groups files

When many tools exist across several services, the post recommends grouping them by a service or resource prefix — asana_search, jira_search — so the model can tell at a glance which system a tool belongs to before it has read the tool's full description. The authors note that the choice between prefix-based and suffix-based namespacing had a non-trivial effect on agent behavior in their own testing — a detail worth taking seriously precisely because it is the kind of decision that looks cosmetic and isn't.

Token efficiency: return only what's high signal

A tool response competes for the same context window as everything else the model is reasoning over, and the post is specific about the fix: implement pagination, filtering, range-selection, and truncation with sane defaults, so a tool doesn't dump an entire dataset back at the model when a handful of rows would answer the question. Return only "high signal information," and prefer semantic identifiers over raw UUIDs — a name or slug the model can reason about, not an opaque token it can only copy verbatim. The quantified example: a verbose Slack tool response cost 206 tokens, where a concise response covering the same information cost 72 tokens — roughly a third the size, repeated across every call a long-running agent makes.

TOKEN COST OF THE SAME INFORMATION, TWO RESPONSE FORMATS verbose response 206 tok concise response 72 tok same information, ~1/3 the tokens — repeated across every call
Figure 20b Both figures are the post's own disclosed numbers for the same underlying Slack response, rendered two different ways. The saving compounds: a long-running agentic loop makes many such calls, and the difference is paid every time.

Evaluating and refining tools the same way you'd eval a model

The post's evaluation methodology treats tool design as an empirical question, not a one-time judgment call. Build realistic multi-tool-call tasks modeled on real workflows — tasks that may require dozens of tool calls to complete — and run them through a simple agentic loop using direct API calls. Track accuracy, runtime, tool-call count, token consumption, and errors as the actual metrics. Then feed the resulting transcripts back into Claude itself and have it propose refactors to the tool definitions, validating any refactor against a held-out test set so the refinement doesn't just overfit to the tasks it was tuned on.

The disclosed result of running this loop: tool definitions that Claude itself refined this way outperformed the human-written originals on held-out Slack and Asana MCP test sets. The post does not disclose an exact percentage improvement in the fetched text, so this should be stated qualitatively — a real, measured improvement, without inventing a number the source doesn't give.

The throughline: a contract only works if both sides can hold up their end

Lecture 13 established that a tool call is a schema and a result block — a valid contract. Everything in this lecture is what makes that same contract good: a description a new hire could follow, an error message that teaches instead of just failing, a scope that doesn't force the model to orchestrate what the tool could have handled itself, a namespace that signals which system a tool belongs to, and a response shaped to spend as few tokens as the task actually needs. None of these are model capabilities — they are all decisions made on the deterministic side of the contract, which is exactly why they are worth this much attention: they are the side an engineer actually controls.

Read the primary source