Connecting a model to a database, email, terminal, and external services changes the nature of the system. It stops merely producing text and begins performing operations with consequences.
The main challenge is not teaching the agent to call a function. It is ensuring that it chooses the right function, supplies valid arguments, stays within the authorized scope, and has a clear way to recover or stop.
Small tools are safer
A generic tool such as execute_command offers flexibility, but transfers almost the entire security policy into the prompt. A specific tool carries intent in its contract:
type PublishPostInput = {
postId: string;
expectedRevision: number;
};
async function publishPost(input: PublishPostInput) {
// validates authorization, revision, and state before publishing
}The agent does not need to invent the publishing procedure. It chooses an explicit operation, while the server remains responsible for authentication, authorization, validation, and concurrency.
A good tool:
- performs an action users can recognize;
- receives only the necessary data;
- validates rules outside the model;
- returns a structured result;
- can be tested without calling the model.
Permission should match impact
Reading a public list, saving a draft, and deleting production data do not belong to the same risk class.
Organize operations by impact and define proportional controls:
| Impact | Example | Control |
|---|---|---|
| Low | search documentation | direct execution |
| Medium | create a draft | limited scope and logging |
| High | publish or send a message | human confirmation |
| Critical | delete data or move money | strong authorization and deterministic policy |
The model may explain and prepare an action. The final decision for irreversible operations should remain in a layer that does not depend only on probabilistic interpretation.
Context needs provenance
More context does not automatically mean better context. Mixing system instructions, retrieved data, and third-party text increases the risk that the agent will treat content as an instruction.
Record the origin of each block and keep these categories separate:
- policies the agent cannot change;
- direct user instructions;
- data retrieved for reference;
- tool results;
- memory derived from previous interactions.
When external content enters the process, treat it as data. A webpage, email, or document does not gain authority to redefine the agent’s rules.
Every action must leave a trail
Debugging an agent requires more than storing its final answer. You need to know the sequence of decisions:
- model and version used;
- tools offered;
- selected tool and arguments;
- returned result;
- permissions evaluated;
- confirmations requested;
- duration and cost of each step.
Do not record secrets or sensitive content without a reason. The goal is to reconstruct behavior safely, compare versions, and identify where a decision went off course.
Controlled failure is part of the product
A call can time out, a result can be ambiguous, and a dependency can become unavailable. The agent needs to know when to retry, when to request information, and when to stop.
Define limits for attempts, time, and cost. Use idempotency keys for repeatable operations. Validate the real state before reporting success. Never turn a tool failure into an invented claim.
Useful agents do not need unlimited freedom. They need a well-designed space for action, where capability and responsibility grow together.
