Skip to content

The Five Tool Design Principles

Before you start

Prerequisite: Week 1, Lesson 04 (the agent loop, tool calling, and MCP) — you should already accept that the model never touches the world directly, it only writes a JSON string, and your code decides what that string is allowed to do. After this lesson, you can: name the five parts every tool needs (identity, schema, execution environment, side effects, trust boundary), and diagnose a production tool failure by asking which of the five was skipped, rather than blaming the model for "choosing badly."

The question worth asking before you write another tool

Rod needs to book a 160-person post-conference pub in Edinburgh tonight, with vegan catering, before a 5 PM cutoff. Hand an agent a book_venue function with a vague docstring, and what breaks it in production usually isn't the model picking the wrong pub — it's the tool call itself: a schema that accepts a string where an integer belongs, or an unhandled exception that kills the loop instead of telling the model what went wrong.

Last week's lesson ended on a single line: the model doesn't do things, it suggests what to do, and your code is the one that turns the key. This week starts by taking that seriously. If the model only ever writes a JSON string, then "giving an agent a tool" can't mean "writing a function with a docstring" — it has to mean something more specific, because that JSON string has to land somewhere, get validated, get executed, and come back in a shape the model can reason about without crashing the loop.

So here's the question: when a tool-calling agent fails in production, is it because the model picked the wrong tool, or because the tool itself was underspecified? Most engineers assume the first answer. This lesson argues for the second — not as a proven incident count, but as the working hypothesis the five-part definition below is built to test, and the rest of this week's lessons build on.

The five-part contract, not a docstring

A tool is a named, schema-defined interface that lets an LLM read or modify state outside its own parameters. That's precise on purpose — it rules out "anything the model can call" and replaces it with five parts that every tool needs, regardless of which of the five paradigms this course covers implements it:

  • Identity — a name the model uses to select it.
  • Schema — formal input/output types, typically JSON Schema.
  • Execution environment — in-process, subprocess, or network.
  • Side effects — what it changes: files, APIs, money, notifications.
  • Trust boundary — validation rules around inputs and outputs.

The model writes the tool call. Your code executes it. That split is the whole security model this course will keep coming back to, starting narrow here and going deep in lesson 10.

The tool loop every paradigm shares

Four gaps explain why this loop exists at all. Training data has a cutoff, so tools connect live knowledge. LLMs are unreliable at precise arithmetic, so tools do computation. Models can't modify the world on their own, so tools carry state and effect. Context windows are finite, so tools reach into memory outside the window. Without tools, the agent is reasoning with no way to act on what it concludes.

How this got standardized, and why it took until 2023

Tool use didn't start with function calling. It has a real history, and it's worth knowing because the current standard — JSON Schema, structured tool calls — is a recent fix for a specific, named failure mode. The two entries that matter most for what this course builds on are both public, checkable releases, not course lore: OpenAI shipped function calling in June 2023, and Anthropic published the Model Context Protocol in late 2024. The earlier rows below compress a longer, less precisely dated history of expert systems and retrieval pipelines; treat those eras as the source deck's own approximate framing, not dated citations.

EraParadigmMechanismLimitation
1970s–1990sExpert systemsHardcoded rules and proceduresBrittle, not learnable
2019–2022RAG pipelinesRetrieval before generationA human decides when to retrieve
2022–2023Prompt-hack toolsParse Action: text, then executeBrittle, no schema
June 2023Function callingJSON Schema plus structured outputPer-vendor, no standard
2024Parallel tool callsMultiple tools per turnStill ad hoc per integration
Late 2024MCPStandard protocol, model to toolAgent-to-agent still ad hoc
2025–2026A2AStandard protocol, agent to agentStandards still maturing

Before June 2023, a tool call was a string like Action: check_pub(name='The Bow Bar'), and your code had to parse free text to figure out what the model meant — fragile by construction. Function calling replaced that with a JSON Schema the model fills in and your code validates before it ever runs. That single shift is why the five-part definition above is possible to state precisely: schema-defined interfaces didn't really exist as a first-class concept until this happened.

This week works through five tool paradigms against one running scenario: Rod needs to book a 160-person post-conference pub for tonight, with vegan catering, before a 5 PM cutoff.

