HOW-TO · RAG

How to Define JSON Schema for Tool Calling

intermediate15 minBy Fredoline Eruo
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES

Function calling-capable model, Python 3.10+

What this does

JSON Schema defines the structure and types of parameters for tool-calling functions. Well-defined schemas help the LLM generate correct arguments and reduce parsing errors.

Steps

  • Write a minimal schema. Every tool schema needs name, description, and parameters.
tool_schema = {
    "type": "function",
    "function": {
        "name": "send_email",
        "description": "Send an email to a recipient",
        "parameters": {
            "type": "object",
            "properties": {
                "to": {
                    "type": "string",
                    "description": "Recipient email address"
                },
                "subject": {
                    "type": "string",
                    "description": "Email subject line"
                },
                "body": {
                    "type": "string",
                    "description": "Email body content"
                }
            },
            "required": ["to", "subject", "body"]
        }
    }
}
  • Include type-rich properties. Use enum, integer, array, and number types to constrain values.
{
    "name": "search_database",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "limit": {"type": "integer", "minimum": 1, "maximum": 100},
            "sort_order": {"type": "string", "enum": ["asc", "desc"]},
            "filters": {
                "type": "array",
                "items": {"type": "string"}
            }
        },
        "required": ["query"]
    }
}
  • Add descriptions for every field. The LLM uses descriptions to understand parameter semantics.
properties = {
    "temperature": {
        "type": "number",
        "description": "Temperature in Celsius, e.g., 22.5"
    },
    "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "Temperature unit"
    }
}
  • Generate schema from Python functions automatically. Use LangChain's @tool decorator.
from langchain.tools import tool

@tool
def fetch_user(user_id: int, include_deleted: bool = False) -> dict:
    """Fetch a user by ID. Optionally include deleted users."""
    return {"id": user_id, "deleted": include_deleted}

print(fetch_user.args_schema.schema())
# Auto-generated JSON Schema
  • Validate arguments against schema. Use jsonschema library to validate before execution.
from jsonschema import validate, ValidationError

try:
    validate(instance=args, schema=tool_schema["function"]["parameters"])
except ValidationError as e:
    print(f"Invalid arguments: {e.message}")

Verification

python -c "
from langchain.tools import tool
@tool
def add(a: int, b: int) -> int:
    '''Add two numbers.'''
    return a + b
s = add.args_schema.schema()
print(s['properties']['a']['type'])
# Expected: integer
"

Common failures

  • Missing required field. Without required, the LLM may omit essential parameters, causing runtime errors.
  • type: object without properties. An empty properties object is valid but useless. Always define at least one property.
  • Enum values don't match case. The LLM may send "ASC" while the enum expects "asc". Use lowercase or handle normalization in the function.
  • Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
  • Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.

Related guides

  • How to Use OpenAI Function Calling with Tools
  • How to Enable Function Calling in Local Models (Ollama)