If your agent keeps doing the wrong thing, the bug is almost never in the prompt. It is in the tools.
What a tool actually is
To an LLM, a tool is a JSON schema with a name and a description. That is it. The model does not run your code, does not see your types, does not understand your domain. It sees:
{
"name": "create_invoice",
"description": "Create a new invoice for a customer",
"parameters": { "customer_id": "string", "amount_cents": "number" }
}
Every choice in that schema is a UX decision. You are designing an API for a reader who has never seen your codebase and never will.
The five rules I keep coming back to
1. One tool, one verb
manage_user is a bad tool. create_user, update_user, delete_user are three good tools. The model picks tools by name first, description second — make the name unambiguous.
2. Use enums, not free text
If a field has 4 valid values, declare them. status: "pending" | "paid" | "void" is dramatically more reliable than status: string. The model will hallucinate "PAID", "Paid ✅", or "completed" otherwise.
3. Describe units in the field name
amount_cents, timeout_seconds, distance_meters. Never just amount or timeout. The model has no way to ask.
4. Return errors as data, not exceptions
If a tool fails, return { "ok": false, "error": "customer_not_found", "hint": "list_customers may help" }. The agent can read that, course-correct, and continue. A raw stack trace just ends the run.
5. Make idempotency obvious
If a tool is safe to retry, say so in the description. If it is not, say that even louder. The single most common production incident I see is an agent retrying a "send email" tool three times because the first call timed out.
Anti-patterns
- The Swiss Army Tool. One
execute(action, params)tool that does everything. The model cannot reason about it. - The Overloaded Param.
query: stringthat accepts SQL, natural language, or a JSON filter depending on the day. Pick one. - The Silent Side Effect. A "read" tool that secretly logs the user out. If you would not want a junior engineer to call it by accident, do not expose it.
The mental model
Imagine you are writing the tool docs for a brand-new hire who joins on Monday and has to be productive by Tuesday afternoon. They are smart, they read carefully, and they will take everything you wrote literally. That is your model.
Design the tools that hire would not screw up, and your agent will mostly stop screwing up too.