#ParadigmInterfaceEdinburgh capability
1CLISubprocess plus shellRead local venue notes from disk
2FunctionsJSON Schema to Python functionCheck pub availability with typed constraints
3APIsHTTP RESTGeocode Edinburgh plus live weather
4MCPJSON-RPC protocolShared venue-search server across agents
5A2AAgent Cards and TasksDelegate booking negotiation to a specialist

Lessons 08 through 10 implement all five against this exact scenario, with working code. This lesson stays at the level every one of those five paradigms has to satisfy first.

Five principles, five separate disciplines

Here's the misconception worth naming directly: "good tool design" is not "write a clear docstring." A tool can have a beautifully written description and still fail in production from an inconsistent return shape, or an unmarked destructive action nobody gated. Naming, description, schema, return contract, and side-effect tiering are five separate disciplines. Getting four of five right does not make the fifth optional.

Principle 1: Naming

The name is the model's first signal for deciding when to call a tool. Verb-first, specific, snake_case, and stable — check_pub_availability, geocode_location, book_venue. Names like helper, data, or tool_v2 give the model nothing to select on. A name change breaks every agent already calling that tool, so treat naming as an interface commitment, not a cosmetic choice.

Principle 2: Descriptions

The most important field almost nobody writes carefully. A good description answers four questions: what does it do, when should you use it, what does it return, and when should you NOT use it. That last question is the most underused trick in tool engineering — a description like "Check if a named Edinburgh pub meets capacity and dietary requirements... Do NOT use this for weather — use get_weather instead" does disambiguation work no amount of model capability can substitute for.

Principle 3: Schema design

Be precise, be explicit, be boring. Use enum for bounded choices instead of free text. Put units in the schema ("unit": {"enum": ["celsius", "fahrenheit"]}), not in the prose where the model might miss them. Set additionalProperties: false to block hallucinated fields, and mark required explicitly. The anti-pattern to watch for is a single command: str catch-all field — that's the prompt-hack era's brittleness smuggled back in behind a schema that looks modern.

Principle 4: Return contracts

Always return the same shape. Every tool call resolves to one of three named contracts: success ({"success": True, "data": {...}}), structured failure with an error_code ({"success": False, "error": "Pub not found: The Bow Bar", "error_code": "NOT_FOUND"}), or partial-with-warning ({"success": True, "data": [...], "warning": "Only 5 of 50 results returned"}). By construction, raising an unhandled exception is the one path that breaks this contract outright — it crashes the loop instead of giving the model something to reason about. A structured failure lets the model say "that pub wasn't found, I'll try another." An exception just ends the conversation.

Principle 5: Side-effect tiers

Not every tool carries the same risk, and treating them as if they do is how destructive actions ship without a human gate. Four tiers, each with a named safety rule:

TierTypeExamplesSafety rule
PureNo side effectscalculate, format_dateFree to retry
ReadQuery onlysearch_venues, get_weatherSafe to retry
WriteMutates statebook_venue, send_emailMust be idempotent
DestructiveIrreversibledelete_record, charge_cardHuman approval required

In the Edinburgh scenario, search_venues costs nothing to call twice. book_venue needs a human in the loop before it fires, because a wrong booking isn't something a retry undoes.

Trust boundary: named here, built out in lesson 10

The fifth part of the original definition — trust boundary — is intentionally left thin in this lesson. It means the validation rules around what a tool accepts as input and what it returns as output, and naming it here is enough to make the five-part contract complete. What it actually takes to defend that boundary against a hostile tool output — the lethal trifecta, prompt injection through tool results, the defence stack — is lesson 10's exclusive ground, because it deserves the full lesson it gets there rather than a rushed paragraph here.

Quick check — A team's agent keeps returning inconsistent errors — sometimes a clean JSON error, sometimes a raw stack trace that crashes the loop. Which of the five tool-design principles does this point to first?

What this buys you before the code starts

Treat these five principles as the spec every paradigm in this week has to satisfy, and the implementation lessons that follow become mechanical: lesson 08 builds CLI wrappers and in-process functions against this exact naming, description, schema, and return-contract discipline. Lesson 09 does the same for external APIs and MCP servers. Lesson 10 finishes the paradigm map with A2A and finally earns the trust-boundary section this lesson only named. Skip any one of the five here, and the failure shows up later as a production incident that looks like a model problem but isn't.

Continue to Lesson 08

CLI wrappers and in-process functions: the two foundational tool paradigms, and the four safety rules that make a subprocess call survivable.

Have a question about this lesson?

Reply here and it goes straight to Rod. Same as replying to one of his emails.