Function calling is a model capability in which the developer describes functions with typed parameters, and the model returns a function name and structured arguments instead of prose. The application, not the model, executes the function, and the term is often used interchangeably with tool calling, which is the broader concept.
A function call is a model’s structured request for an operation, not the operation itself. Between the request and whatever finally changes in the world, four parties each do part of the work. The model proposes. The application’s harness validates and dispatches. The runtime supplies the capabilities the function uses. The target system decides what actually happens. The entry on tool calling describes the round trip in general. This entry follows the chain as model APIs implement it, and shows where a successful-looking call can still fall short of its intended effect.
Exposure: what the model is given
A function is exposed to the model as three things:
- A name, unique among the functions offered.
- A description in plain language, written by the developer. The model has no other account of what the function does.
- A schema for its parameters, usually JSON Schema: which arguments exist, their types, which are required. Gemini’s documentation describes its format as a subset of the OpenAPI schema specification.
Frameworks often generate these from code. Pydantic AI, for example, builds the schema from a Python function’s signature and takes the description from its docstring.
The application also chooses how much latitude the model has. The major APIs share the same options under different names: let the model decide whether to call a function, require it to call one, forbid calls, or force a specific function. OpenAI calls these auto, required, none and a named function; Anthropic calls them auto, any, none and tool; Gemini calls them auto, any and none, and adds a validated mode.
The structured call
When the model decides to call a function, it returns a structured request instead of, or alongside, text. OpenAI’s API returns a call_id, a name and the arguments as a JSON-encoded string. Anthropic’s returns a tool_use block with an id, a name and an input object. Gemini’s returns the function name and its arguments.
Three details matter later:
- The call is usually identified. In APIs that attach an identifier to each call, as OpenAI’s and Anthropic’s do, the result is sent back with the same identifier, which is how the application and the model keep several calls apart. How calls and results are paired, and how strictly, differs between APIs, and it matters most when several calls are in flight at once.
- There may be several calls at once. Parallel calling is the default in some APIs and can be turned off. Gemini’s documentation also describes compositional calling, where one call’s result feeds the next.
- Some functions are not the application’s. Anthropic distinguishes client tools, which the application executes, from server tools such as web search, which run on Anthropic’s own infrastructure. For a client function, the application runs it. As Gemini’s documentation puts it, the model does not execute the function itself.
Valid is not the same as correct
A model can produce arguments that do not match the schema: a missing field, a string where a number belongs. Two mechanisms address this. Providers offer constrained modes, OpenAI’s strict mode and Anthropic’s strict tool use among them, in which the model’s output is constrained so that the arguments conform to the schema; Anthropic describes its version as grammar-constrained sampling and guarantees that the input follows the schema and the name is a valid tool. Applications and frameworks also validate what they receive, and some return a validation error to the model so it can try again.
Both establish the same thing: the arguments satisfy the schema. Within the subset of JSON Schema a provider or framework supports, that can include more than shape: required fields, types, allowed values, patterns and ranges. What no schema can establish is real-world correctness or authority. A schema can require an order identifier in the right format and cannot know whether it is this customer’s order, whether the order can still be changed, or whether the caller is permitted to change it. Anthropic’s documentation notes that when a request lacks a required value, a model may ask for it or may infer a plausible one the user never supplied. A schema-valid call is a well-formed request, and the rest of the chain still decides whether it is a correct one.
Validation, approval and dispatch
Everything between the model’s request and the function running belongs to the application. A harness can:
- validate the arguments, and return an error to the model if they fail;
- check whether this function may be called now, by this agent, with these arguments;
- ask a person to approve the call before it runs, which is where human in the loop usually attaches;
- refuse, and tell the model so;
- dispatch the call.
None of these is part of function calling as a model capability. They are the application’s choices, and a function call is exactly as controlled as the application makes it.
Execution and the returned result
Once dispatched, the function runs with whatever its runtime provides: its credentials, its network access, the systems it can reach. The function then returns something, and the application sends that back to the model: OpenAI’s API takes it as a function_call_output tied to the call_id, and Anthropic’s as a tool_result tied to the tool_use_id, with an optional error flag. The model reads the result and decides what to do or say next.
The result is the function’s report. It says what the function chose to return, not what happened in the system the function called. A function that submits a change to another service and returns {"status": "accepted"} has reported acceptance, which is true, and has said nothing about whether the change took effect.
An example: one call from proposal to effect
The following sequence is genuine output from Pydantic AI, an open-source agent framework. The model is Pydantic AI’s function model, scripted for this entry to make the three moves shown, so no live language model chose them. The function is a stand-in for a fulfilment service: it records a pending change in an in-memory store and returns a status. Nothing outside the process was contacted.
A customer asks: “Please change the shipping address on order-4412 to 450 Mission St, 94107.”
1. Exposure. The framework generated this definition from the function’s signature and docstring and gave it to the model:
{
"name": "update_shipping_address",
"description": "Change the shipping address on an order that has not yet shipped.",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"postal_code": {"type": "string"},
"street": {"type": "string"}
},
"required": ["order_id", "postal_code", "street"],
"additionalProperties": false
}
}
2. A call that fails validation. The model’s first request omitted the street:
{"tool_name": "update_shipping_address", "tool_call_id": "call_1",
"args": {"order_id": "order-4412", "postal_code": "94107"}}
Pydantic AI validated the arguments, did not run the function, and returned the error to the model: the field street was required.
3. A valid call, dispatched. The model asked again with all three fields, as call_2. This time the arguments passed validation and the function ran.
4. The result. The function returned {"status": "accepted", "order_id": "order-4412"}, and the framework sent it back to the model with the call’s identifier.
5. The model’s answer. “Done: the shipping address for order-4412 is now 450 Mission St.”
6. The target system. The stand-in fulfilment store, read after the run: the order’s address was still 12 Elm St, the label had already been printed, and the new address sat in a list of pending changes.
The call was validated on its second attempt, dispatched, and accepted: the function returned a status of accepted, and the model told the customer the address had changed. The effect the customer wanted, a parcel going to the new address, was not verified anywhere in this exchange. The target system’s own state shows it had not happened, and nothing in the exchange read that state. Acceptance of the call and the intended effect are different facts, and here only the first was established.
Where the chain can break
| Link | What can go wrong |
|---|---|
| The model proposes | The wrong function, or the right function with plausible but wrong values |
| The schema constrains | Schema-valid arguments can still identify the wrong order or an unauthorized operation |
| The harness dispatches | A call that should have been checked or approved is dispatched without it |
| The runtime supplies | The function reaches more, or less, than intended |
| The target decides | The request is accepted but deferred, partially applied, or overtaken by earlier state |
| The result reports | The function reports what it chose to report, which may not be the effect |
| The model reads the result | A report of acceptance is retold as a completed change |
Often confused with
Tool calling. The broader concept, and often used interchangeably. Tool calling covers functions the application defines and also tools provided by a model vendor or supplied through a protocol. Function calling is the model capability at its core.
The agent harness. The harness is the software that receives the model’s call, validates it, decides whether to run it, dispatches it and returns the result. Function calling is what the model contributes to that exchange.
Calling an API. A function call is not an API call, though the function often makes one. The model requests a function; the application runs it; the function may then call an API, which is the request that actually reaches the target system.
The agent runtime. The environment the function runs in. The same function call can reach very different systems depending on the runtime, which the runtime entry covers.
The Model Context Protocol. A protocol for exposing tools and data to applications. An MCP server’s tool, once offered to a model, is called through function calling, and MCP defines how the application then invokes it on the server.
Runtime governance. Evaluates each dispatched call against what the agent was asked to do. Function calling produces the calls; governance examines them against applicable policies, permissions or task boundaries.
Function calling and runtime governance
The moment after a call has been validated and before it is dispatched is an execution boundary, and what can be captured there is an agent action: which function, which kind of operation, which system. Runtime governance can evaluate a proposed action against applicable policies, permissions or declared task boundaries before execution. It asks a question function calling does not: whether this call is permitted in this context. Like the schema, it examines the request; neither confirms what the call changed in the target system.
Where the concept stops
Function calling lets a model ask for an operation in a form software can act on. It establishes that the model made a well-formed request, and, with constrained modes, that the request matches its schema. It does not establish that the values are right, that the call should have run, that the function did what it was meant to, or that the target system changed as intended. Those depend on the application, the runtime and the target system, and on evidence from the last of these.