Connect models to APIs through typed tool calls and controlled execution.
Function calling does not let a model magically access systems. It lets the model request a named action that code may accept or reject.
A tool boundary says what the model may ask code to do.
Why this matters: It prevents confusing generated text with authorized execution.
A tool call is a structured request: a name plus arguments. The model can propose lookup_order(order_id="A123"), but it does not hold credentials or execute the database query itself.
Problem anchor: a support bot needs order status and refund actions. Looking up an order is mostly read-only; issuing a refund changes money and needs stronger authorization.
lookup_order or issue_refund? Why?The support assistant receives: “Where is order A123, and refund it if late.” It should call lookup_order first. It should not call issue_refund until policy and user confirmation are checked.
The model chooses tools from declarations. Clear names, descriptions, and input schemas reduce wrong-tool and missing-argument failures.
Tool schemas define callable names and typed arguments.
Why this matters: Good schemas reduce missing arguments and wrong-tool calls.
Tool declarations include a name, description, and input schema. The model reads those declarations as part of context, so vague names and overlapping descriptions make selection harder.
A good tool schema says what the tool does, when to use it, what arguments are required, and what the tool does not do.
Tool name: lookup_order. Description: “Fetch shipping and payment status for one order ID. Does not issue refunds.” Input schema: {order_id: string} required. Output: status, delivery date, refundable flag.
That “does not issue refunds” sentence matters. It tells the model not to treat a lookup tool as an action tool.
Runtime code validates arguments, checks authorization, executes the function, handles errors, and records the action.
The runtime is the owner of real-world action.
Why this matters: It keeps credentials, side effects, and retries out of model control.
The application should treat tool calls as untrusted input. It validates the tool name against an allowed registry, checks arguments against schema, enforces policy, then executes.
This division is what makes tool use safe enough to ship: the model can reason about actions, but code owns permissions and side effects.
def lookup_order(order_id): return {"order_id": order_id, "status": "late", "refundable": True} tools = {"lookup_order": lookup_order} call = {"name": "lookup_order", "arguments": {"order_id": "A123"}} def execute(call): if call["name"] not in tools: raise ValueError("unknown tool") if "order_id" not in call["arguments"]: raise ValueError("missing order_id") return tools[call["name"]](**call["arguments"]) result = execute(call) print(result["status"]) print(result["refundable"])
input datadecision ruleprint(...)Run this as a tiny model of the mechanism. The point is to predict behavior before trusting the output.
It prints:
late
True
The runtime accepts a known tool with the required argument and returns structured data.
When an AI writes tool-calling code, check the dangerous boundary.
Tool results should be tied to the original call and treated as untrusted context. The model uses them to continue or answer.
Results become new evidence for the next model turn.
Why this matters: It explains multi-step tool workflows and stale-result risks.
After execution, the application sends the tool result back to the model, usually tied to the tool-call ID. The model can then decide whether to answer, call another tool, or ask for approval.
Tool output is not privileged instruction. A web page, database note, or document can contain malicious text. Label it as data and keep higher-priority instructions separate.
Turn 1: model calls lookup_order(A123). Runtime returns status late, refundable true. Turn 2: model wants issue_refund, but runtime requires confirmation and policy check. The assistant asks the user to confirm instead of silently refunding.
The important handoff is that the lookup result becomes evidence, not permission.
Tool systems fail through wrong tools, malformed arguments, unsafe side effects, stale results, and prompt injection in tool output.
Tool failures are product and security failures, not just model errors.
Why this matters: It teaches the checks required before shipping tool use.
Function calling failures often look like normal agent behavior until a real system is changed. The model may choose the wrong tool, omit arguments, retry blindly, or trust malicious tool output.
From memory, trace a tool call: declaration, model-selected name and arguments, validation, authorization, execution, tool result, and final answer. Then name two places code must not delegate trust to the model.
Design one safe lookup_order and one risky issue_refund tool. Write their schemas, validation rules, authorization checks, and failure behavior. Next rung: secure tool-using agents and MCP.
A language model receives a user message and decides to call a send_email tool. Which statement best describes what happens at that moment?
The model only outputs a call proposal — all real-world execution happens in your code, which is why authorization and validation must live there.
You are writing a tool schema for a search_orders function. Which of the following description practices will most help the model call the tool correctly?
A clear, purposeful description — covering the tool's action, trigger condition, and argument semantics — is what guides the model to call the right tool with the right inputs.
Your executor receives a tool call from the model for a tool named delete_record. That tool is NOT in your registered tool list. What should your executor do, and why?
Rejecting unknown tools is a core safety rule: the executor is the enforcement boundary, so any tool not explicitly registered must be refused.
After your code runs a tool and gets a result back, how should that result be returned to the model?
Tool results must be returned as properly linked tool-result messages; dropping or misrouting them breaks the model's ability to reason about what actually happened.
A model is in a tool-call loop and the tool keeps returning errors, but the model continues calling it repeatedly. Which safeguard directly prevents this from running indefinitely?
A hard iteration cap in your loop is the direct safeguard against infinite retry cycles — schema improvements and better descriptions help quality, but only a turn limit stops runaway loops.