A model on its own can only produce text. It can't look up today's price, query a database, or send an email. Tool use, also called function calling, is what turns a text generator into something that can reach out to the world: you describe the functions it's allowed to call, and the model decides when to call one and with what arguments. It's the block that makes an assistant do things, and the foundation the next page (agents) builds a loop out of.
Why this is the job — and where the trust boundary is
Tool use is how an LLM app stops being a chatbot and starts being useful: it can retrieve, calculate, look up a record, file a ticket. But notice the boundary in the definition above, because it's the whole safety story. The model never executes anything itself. It requests, and your code chooses whether and how to run it. That boundary is where you enforce everything: validate the arguments, check permissions, and require a human for anything irreversible. An FDE who understands tool use treats the model's tool request as untrusted input to be checked, not a command to be obeyed.
Before reading on: you give your assistant a send_email tool. What has to sit between the model's request to call it and the email actually going out, and why is "nothing, that's the point of tools" the dangerous answer?Between the request and the send has to sit a guardrail: validate the arguments, and for an irreversible action like email, a human checkpoint. "Nothing" is dangerous because the model is probabilistic. It will eventually request the wrong email to the wrong person, and the tool boundary is the only place to catch it before it becomes a real-world event.
The round trip
- Describe the tools. Each tool gets a name, a clear description (the model reads this to decide when to use it), and an argument schema.
- The model requests a call. Given the conversation, the model returns a structured tool call (the tool name and arguments) instead of a final answer.
- Your code validates and executes. Check the arguments against the schema and your rules, enforce permissions, and for anything irreversible, pause for approval. Then run it.
- Feed the result back. Return the tool's output to the model, which continues, possibly calling another tool or producing the final answer.
A single question can go through this loop several times. When it loops autonomously toward a goal, you've built an agent. That's the next page.
A tool definition, and the gate around it
Here is the send_email tool from the question above, defined in the shape Anthropic's tool-use API expects: a name, a description the model reads, and a JSON Schema for the arguments. (Illustrative.)
{
"name": "send_email",
"description": "Send an email from the support mailbox. Use only when the user has explicitly asked for an email to be sent and has confirmed the recipient. Sending is irreversible.",
"input_schema": {
"type": "object",
"properties": {
"to": { "type": "string", "description": "Recipient address. Must be a contact on this account." },
"subject": { "type": "string", "maxLength": 120 },
"body": { "type": "string", "description": "Plain-text body. No pricing or legal commitments." }
},
"required": ["to", "subject", "body"]
}
}Notice that the description carries operating rules ("only when the user has explicitly asked", "has confirmed the recipient"). That text is the model's only guidance on when to reach for this tool, which is why a tool description is engineered like a prompt (more on this below). The schema is the machine-checkable half, and your code — never the model — wraps every proposed call in a gate:
# the gate every tool call passes through (illustrative)
call = response.tool_use # model proposes: name + args
if not validates(call.args, TOOLS[call.name].input_schema):
return tool_result(error="malformed arguments") # reject; the model can retry
if not permitted(current_user, call.name, call.args):
return tool_result(error="not permitted") # the user's authority, never the model's
if TOOLS[call.name].irreversible:
await_human_approval(call) # checkpoint before send_email fires
result = TOOLS[call.name].run(call.args)
return tool_result(result) # feed back; the model continuesThree checks stand between the model's request and the send, and each answers a distinct failure: schema validation catches malformed arguments, the permission check scopes the call to what this user is allowed to do, and the irreversibility gate holds anything with real-world consequences until a human approves it. Only then does the tool run and the result flow back.
What an interviewer probes
- The tool description is a prompt. The model decides whether to call a tool from its description, so a vague description means the model uses the wrong tool or skips the right one. Descriptions are engineered.
- Arguments are untrusted. The model can request a call with malformed or dangerous arguments (a delete with no filter, an email to the wrong address). Validate them exactly as you would user input, because functionally that's what they are.
- Actions need bounding. Reversible, low-cost tools can run automatically; irreversible or high-blast-radius ones need a human checkpoint. The action guardrails from the guardrails page live right here.
Bad / Good / Great — "how does the assistant look things up or take actions?"
Bad — "the model calls the APIs it needs." It phrases the model as the executor, which is both technically wrong and a security hole. It tells an interviewer you haven't built with tools.
Good — "I define functions with schemas; the model requests a call and my code runs it." Correct mechanics, solid. The gap: nothing about validating the model's requested arguments or bounding what runs without a human.
Great — "I expose tools with clear descriptions and argument schemas; the model returns a structured call, and my code treats that call as untrusted — validate arguments, enforce the user's permissions, run reversible tools automatically, and gate irreversible ones behind a human checkpoint. The tool boundary is where safety lives." You described the round trip and put the guardrail at the boundary.
What to carry into the interview
When a design lets the system act, describe tool use as a trust boundary: the model requests, your code validates and decides, and irreversible actions need a human. Treating the model's tool call as untrusted input your code must validate is what separates a safe acting system from a demo waiting to email the wrong client.
Next: Agents & Orchestration. What happens when you let the model loop through tools toward a goal, and when you shouldn't.NextAgents & Orchestration
