When an agent misbehaves, the usual reaction is to rewrite the system prompt. Most of the time the problem is the tools: what they're called, what they accept, and what they say back when something goes wrong.
The model only sees names and descriptions
An agent picks a tool from its name, its description and its argument schema. Nothing else. Give it search_customers and find_customer with similar descriptions and every lookup becomes a coin flip.
Write descriptions the way you'd brief a new teammate: what the tool does, when to use it, when not to, and what a good argument looks like. "Searches customers" is a label. "Find customers by name, email or phone. Use this before any action that needs a customer_id. Partial names work." is an instruction.
Fewer, higher-level tools
If answering "what did this customer order last week" takes list_orders, then get_order for each one, then list_order_items, the agent makes a dozen calls. Each call is a round trip, more tokens in context, and one more chance to go wrong. One get_recent_orders(customer_id, days) tool does the same job in one step.
Don't take this too far. A tool that both looks things up and changes them is hard to describe and hard to approve. Group by task, keep reads and writes apart.
Return what the model needs, not the raw API
- Drop fields the agent will never use. A forty-field JSON record costs tokens on every call and buries the three fields that matter.
- Prefer names over opaque IDs where you can, and include the ID too when a later tool needs it.
- Cap list sizes and say so: "Showing 20 of 312. Narrow the search or call again with page=2."
Errors are instructions
An agent reads a tool's error and decides what to do next. A bare error gives it nothing to work with, so it retries the same call or invents an answer. A good error says what went wrong and what to try instead.
# unhelpful
{"error": "not found"}
# helpful
{"error": "No customer with email ravi@exmple.com. The domain may be misspelled. Try search_customers with the name or phone number."}
Make writes safe to retry
Agents retry. Networks time out after a request has already landed. Any tool that writes should take an idempotency key, so the same call twice does the work once. Validate arguments inside the tool instead of trusting the model to send sensible values, and for risky actions offer a dry_run flag that shows what would change without changing it.
Put the limits outside the model
A model asked to stop after ten steps will sometimes take thirty. Enforce a maximum number of steps, a timeout per tool and a token or cost budget in the code that runs the loop. When a limit is hit, stop and return what was done so far with a plain explanation. A partial answer with a reason beats an agent that loops until something else kills it.
Before you touch the prompt again, read a few transcripts of the agent failing. Usually you'll see it misread a tool, drown in a tool's output, or retry an error it couldn't understand. Those are tool fixes.
Originally published at anukumar.site.
Top comments (0)