Tools: giving the model hands
A tool is any button the model is allowed to press. Click each part of the diagram to see where trust is won and lost.
In 60 seconds
Tools: giving the model hands
A tool is any button the model is allowed to press. Click each part of the diagram to see where trust is won and lost.
| Part | Example | Who writes it |
|---|---|---|
| Name | send_email | Developer |
| Description | "Sends an email. Use when the user asks to contact someone." | Developer — but see Module 15 |
| Arguments | to, subject, body | The model, at run time |
| Result | "Sent, message id 8812" | The outside world — untrusted |
Tap any box in the diagram
You set the goal and, in a well-built system, you approve the risky steps. You are the only part of this picture that can be held responsible. Never design a system that quietly removes you from it.
Tools are ranked by how sorry you will be
| Risk | Tools | Rule of thumb |
|---|---|---|
| Low | Read a public page, do maths, check the time | Let it run freely |
| Medium | Read private files, query a database, search internal docs | Log everything, limit scope |
| High | Send email, post publicly, write to a database, run code | Ask a human first |
| Extreme | Move money, delete data, change permissions, deploy | Ask a human, every single time, with the details shown |
Watch and read more
Lab
A tool registry with real argument validation, and the injection it stops.
The problem
send_email with an address you choose, and confirm your validation blocks it.from dataclasses import dataclass
from typing import Callable
@dataclass
class Tool:
name: str
run: Callable
validate: Callable[[dict], str | None] # returns an error, or None
def refund_validate(args):
if not isinstance(args.get("amount"), (int, float)):
return "amount must be a number"
if not 0 < args["amount"] <= 5000:
return "amount must be between 0 and 5000"
if not args.get("order_id", "").startswith("ORD-"):
return "order_id must look like ORD-xxxx"
return NoneYou are done when
Hard questions
Try to answer before you reveal. If you can answer these, you understood the lesson.
Q1Your validation caps refunds at ₹5,000. An injected agent issues 400 refunds of ₹4,999 in one hour. Was your control useless?Reveal
Q2Why validate arguments in the tool runner rather than asking the model to produce valid arguments?Reveal
{"amount": 999999} while explaining that it is following your rules. Validation in ordinary code cannot be argued with, and it is testable.Questions people ask
Can the model invent a tool that does not exist?
It can try. It will write a call to transfer_funds even if you never built one. A correct tool runner rejects unknown tool names outright. If yours passes them through to some generic executor, you have a serious hole.
What if the model puts nonsense in the arguments?
Then your tool must reject it. Validate every argument like it came from a stranger on the internet — because functionally, it did. Type checks, ranges, allow-lists, maximum amounts.
Is MCP a tool?
MCP (Model Context Protocol) is a standard way to plug whole sets of tools into an agent, like a USB port for capabilities. Very useful, and a real supply-chain risk, because you are now trusting someone else's tool descriptions. Module 15.
Should tool results be shown to the user?
Ideally yes, at least in a log. Hidden tool output is how bad things stay hidden. If a human never sees what came back, nobody notices the poisoned instruction that arrived with it.
Lesson test
5 questions. Get 3 right (60%) to pass and complete this lesson.