How it works
Tool use runs on a structured contract between the model and a runtime. You describe each tool: a name, a purpose, and a typed input schema. Given a task, the model emits a structured call naming one tool and its arguments. Your runtime validates and executes that call, captures the result or error, and returns it to the context. The model reads the observation and decides the next step.
The control loop, concretely:
- Expose a set of tools with descriptions and argument schemas.
- The model selects a tool and emits arguments as structured output.
- The runtime validates the arguments and executes the call.
- The result — or the error — returns to the context as an observation.
- The model reasons over that observation, then repeats or stops.
The important detail: the model never touches your environment directly. It only produces a request. Your code decides whether and how to run it. That indirection is the whole game — every tool call is a seam where you can validate, gate, budget, log, or refuse. The model proposes; the runtime disposes.
Why it matters in an agent harness
Tool use is where an agent stops being a chat and starts having consequences. A text-only model is inert. A tool-using model can write files, spend money, send email, and mutate production state. That is precisely why the harness exists at all.
Every meaningful control you build attaches to a tool call: permission checks, approval gates, budgets, rate limits, sandboxing, and audit logs. Because the model chooses tools stochastically, you cannot trust it to self-limit — containment lives in the runtime, not in the prompt. Politely asking a model not to delete things is not a safety control; a runtime that refuses the delete is.
The tool boundary is your enforcement point. Validate arguments before executing. Scope credentials to least privilege per tool, not per agent. Make destructive tools reversible, gated behind an approval, or both. Observability lives here too: a clean trace of tool calls and their observations is the most legible record you will ever get of what the agent actually did — far more honest than its narrated reasoning.
Tool use vs tool surface
These get conflated, and the conflation hides where your leverage is. Tool use is the model's capability to call tools. Tool surface is the specific set of tools you expose to a given agent in a given context. You cannot revoke tool use — it's a property of the model. You fully control the surface.
| Tool use | Tool surface | |
|---|---|---|
| What it is | Capability to call functions | The tools actually exposed |
| Who controls it | The model provider | You, the harness author |
| Design lever | Fixed baseline | Scoped per task, per role, per phase |
| Failure if ignored | Agent is just a chatbot | Over-broad blast radius |
The design decision that follows: don't reason about "can the agent use tools" — reason about which tools are on the surface for this step, and narrow it. A research phase needs read and search, not write and deploy.
The Rifty take
We treat the tool boundary as the primary control plane and design the surface before we design the prompt. We optimize for a small, reversible, well-scoped tool set over a broad capable one, and we accept slower agents in exchange for containment we can reason about. Every tool that can cause irreversible harm gets a gate or a rollback path — no exceptions bought with cleverness in the system prompt.
Common failure modes
- Over-broad surface. Exposing every tool to every agent so the blast radius equals your entire environment. Scope per task instead.
- Trusting the prompt for safety. Enforcement in instructions rather than in the runtime — the model can and will ignore it under pressure.
- Unvalidated arguments. Executing a tool call without schema-checking or sanity-bounding its inputs; injection and malformed calls slip straight through.
- Shared, over-privileged credentials. One fat token behind every tool instead of least-privilege scoping per tool.
- Irreversible tools with no gate. Destructive actions that lack an approval step, a checkpoint, or a rollback.
- Opaque tracing. Logging the model's prose but not the actual call/observation pairs, so you can't reconstruct what happened.
- Silent error swallowing. Returning empty results instead of real errors, leaving the model to hallucinate a recovery.
Frequently asked questions
What's the difference between tool use and function calling?
They name the same mechanism from different angles. "Function calling" describes the model-provider feature — emitting structured calls against a schema. "Tool use" describes the agent behavior — invoking those functions to act on an environment and read results. In practice the terms are interchangeable; the tool is the function you expose.
Where should I enforce limits on what an agent's tools can do?
Enforce at the runtime, never in the prompt. The model chooses tools stochastically and can ignore instructions, so validation, permission checks, budgets, and rollback must sit in the code that executes each call. Treat the tool boundary as your control plane and scope credentials to least privilege per tool.
Does giving an agent more tools make it more capable?
Not reliably. A larger tool surface raises blast radius, dilutes tool selection, and lengthens context, which can degrade accuracy. Capability comes from the right small set of well-described, well-scoped tools for the task at hand, plus a runtime that keeps their effects reversible and observable.
How do I make tool use safe for destructive actions?
Gate or reverse them. Put irreversible tools — deletes, deploys, payments — behind an approval step, a checkpoint you can roll back to, or both. Scope the credential to just that action, validate arguments before executing, and log the full call and result so any effect is auditable and recoverable.
Why does tool use matter for observability?
Tool calls are the most honest record of agent behavior. The model's narrated reasoning can drift from what it actually did, but the sequence of calls, arguments, and observations shows real actions and effects. Logging clean call/observation pairs gives you a legible trajectory to debug, evaluate, and audit against.