The mechanics are deliberately simple. The application registers available functions with the model as JSON Schemas — a name, a description and typed parameters. When the model decides a function is needed, its response contains a structured call request rather than prose. The application validates the arguments, executes the real code, and appends the result as a tool message so the model can reason over it. The model never executes anything itself; it requests, and your code decides whether to comply. That indirection is the entire security model.
The description fields do more work than most teams realise. The model chooses which function to call, and with what arguments, almost entirely from the names and descriptions in the schema. Writing "returns the customer record for an email address; call this before any refund operation" reliably outperforms "gets customer", and strict schemas with enums, formats and required fields convert the model's guessing into validation errors your code can catch.
In production, function calling should be treated as an RPC layer exposed to an untrusted caller. Arguments are validated server-side on every call, expensive or destructive functions require approval tokens the model cannot issue to itself, and functions that mutate state are made idempotent so a retried call does not execute twice. Parallel calls — the model requesting several functions in one turn — are normal and need concurrent-safe handlers.
Error returns deserve the same design attention as success. A stack trace teaches the model nothing, while "customer not found for that email address — confirm it with the user before retrying" steers its next step. Well-built functions fail predictably, with error messages written for the model to act on rather than for a developer to debug, timeouts on every execution, and a hard cap on calls per run enforced by the executor itself. When those properties hold, the model can recover from most failures on its own, which is what makes a tool-using system feel robust instead of brittle.
There is also a maturity path worth recognising. The simplest use is a single call answering a single prompt — look something up, then respond. Agents generalise that into a loop where the model chains calls toward a goal. Protocols like MCP then standardise the registration side, so a capability exposed once becomes callable from any compatible client rather than being rewired per assistant. The underlying mechanism is identical at each stage; what grows is how much decision-making the loop around it owns.
Structured request, not execution
The model emits a call request; application code validates and executes it.
Schema-driven
Names, descriptions and JSON Schema types drive the model's calling behaviour.
Provider-standard
Supported across OpenAI, Anthropic, Gemini and open-weight models, with minor format differences.
Codazz builds this in production — AI Agent Development.