Function Calling: Structured Tool Use for Large Language Models › Function Schema Definition
Language AI HandbookAll chapters Function Calling: Structured Tool Use for Large Language Models › Function Schema DefinitionOne section · Sections in this chapter2 / 12 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
For a language model to invoke external tools, it must first understand what tools are available, what parameters they accept, and what types of values those parameters require. This metadata is provided through function schemas, typically expressed in JSON Schema format, which is a contract between the model and the external environment. The schema acts as a Rosetta Stone translating between the unstructured world of human language and the rigid requirements of software APIs.
Think of a function schema as a documentation standard that a model can read and act on. When a human developer reads API documentation, they build a mental model of what the function does, what inputs it needs, and what outputs to expect. They can then write code that calls the function correctly. The model does something analogous at inference time: it reads the schema, develops a representation of the tool's purpose, and generates calls that conform to the specification. The quality of the schema directly determines how reliably this process works.
JSON Schema Structure
A function schema describes the interface of a callable function using a structured dictionary. At minimum, it specifies the function name, a natural language description of its purpose, and the expected parameters.
weather_schema = {
"name": "get_weather",
"description": "Retrieve current weather conditions for a specific location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state/country, e.g., 'Boston, MA' or 'Paris, France'",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit to use for the forecast",
},
},
"required": ["location"],
},
}The key components of a function schema are:
- name: A unique identifier for the function using snake_case conventions. This becomes the token the model emits to signal which tool to invoke. The choice of name matters semantically, as models often infer function purpose partially from the name itself. A function named
get_current_temperaturewill likely be invoked for different queries than one namedget_historical_weather_data, even if their schemas are similar. - description: A clear, imperative explanation of what the function does and when to use it. This text is semantically embedded into the model's context, and heavily influences whether the model chooses to invoke this particular tool. Well-written descriptions act as soft classifiers, helping the model distinguish between similar tools. For instance, if you have both a
search_productsandget_product_detailsfunction, the description should clarify that the former is for finding items matching criteria while the latter requires a specific product ID. - parameters: A JSON Schema object defining the function's arguments, including type constraints, valid ranges, and nested object structures. This section effectively constrains the model's output space, limiting what it can generate to syntactically valid structures.
- required: A list of parameter names that must be provided for the function call to be valid. This creates a hard constraint: if the model attempts to call the function without these parameters, the call fails validation. This forces the model to either extract the necessary information from your query or ask for clarification, rather than hallucinating missing values.
The description field deserves special attention because it operates on two levels simultaneously. At the syntactic level, it tells the model the signature of the function. At the semantic level, it guides the model's judgment about when to invoke the function at all. A description like "Retrieve current weather conditions" implicitly communicates that this function is appropriate for present-tense weather queries but not for historical weather data or general weather science questions. Writing descriptions that calibrate this boundary accurately is one of the most important skills in function calling design.
Type System and Constraints
JSON Schema provides rich typing capabilities that help constrain model outputs and prevent hallucinated parameters. These constraints serve as guardrails that reduce the cognitive load on the model during generation. When a parameter is constrained to an integer type with a minimum value of zero, the model need not consider negative numbers or fractional values, effectively narrowing the search space during token sampling.
The available type primitives and constraint mechanisms include:
- Primitive types:
string,number,integer,boolean,array,object, andnull. These basic types align with most programming language type systems, making translation to actual function arguments straightforward. - Enum constraints: Restrict string values to a predefined set of options, reducing the probability of invalid values. For example, a
colorparameter with enum["red", "green", "blue"]prevents the model from inventing colors like "turquoise" when only primary colors are supported by the underlying API. - Array schemas: Define homogeneous arrays with
itemsspecifications or heterogeneous tuples withprefixItems. This allows for complex inputs like lists of coordinates or structured records. - Nested objects: Support complex parameter structures through recursive
propertiesdefinitions. This is needed for APIs that require structured data, such as shipping addresses with nested fields for street and city plus a postal code. - Validation keywords:
minimum,maximum,minLength,maxLength,pattern(regex), andformat(email, URI, date-time). These constraints serve dual purposes. During inference, they guide the model toward valid outputs through the semantic cues in parameter descriptions. During structured decoding (as discussed in Constrained Decoding), they can be enforced grammatically to guarantee syntactic validity.
The interplay between these constraints creates a reliable interface. When a model sees a parameter defined as a string with pattern ^[0-9]{5}$, it understands that a zip code is required and that the value must consist of exactly five digits. This semantic signal helps the model extract the correct information from your queries or recognize when it lacks necessary information.
A well-designed schema reduces ambiguity at every level. Numeric ranges communicate expected magnitudes: a page_number parameter with minimum: 1 implicitly tells the model that pages are one-indexed, not zero-indexed. String format constraints communicate the expected structure of textual inputs. Even the choice between number and integer provides semantic information: using integer for a quantity parameter signals that fractional quantities are not meaningful. Every constraint you add is information the model can use to generate more accurate calls.
Schema Design Best Practices
Writing effective schemas is an iterative process that benefits from understanding how the model interprets them. The descriptions you write are not just documentation for human readers; they are the primary signal the model uses to decide whether and how to invoke the tool. Treat every word in a description as meaningful input to the model's decision process.
Several principles consistently produce more reliable schemas. First, be specific about what the function does rather than what it is. "Search products" is weaker than "Search the catalog for products matching keywords, returning up to 20 results sorted by relevance." The latter communicates the function's behavior, expected output format, and appropriate use case. Second, explicitly describe what the function does not do when there is potential for confusion with similar tools. If you have both a search_products and a lookup_product_by_id function, adding "Do not use this function when you have a specific product ID; use lookup_product_by_id instead" to the search function's description prevents the model from using the wrong tool.
Third, use consistent naming conventions across all functions in a toolkit. If some functions use user_id as a parameter name and others use userId or uid, the model may struggle to recognize that they refer to the same concept. Consistency reduces the cognitive overhead the model faces when reading schemas and makes parameter extraction more reliable. Fourth, keep required parameters minimal. Every required parameter is a point of potential failure: if the model cannot extract or infer the value, the call fails. When a parameter can be given a sensible default, make it optional with a default value documented in the description.
Finally, test your schemas with adversarial queries: questions that are adjacent to the function's domain but should not trigger it, questions that require the function but provide information in unexpected formats, and questions that are ambiguous between multiple tools. The cases where the model makes wrong decisions reveal gaps in your schema descriptions that can be addressed iteratively.
Multiple Function Definitions
Real-world applications rarely expose a single tool. Instead, they present the model with a toolkit containing multiple functions. The schemas are provided as a list, and the model must learn to select the appropriate function based on your intent. This selection process mirrors the routing logic in traditional software systems, but happens dynamically based on natural language understanding.
tools = [
{
"name": "search_database",
"description": "Query the product database for items matching criteria",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search terms"},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "books"],
},
"max_price": {
"type": "number",
"description": "Maximum price filter",
},
},
"required": ["query"],
},
},
{
"name": "calculate_shipping",
"description": "Calculate shipping cost based on weight and destination",
"parameters": {
"type": "object",
"properties": {
"weight_kg": {"type": "number", "minimum": 0},
"destination_zip": {"type": "string", "pattern": "^[0-9]{5}$"},
"express": {"type": "boolean", "default": False},
},
"required": ["weight_kg", "destination_zip"],
},
},
]When multiple functions are available, the model performs implicit tool selection by emitting the name field corresponding to the appropriate schema. This selection mechanism relies on the semantic alignment between your query, function descriptions, and parameter descriptions. The model essentially performs a form of nearest-neighbor search in embedding space, matching your intent against the semantic content of available tool descriptions.
Consider asking, "How much to ship a 5kg package to Boston?" The model must recognize that while both tools are available, only calculate_shipping addresses the specific question. It extracts "5kg" as the weight parameter, infers the zip code for Boston (or recognizes it needs this specific information), and understands that the express parameter is optional. This discrimination capability requires the model to develop a sophisticated understanding of tool capabilities through training on diverse examples. We'll explore more sophisticated selection strategies in the upcoming chapter on Tool Selection.
The challenge of multi-tool selection scales non-linearly with the number of tools available. With two tools, the selection problem is straightforward. With ten tools, the model must maintain a richer understanding of tool boundaries. With hundreds of tools (as in enterprise environments with dozens of integrated APIs), the selection problem can overwhelm the context window and tax the model's attention. Practical systems often solve this by implementing a two-stage retrieval: first retrieving the most relevant tools using embedding similarity, then presenting only the top-k candidates to the model. This mirrors how human experts work through large toolsets: they first recall which category of tool applies, then select the specific tool within that category.
