AI Engineer Track · Prompt Engineering
Function / Tool Calling
Function / Tool Calling
Function, or tool, calling is the mechanism that lets a model respond with a structured request to run one of your actual functions, look up this order, send this email, with specific arguments filled in, instead of just replying with text. It is the single feature that turns a model from something that only talks into something that can take real action inside your systems.
Why this matters
You describe each action in plain language plus a schema of its arguments; the model decides when an action is needed and which one, and hands back a request your code still has to validate and execute. It chooses and describes, it does not act on its own, and clear, narrowly scoped descriptions are what make a system reliable instead of one that keeps picking the wrong action.
What tool calling is
Tool calling is the API mechanism that lets a model respond with a structured request to invoke one of your functions, a name plus a set of JSON arguments, instead of plain free text. Each tool is registered with a name, a plain-language description of when it should be used, and a JSON schema describing its arguments; the model decides whether a tool is needed for a given request and, if so, returns a structured call rather than a prose answer, and your code is responsible for executing that call and returning the result back to the model.
The critical boundary here is that the model only ever emits the request. It never executes anything itself. Your code runs the actual function and hands the result back into the conversation, and that boundary, where the model decides and your code executes, is exactly where validation and safety have to live.
Tool calling is the primitive that turns a chatbot into something that can act on your actual systems, with the decide-versus-execute boundary as the key seam to protect.
Designing tool schemas
Tool design is where reliability is actually won or lost, more than any amount of prompting around the tools afterward. The description should be written for the model, not for a database administrator: it should say when to use the tool, what it returns, and what side effects calling it has. The schema itself should be as constrained as the real argument space allows, using specific types, enums for closed sets of values, and a required-fields list, so the model is structurally unable to emit malformed arguments. And tools should stay granular: one focused tool that does one thing well tends to outperform a single tool that tries to do everything, because a narrow, well-described tool is much easier for the model to select correctly.
The most common failure modes trace directly back to these three rules. A vague description causes the wrong tool to get selected for a request it was not actually meant for. A missing required field in the schema lets arguments come back empty when they should not be. And the absence of an enum constraint where one was available is what allows a hallucinated value through that a tighter schema would have blocked outright.
The schema is the contract between your code and the model. Good descriptions plus tight schemas are most of what makes tool calling reliable in practice.
Parallel tool calls and error handling
Two production realities show up once tool calling moves past a toy example. The first is parallel tool calls: a model can emit several tool calls within a single response, for instance searching files and checking the weather at the same time, and your code has to execute all of them and return every result together. If one tool's arguments genuinely depend on another tool's result, parallel calls need to be disabled for that pair specifically, so the model is not allowed to batch them before it actually has the information it needs.
The second is error handling: a tool will fail eventually, whether from an API outage, invalid input, or a timeout, and the exception should never be allowed to crash the surrounding loop. Catching the failure and feeding it back as the tool's result, rather than letting it propagate, is what lets the model see that something went wrong and adjust or retry instead of the whole request simply dying. The most common bug in a naive implementation is exactly this: a single tool exception taking down an entire request that could otherwise have recovered.
Validate every argument before executing, execute all parallel calls fully, and treat tool errors as data fed back into the loop rather than exceptions that are allowed to end it.
Worked example
A support agent given a search_orders tool and a send_refund tool, asked to refund a specific order, should call search_orders first to confirm the order exists and get its amount, then call send_refund with that confirmed amount, rather than calling send_refund directly with a guessed amount. Designing the two tools' descriptions to make that sequencing obvious, search_orders described as returning the information refunds depend on, is what makes the model choose the safe order on its own rather than needing to be told the sequence explicitly every time.
Practice
Define three to five tools with real schemas, including at least one enum argument and one nested object, and drive a model to select and call the right one across twenty varied requests, tightening descriptions until selection is reliably correct. Then write the execution loop: parse the call, validate every argument, run the tool, and return the result, with a guard that refuses to execute before validation passes.
Interview checks
- What exactly is the model allowed to do versus what has to stay in your code?
- Why does a vague tool description cause wrong-tool selection even when the schema itself is correct?
- What should happen when a tool call fails partway through a multi-tool request?
Common failure modes
- A tool call missing a required argument because the schema did not actually mark it as required.
- The wrong tool being selected because its description did not clearly say when it should and should not be used.
- A hallucinated argument value passed through because no enum constrained the field to a known set of values.
- Parallel tool calls executed when one tool's arguments genuinely depended on another tool's result, producing a call based on information that did not exist yet.
Resources
- OpenAI Function Calling guide — The reference for the tool-calling protocol and practical guidance on designing tool schemas.
- Anthropic Tool Use overview — Anthropic's model of tool_use and tool_result content blocks, including parallel tool use.
- Anthropic: Building Effective Agents — Places tool calling inside the larger agent-design picture, including the workflow-versus-agent framing worth reading alongside this.
Expert signals
Recognizing that native tool calling is fundamentally schema-constrained generation, the model's output restricted to a grammar of valid tool-call objects, is what explains why it is strictly more reliable than emulating tools through plain prompting and regexing the result. The deeper tradeoff worth internalizing is that good tool design pushes clarity into the description and constraint into the schema: the description tells the model when to use a tool and what it does, the schema tells it exactly what a valid call looks like, and the model is only ever deciding which tool to use, never inventing an argument that was not declared. It is also worth knowing that tool selection degrades as the number of available tools grows, so a large tool set needs routing or retrieval over tools rather than one flat list, and that providers differ in their tool-calling protocol and change it over time, which is a good reason to isolate that protocol behind a thin wrapper rather than let it leak through your whole codebase.
Confidence
high
Pathweys