Tool Calling: The Model Doesn't Act. Your System Does. That Distinction Is Everything.
The model never executes anything — it writes a note and hands it to your code. Every reliability problem worth solving lives on your side of that line, and almost none of it needs a better model.
Ask most people what makes an AI agent “agentic” and you will get something about autonomy — the model deciding things, taking actions, operating on its own. It is a picture that makes the technology sound more mysterious than it is, and it quietly misleads the people who have to build it.
Here is what actually happens. The model does not act. It writes down what it would like to happen — a tool name, some arguments — and hands that note to your application. Your code reads the note, decides whether to honour it, runs the actual work, and passes the result back. The model proposes. Your system decides. Every bit of “autonomous AI” you have seen is that loop, running repeatedly.
This distinction is not pedantry. It relocates the problem. Tool calling is what turns a chatbot into an agent, and it is consistently the most fragile layer in production agent systems — not because models are bad at deciding what to do, but because the system around them is usually built sloppily. Reliability here is a systems-engineering problem wearing an AI costume.
Model proposes, system decides
Sit with the mechanism for a moment, because almost every reliability problem downstream is easier to reason about once it is precise.
You give the model a catalog of available tools — names, descriptions, expected arguments. It generates a structured request: call get_order_status with order_id 4471. That output is text in a defined shape. Nothing has happened yet. Your application parses it, checks whether this caller may invoke this tool with these arguments, runs the real function, and returns the result to the model, which uses it to decide what to do next. In real agents that loop runs many times, each result informing the next proposal.
Two things follow immediately. First, every action an agent takes is an action your code chose to run. There is no autonomy that bypasses your application; if an agent did something it should not have, your system executed it. Second, the interesting engineering is not in the model. It is in the decisions your code makes about proposals — and that is the part usually written in an afternoon and never revisited.
Five layers, five ways to fail
“Add function calling” sounds like one task. It is five, chained, and each has a characteristic failure.
The catalog is what tools exist and how they are described. This is the layer teams treat most casually and it causes the most trouble, because the description is the model’s entire understanding of the tool. A vague one-liner — “gets user data” — produces exactly the confusion you would expect from a colleague handed the same instruction.
Selection is the model choosing which tool to use. Modern models are good at this when the catalog is clear. They struggle when two tools overlap ambiguously, which is almost always a catalog problem wearing a selection costume.
Argument generation is filling in the values — and it is the quietest, nastiest layer. More on this below, because the way it fails is not the way most people expect.
Validation is your code deciding whether this call should actually run. Are the arguments well-formed? Is this caller allowed? Is this action reversible? This layer is skipped constantly, because in the demo the model always proposed something sensible.
Execution and error handling is running the thing and dealing with what comes back. The failure here is silence — a tool errors, returns something unhelpful, and the model gamely carries on building on a result that was never valid.
Because these are chained, the whole thing is only as good as its weakest link. A team with an excellent model, thoughtful prompts, and no validation layer has a flaky agent, and will usually spend weeks blaming the model.
What “reliable” actually means here
Vendors quote impressive numbers, and they are not lying — they are just answering a narrower question than the one you are asking.
On simple, single-step calls, well-formed call rates run above 90%. That is real. But almost nothing in production is single-step. Real workflows chain calls, each depending on the last, and end-to-end success on those lands closer to 80–90% once selection and argument errors compound.
This is worth internalising before you promise anything to a business stakeholder. The useful framing is not “is the agent reliable” but “how many steps does the workflow take, and what happens on the ones that fail?” A five-step workflow with a clean retry path is a far better bet than a twelve-step workflow with an excellent model and no recovery. Shortening chains is a reliability strategy.
There is a subtler finding here that deserves more attention than it gets. Research stress-testing multi-step tool use found that strong models frequently emit syntactically valid calls carrying incorrect or stale argument values across steps — the tool is right, the shape is right, the value is from three steps ago. This is broken state tracking, not bad tool selection, and it is invisible to any check that only validates structure. Tellingly, a mitigation as simple as explicitly restating prior variable values to the agent at each step produced large gains — in one case moving GPT-5 from 62.5% to 81.3% success. The fix was not a better model or a cleverer prompt. It was not making the agent rely on its own recall.
Tool contract drift: the failure with no deploy to blame
This one is worth the whole article, because it is genuinely common, genuinely confusing, and almost never written about.
A backend team renames a field. Perfectly reasonable — customer_id becomes account_id, the API is versioned, tests pass, nothing breaks. The tool definition your agent sees still describes the old shape, because nobody thought of it as something that needed updating. It is documentation, sort of. It lives in a different repo, sort of.
Nothing fails immediately. That is what makes it vicious. Days later the agent starts behaving strangely in ways that do not obviously connect to anything — sometimes it works, because the model guesses the right thing from context; sometimes it does not. You search the deploy history for the day it started and find nothing, because the change that caused it shipped a week earlier and looked completely unrelated.
The mental shift is small and does the work: your agent is an API consumer. You would not rename a field that a paying customer’s integration depends on without a migration path. The agent deserves the same treatment, and it will not complain if it does not get it — it will just quietly get things wrong.
Score the chain, not the answer
One practice separates teams who know how their agent is doing from teams who think they do.
If you evaluate only the final response — does this look right, would a user accept it — you are flying blind, and the reason is uncomfortable. A correct answer and a wrong-but-plausible one look identical in the output. An agent that made three bad calls, got confusing results, and produced a confident guess reads exactly like one that did everything properly. Your eval scores them the same. One of them is a time bomb.
So log the trace and grade it: every proposed call, the arguments, what came back, what the agent did next. Then ask better questions than “was the answer good.” Did it call the right tools in a sensible order? Were the arguments correct, or merely well-formed? Did it recover when something failed, or paper over it? Did it silently skip a step?
This is also what makes debugging possible at all. “The agent sometimes gets it wrong” is not something you can act on. “In 8% of runs it calls the lookup tool with an order ID from an earlier turn” is a bug with an address. The difference between those two sentences is entirely whether you were logging the chain.
Where Macrosol fits
Almost none of what makes tool calling reliable is interesting. It is precise tool definitions, a real validation layer, error handling that surfaces failures instead of swallowing them, logging that makes a bad run reconstructable, and the discipline to treat tool contracts as something owned rather than something that accumulated. It is the work that gets deferred because the demo already works — and it is the difference between an agent that impresses in a meeting and one that can be trusted with a real workflow. That plumbing is what we build at Macrosol Technologies, so teams can focus on what the agent is for rather than why it occasionally does something inexplicable. It sits alongside our AI & Data Science and DevOps & cloud practices.
One bridge worth flagging: everything here is about whether and how the model calls a tool. A separate question — how an agent discovers and reaches tools in the first place — now has a standard answer, and MCP is covered next.
The unglamorous truth
Tool calling is where the agent story stops being about AI and starts being about engineering. The model’s part — deciding what to do — is largely solved and improving on its own. The rest of it is a catalog you maintain, a validation layer you write, errors you handle, and a trace you can read. Nothing about that requires a breakthrough. It requires someone to own it.
Which is oddly good news. The gap between a flaky agent and a dependable one is rarely a better model. It is usually five or six unglamorous decisions that nobody made, because the demo worked and everyone moved on. Make them deliberately and most of the mystery goes away — leaving a system that fails in ways you can name, find, and fix.