Function Calling and Tool Schemas
Goal
Design a provider-neutral tool schema that names one action, documents its purpose, and constrains required argument names, types, and allowed values.
Think of a paper form at a school office. The form has a name, explains what request it is for, and has boxes with rules: student ID must be text, number of tickets must be between 1 and 4, and some boxes are required. Filling the form correctly does not mean the request is approved; it only means the request has the expected shape.
A tool schema plays that role for a model-facing tool. It tells the model which action exists and which argument names, types, and allowed values form a valid proposal. Authorization is a separate decision made by trusted application code after the proposal passes the shape checks.
A useful schema is closer to an API contract than to a persuasive prompt.
Start from the function you actually want
Suppose the application needs:
search_orders(customer_id, status, limit)
The schema should explain those exact fields. If limit must be between 1 and 20, say so. If status can only be open, shipped, or closed, encode that boundary instead of hoping the model remembers prose.
A simplified JSON-Schema-style description might be:
{
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"status": {"enum": ["open", "shipped", "closed"]},
"limit": {"type": "integer", "minimum": 1, "maximum": 20}
},
"required": ["customer_id"],
"additionalProperties": false
}
The application can validate the model's arguments against the same shape.
Descriptions should explain meaning, not hide policy
A field description can say “maximum number of orders to return.” It should not be the only place that enforces a security rule such as “users may only read their own orders.”
Security policy belongs in trusted application code. A schema helps reject malformed data; authorization decides whether a valid request is allowed for the current user.
Required, optional, and default are different
If a field is required, its absence is invalid. If it is optional, the application must define what omission means. A default is an explicit application choice.
These distinctions matter because silent guesses can create surprising behavior. If a currency field is omitted, choosing USD without a documented rule may be unsafe for a payment tool.
Extra fields should have a policy
Unexpected arguments can be harmless typos or attempts to smuggle unsupported control into the tool call. For narrow tools, rejecting additional properties is often easier to reason about than silently ignoring them.
The rule should be explicit and tested.
Schema design affects tool selection
Two tools with vague, overlapping descriptions are difficult for both humans and models to distinguish. Prefer names and purposes that map to clear task boundaries.
For example:
get_order(order_id) → read one order
cancel_order(order_id) → request cancellation
is clearer than two tools both described as “manage orders.”
Schemas should be versioned like interfaces
Tool schemas are part of the model-facing application interface. If status gains a new allowed value or a required argument is renamed, old recorded tool calls may no longer validate. Record a schema version in traces and evaluation fixtures so a later failure can be connected to the interface that produced it.
Backward-compatible changes should still be tested. Adding an optional field may look harmless, but it can change which tool the model selects or which arguments it tends to emit. Removing a field can break a retry or replay path. Treat schema changes as software-interface changes with fixed regression cases rather than as prompt copy edits.
Descriptions need observable boundaries
A description such as “Use this for order operations” is too broad if several tools manage orders. Prefer a sentence that states the operation and its boundary: “Read the current status of one order by ID; this tool does not modify the order.” That wording helps selection while also giving reviewers a human-readable expectation to compare against the executable schema and policy.
Predict
Run the local Lab
python labs/notebooks/level-10/l10-02-tool-schema.py
- Run the command. Of the four candidate argument objects, only the first is accepted. The others fail for three different reasons:
missing=['customer_id'],limit: outside range, andextra=['debug']. - Change
"additional_properties_allowed": FalsetoTrueand rerun. - Only the fourth candidate changes:
{'customer_id': 'c-1', 'debug': True} -> (True, 'ok'). The tool now silently accepts a field it does not understand. - Explain whether that broader interface is useful for this tool. (Hint: what could an unexpected
debugoroverridefield do if a later version of the tool started reading it?) Change the value back toFalse.
Loading lab…
Write the core logic yourself
Open:
labs/notebooks/level-10/l10-02-tool-schema-exercise.py
Implement required-field, unexpected-field, type/enum, and range validation. The starter fails until your validator distinguishes the four supplied cases.
Run the starter after each change:
python3 labs/notebooks/level-10/l10-02-tool-schema-exercise.py
A correct implementation ends with a PASS: marker. Only after you have a working version, compare your approach with the solved deterministic script used by the Level smoke tests.
Optional: let a real model propose the tool call
After the deterministic Lab is clear, use the optional real-model extension:
python labs/real-model/l10_tool_calling_real_model.py
The script passes a real Python function definition through the model's tool-aware chat template. Inspect the model's proposal before the application executes anything. The controller still checks the tool allowlist and exact argument shape, so a model-generated call is treated as data rather than authority.
Change the user request to an order that does not exist, then try wording that does not require order data. Compare what the model proposes with what the deterministic controller is willing to execute.
Quick Check
Key Takeaways
- Tool schemas describe names, meanings, types, required fields, and allowed values.
- Schema validity and authorization answer different questions.
- Optional fields need explicit omission/default behavior.
- Extra properties need an explicit accept/reject policy.
- Clear tool boundaries improve both selection and security review.
Next Lesson
Next, turn the schema into an executable validation boundary before any external call occurs.
References
- JSON Schema, Draft 2020-12 Core Specification.
- OpenAPI Initiative, OpenAPI Specification 3.1.0.
Completion is stored locally on this device.