Tool Calling Is Not Tool Execution: The Model and the Application
AI Foundations #35 explains the tool-calling loop, function schemas, structured arguments, execution permissions, tool results, and why valid JSON is not authorization.
Approximately 8 min read · AI Foundations / Lesson 35
In AI Foundations #34, we learned that an LLM runtime can constrain tokens so a reply follows a grammar or JSON Schema.
That raises a natural next question:
If a model produces a valid JSON instruction, does the real-world action automatically happen?
No. A model can propose a function call. A separate application, service, or tool runner decides whether it can and should execute that function. Confusing these two steps is one of the most important mistakes to avoid when learning how AI agents work.
This is AI Foundations #35, continuing the cumulative series. The examples are simplified learning models and do not claim that any particular service or external system was accessed.
Start with the old model: text in, text out
An ordinary language-model request might look like this:
User: What is 12 plus 17?
Model: 29
The answer lives in the model’s output. For many questions, producing text is enough.
Now imagine a user asks: “What is the current weather in Paris?” A model’s training data is not a live weather sensor. It could guess, decline, or ask an application for live information.
For that third path, the application can provide a tool definition describing a callable function and its parameters.
{
"type": "function",
"function": {
"name": "lookup_weather",
"description": "Get observed weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}
A tool definition is like a menu of capabilities. Its name and description tell the model what it might request. The schema describes the expected shape of an argument. None of this grants the model unrestricted access to the machine.
A tool call is a request to the host application
A possible model response is:
{
"name": "lookup_weather",
"arguments": {"city": "Paris"}
}
That object is not a weather reading, and it is not proof that the lookup already ran. The host application receives the proposed call and decides what to do with it.
A minimal flow is:
user question
|
v
application sends messages + available tool definitions
|
v
model proposes lookup_weather(city="Paris")
|
v
application checks permissions and arguments
|
v
tool executes and returns a result
|
v
application gives result to model
|
v
model explains result to user
The vLLM tool-calling documentation explicitly shows an application declaring callable functions, receiving generated tool-call arguments, and running the corresponding code. The Anthropic tool-use guide similarly distinguishes tools executed by the caller from provider-executed server tools.
Different APIs encode the messages differently. The architectural separation remains the important point.
The loop needs another model turn
A common misunderstanding is that choosing a tool and delivering the tool’s output are one model prediction.
For an ordinary client-executed tool, there are usually at least two model interactions:
- The model sees the user’s question and the list of available tools.
- The model produces a call request rather than a complete answer.
- The application runs a permitted tool, capturing success, failure or denial.
- The application sends the tool result into the conversation.
- The model uses the result to formulate an answer or decide its next step.
If the tool fails, the model should not present its imagined successful result as an observation. If the function returns stale information, the model cannot turn it into real-time truth merely by writing confidently.
This is why tool-using applications need event logs and explicit result handling, not just a polished chat interface.
Three separate meanings of correct
Recall lesson #34: a structured-output decoder can make strings conform to a supported grammar.
Tool calling adds another boundary:
| Question | Example | Who is responsible? |
|---|---|---|
| Is the call syntactically parseable? | JSON has the expected object and keys | Model/runtime and parser |
| Are the arguments valid? | City is a string, not arbitrary unbounded data | Schema validator and application |
| Is the action allowed? | May this user query this tool with these inputs? | Host application and its policy |
| Is the result true or useful? | Weather data are current and sourced correctly | External service, validation and interpretation |
A syntactically correct request can still be semantically wrong, unauthorized, or unsafe to execute.
For example, a file-management function might receive a perfectly valid string identifying a file the user has no right to delete. No JSON Schema can infer the user’s real permissions from the shape of that string.
This is a general principle: valid output is not authorization.
What does auto tool choice mean?
When an application makes tools available, it may allow the model to decide whether to call one. In the OpenAI-compatible interface used by vLLM, the documentation describes these broad choices:
- auto: the model may request a tool or answer without one.
- none: the model should not issue a tool call.
- named function: request a particular tool.
- required: request at least one tool call.
Exact parser support, templating behavior and enforcement details depend on the runtime and model. A tool may be requested under a mandatory setting without the chosen arguments being sensible or a live external action having occurred.
The vLLM tool-calling guide distinguishes parsers and model-specific templates. This matters when engineers test different checkpoints: a model producing ordinary text instead of a structured call may be a formatting or parser problem, not evidence that the physical tool is broken.
For error-specific configuration steps, see the separate vLLM tool-calling troubleshooting guide. This lesson focuses on the architecture rather than server flags.
What actually makes a tool safe?
The model’s output should be treated as a proposal from an untrusted component. The host application can enforce controls the model itself cannot guarantee:
- Allowlist: expose only tools relevant to the task rather than arbitrary commands or unrestricted HTTP requests.
- Parameter validation: enforce types, sizes, value ranges and identifier syntax independently of model-generated JSON.
- Authorization: verify the acting user and the specific resource; do not confuse “the model asked” with “the user permitted.”
- Side-effect boundaries: require stronger approval for sending messages, changing records, buying items or deleting data than for reading public information.
- Result validation: record which tool ran, whether it succeeded, and which result actually came back.
- Loop limits: cap the number of tool calls, execution time and resource consumption to avoid an endless cycle.
The Model Context Protocol tool specification defines interoperable ways to describe tools and exchange requests and results. It does not remove the need for the application to establish and enforce trust boundaries.
An even subtler failure is when retrieved text tries to impersonate instructions to the assistant. Material returned by a search or document-reading tool should remain data, not authority to invoke another tool or disclose protected information.
A concrete example: an agent answering a travel question
Suppose the request is: “Which train runs next from Station A to Station B?”
A reliable tool-using application can:
model requests get_departures(origin, destination)
application validates station codes and permissions
transport API returns a timetable with a timestamp
application passes the response and source to the model
model summarizes the next departure and any uncertainty
If the transport API times out, a correct system reports the missing live result rather than inventing a departure. If a schedule is for yesterday, the caller should account for its timestamp. If a web page contains hidden instructions to send the user’s contacts somewhere else, those instructions are not part of the travel request.
The model remains useful for interpreting the result and responding naturally. But it does not own the authorization or factual provenance of the external lookup.
Why this matters when building agents
A chatbot without external tools mainly produces content. A tool-using system can affect files, websites, payments, infrastructure or communications. That change makes execution policy, resource identity, and verification first-class parts of the architecture.
Tool calling does not magically give a model hands. It lets the model express which action might help. The application supplies the hands, decides when they may move, and reports what actually happened.
Self-check
Try answering these without looking back:
- A model produces valid JSON asking to delete a file. Has any deletion occurred yet?
- A response contains the correct tool name but the wrong resource identifier. Which boundary should catch it?
- A weather API returns a timeout. Is the model allowed to invent a plausible weather report?
- What is the difference between a tool declaration and the permissions of the person using the application?
Suggested answers: (1) No, not without execution. (2) Validation and authorization by the application. (3) No; the missing observation must remain explicit. (4) A declaration describes a possible action; permissions decide whether the action is allowed.
The next step after learning tools is to understand how an agent can plan multiple steps, remember intermediate results and avoid treating its own earlier guesses as evidence.
Primary sources
- vLLM: Tool Calling and the OpenAI-compatible API
- Anthropic: Tool use, caller-executed and server-executed tools
- Model Context Protocol: Tools specification
Continue from AI Foundations #34: Constrained Decoding and revisit AI Foundations #22: Evaluation and Benchmarks for the difference between valid outputs and validated claims.