C.W.K.
Stream
Lesson 02 of 05 · published

JSON Schema as Contract

~26 min · json-schema, parameters, description, required

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The tool definition is a contract between you and the model. The most underrated field in that contract is the description — the prose that tells the model when and why to use this tool. Production teams routinely under-invest in descriptions and over-invest in fancy schemas. The model selects tools by reading descriptions, not by reading your hopes.

Schema-wise, every modern provider speaks JSON Schema with minor dialectic differences. The shape that always works is: {"type": "object", "properties": {…}, "required": [...]} with each property carrying its own type and a one-line description. Use enum for closed sets ("status": one of open|closed|in_progress). Use format for things like dates and emails — most providers do not enforce them, but they bias the model toward producing valid output.

Three rules for descriptions, learned the hard way:

  • Tool description: when, not what. "Get current weather for a city" is a definition. "Use this when the user asks about today's weather, temperature, or whether it will rain in a named city" is a contract.
  • Parameter descriptions: format and edge cases. Not just "city name" — "city name in English; for cities with translations like 'Seoul' use the romanized form, not '서울'." That is the description that prevents the most common failure mode.
  • Required is required. If a parameter is required to answer correctly, mark it required. Optional parameters get omitted half the time and the model never asks; required ones get a structured re-ask if missing.

Schema design is a writing problem disguised as an engineering problem. The schema is correct when a colleague who has never seen your codebase can read the tool definition and predict, with 90% accuracy, what the tool does and when the model will pick it.

Code

A well-described tool — Anthropic shape·python
{
  "name": "search_orders",
  "description": (
    "Search the customer's order history. Use this when the user mentions "
    "an order, a tracking number, a refund, or asks 'where is my package'. "
    "Do NOT use this for product browsing — use search_catalog for that."
  ),
  "input_schema": {
    "type": "object",
    "properties": {
      "customer_id": {
        "type": "string",
        "description": "The customer's account ID, exactly as it appears in the user's profile context."
      },
      "status": {
        "type": "string",
        "enum": ["pending", "shipped", "delivered", "returned"],
        "description": "Filter by status. Omit to search all statuses."
      },
      "since": {
        "type": "string",
        "format": "date",
        "description": "Earliest order date to consider, in YYYY-MM-DD format."
      }
    },
    "required": ["customer_id"]
  }
}
OpenAI Responses API — same shape, slightly different envelope·python
tools = [{
    "type": "function",
    "name": "search_orders",
    "description": "...",
    "parameters": {
        "type": "object",
        "properties": { ... },
        "required": ["customer_id"]
    }
}]

External links

Exercise

Take a tool you already use in code and rewrite its description three times: once as 'what it does', once as 'when to use it', once as 'when NOT to use it (and what to use instead)'. Run all three through a model with the same prompt and observe selection accuracy. The 'when to use it' version usually wins; the 'when NOT' version is the tiebreaker for tools that overlap.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.