Safety, and what to check
An agent with tools can do things. The question is not whether you trust the model, it is what the worst available action would do.
You have already built the two mechanisms that matter, in earlier lessons. This lesson is about using them on purpose.
| Risk | What you already know |
|---|---|
| It calls a dangerous tool | A before_tool_callback that refuses, lesson 14 |
| It is told to do something by a document it reads | Tools that read identity from state, not from parameters, lesson 10 |
| It loops and burns money | max_llm_calls, lesson 15 |
| It returns the wrong shape to your code | output_schema, lesson 13 |
| It gives a specialist too much reach | Small tool lists per agent, lesson 16 |
The two lines that do the most
First: never take an identity as a tool parameter. A tool that refunds account_id can be asked to refund somebody else's account. A tool that reads the account from state cannot, because the model does not write state.
Second: put a callback in front of anything irreversible. Money, deletion, sending. The callback is code, so no instruction and no clever prompt gets past it.
def guard(tool, args, tool_context):
if tool.name in {"refund", "cancel_account", "send_email"}:
if not tool_context.state.get("approved_by_human"):
return {"status": "refused", "reason": "needs human approval"}That is lesson 14's shape, applied to a list rather than one tool. Four lines, and they remove a whole category of bad afternoon.
What ADK adds on top
The documentation has a safety section covering the platform side: model level safety settings, guardrail patterns, and running tool code in a sandbox rather than in your process. Worth reading before anything goes near production, and it does not change what you build here.
- Script the stand-in to ask for a refund and confirm your callback refuses it.
- List every tool in your project that takes an identity as a parameter. Move them to state.
Little by little, you're building something great.