Skip to content
Learn Agentic AI11 min read0 views

Designing Tool Schemas for AI Agents: JSON Schema Best Practices

Learn how to write effective JSON Schema tool definitions that help LLMs understand parameters, constraints, and expected inputs. Covers parameter types, descriptions, required vs optional fields, nested objects, and enums.

Why Tool Schemas Matter More Than You Think

When an LLM decides to call a tool, the only thing guiding that decision is the schema you provide. A vague schema produces vague tool calls. A precise schema produces precise ones. The JSON Schema definition you attach to each tool is not just a validation layer — it is the primary interface between the LLM's reasoning and your code's execution.

This post covers the practical patterns that make tool schemas work reliably across OpenAI, Anthropic, and open-source function-calling models.

The Anatomy of a Tool Schema

Every tool schema has three critical parts: the function name, the description, and the parameters object. Here is a minimal example:

search_tool = {
    "type": "function",
    "function": {
        "name": "search_documents",
        "description": "Search internal documents by keyword query. Returns the top matching document titles and snippets. Use this when the user asks about company policies, procedures, or internal knowledge.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "The search query. Use specific keywords rather than full sentences."
                },
                "max_results": {
                    "type": "integer",
                    "description": "Maximum number of results to return. Defaults to 5.",
                    "default": 5,
                    "minimum": 1,
                    "maximum": 20
                },
                "department": {
                    "type": "string",
                    "description": "Filter results to a specific department.",
                    "enum": ["engineering", "sales", "hr", "finance", "legal"]
                }
            },
            "required": ["query"]
        }
    }
}

Notice a few things. The function description explains both what the tool does and when to use it. Each parameter description guides the LLM on how to fill that parameter. The enum constrains free-text to valid values. The required array distinguishes mandatory from optional parameters.

Writing Descriptions That Guide Selection

The function description is the most important field. The LLM reads it to decide whether to call the tool at all. Write descriptions that answer three questions: what does this tool do, when should it be used, and when should it not be used.

# Bad: too vague
"description": "Gets weather data"

# Good: explains what, when, and constraints
"description": "Fetch current weather conditions for a specific city. Returns temperature, humidity, and wind speed. Use this when the user asks about current weather. Do NOT use this for weather forecasts or historical weather data."

Parameter Types and Constraints

JSON Schema supports types that map well to tool calling. Use them precisely:

"properties": {
    "name": {
        "type": "string",
        "description": "Full name of the customer",
        "minLength": 1,
        "maxLength": 200
    },
    "age": {
        "type": "integer",
        "minimum": 0,
        "maximum": 150
    },
    "tags": {
        "type": "array",
        "items": {"type": "string"},
        "description": "List of tags to apply. Each tag is a lowercase string.",
        "maxItems": 10
    },
    "is_active": {
        "type": "boolean",
        "description": "Whether the account is currently active"
    }
}

The minimum, maximum, minLength, maxLength, and maxItems constraints are not always enforced by every model, but they serve as documentation that helps the LLM generate reasonable values.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

Nested Objects and Complex Structures

When a tool needs structured input, use nested objects with their own property definitions:

"properties": {
    "filters": {
        "type": "object",
        "description": "Search filters to narrow results",
        "properties": {
            "date_from": {
                "type": "string",
                "description": "Start date in YYYY-MM-DD format"
            },
            "date_to": {
                "type": "string",
                "description": "End date in YYYY-MM-DD format"
            },
            "status": {
                "type": "string",
                "enum": ["open", "closed", "pending"]
            }
        },
        "required": ["date_from"]
    }
}

Keep nesting to two levels at most. Deeply nested schemas confuse most models and lead to malformed calls.

Required vs Optional: The Decision Framework

Mark a parameter as required when the tool cannot function without it. Mark it as optional when there is a sensible default or when the parameter narrows results but is not essential.

A common mistake is making everything required. This forces the LLM to hallucinate values for parameters the user never mentioned. Another mistake is making everything optional, which leads to vague, unfocused tool calls.

Enums: Your Most Powerful Constraint

Enums are the single most effective way to prevent invalid tool calls. Whenever a parameter has a finite set of valid values, use an enum. The LLM will almost always pick from the enum list rather than generating a free-text value.

"priority": {
    "type": "string",
    "enum": ["low", "medium", "high", "critical"],
    "description": "Priority level for the ticket"
}

FAQ

How many parameters should a single tool have?

Keep tools to 5-7 parameters at most. Beyond that, models start making mistakes with parameter mapping. If you need more, consider splitting the tool into two or grouping related parameters into a nested object.

Should I use camelCase or snake_case for parameter names?

Use snake_case. Most function-calling models were trained primarily on Python tool definitions, and snake_case produces marginally more reliable calls. Be consistent across all your tools regardless of which convention you choose.

Do all LLM providers support the same JSON Schema features?

No. OpenAI supports most of JSON Schema including enum, minimum, maximum, and nested objects. Anthropic supports a similar subset. Open-source models vary widely. Stick to basic types, enums, and one level of nesting for maximum compatibility.


#ToolDesign #JSONSchema #FunctionCalling #AIAgents #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.