A perfect memory system can't save an agent that doesn't know when to reach for the tool sitting right in front of it. Prompt engineering for an agent differs from prompting a chatbot in one key way: the system prompt is re-read fresh on ev...
A perfect memory system can't save an agent that doesn't know when to reach for the tool sitting right in front of it. Prompt engineering for an agent differs from prompting a chatbot in one key way: the system prompt is re-read fresh on every single step of a loop, not judged once.
This post continues my series on building agents. The previous one covered short-term vs long-term memory.
Why vagueness compounds in an agent prompt
A vague instruction in a one-shot prompt costs one bad answer. The same vagueness in an agent's system prompt costs one bad decision per step, and across a long conversation that adds up instead of averaging out — the same ambiguous text, reread with the same risk, every single time.
The five sections
Role — one or two sentences, not a biography.
Tools, and exactly when to use each — "use this whenever X," not just a capability list.
Boundaries — what it must never do: invent data, act irreversibly without confirmation, go outside its given tools.
Handling uncertainty — ask, guess, or escalate, picked explicitly.
What "done" looks like — an explicit stopping condition.
Tool descriptions are prompts too
Going back through this series' actual code: add_expense has "Use it whenever the user says they spent money" — real trigger phrase, doing real work. get_total, from the same file, has no trigger phrase at all, and gets away with it only because nothing else in that toolset sounds like "total." The rule isn't "always add a trigger" as a blanket mandate — it's that the less distinguishable a tool's name is from its neighbors, the more the description has to do.
A structured prompt, and a way to check it
// agent/prompt-template.ts
const SYSTEM_PROMPT = `
You are an expense-tracking assistant for a single user.
## Role
Record expenses the user mentions and answer questions about what they've spent. You do not give financial advice.
## Tools and when to use them
- add_expense: use this whenever the user states they spent money on something.
- get_total: use this whenever the user asks for a total, a sum, or how much they've spent overall — not for a single expense or an average.
- save_note: use this whenever the user states a lasting preference or constraint, not a one-off detail about today.
## Boundaries
- Never invent an expense, a total, or a saved note the tools did not actually return.
- Never delete or change a past expense unless the user explicitly asks to.
## When you're not sure
If a message could mean more than one thing (for example, an amount with no stated purpose), ask one short clarifying question instead of guessing which tool to call.
## When you're done
Once every expense or note the user mentioned has been recorded and any question has been answered, reply in plain text with no further tool calls.
`.trim();
function hasTriggerPhrase(description: string): boolean {
return /\buse (this|it) whenever\b/i.test(description);
}
const toolDescriptions: Record = {
add_expense: 'Record one expense. Use it whenever the user says they spent money.',
get_total_before: 'Return the exact total of all recorded expenses in BDT.',
get_total_after:
"Return the exact sum of every expense recorded so far, in BDT. Use this whenever the user asks for a total, a sum, or how much they've spent overall — not for a single expense or an average.",
};
for (const [name, description] of Object.entries(toolDescriptions)) {
console.log(name, '->', hasTriggerPhrase(description) ? 'has trigger phrase' : 'MISSING trigger phrase');
}
console.log('\n--- system prompt preview ---');
console.log(SYSTEM_PROMPT);
Running the checker against the real get_total description and its rewrite shows the gap directly: the original fails, the rewrite passes, with no need to guess how a real model would respond to either one.
Common mistakes
Treating the system prompt as one block of advice instead of distinct sections.
Writing tool descriptions in isolation instead of reviewing them together.
No explicit stopping condition.
Padding the prompt with generic advice that doesn't change behavior.
Read the full version
I write each post in English and Bangla. The full version is on my blog: How to Write a Good Prompt for an AI Agent
Has a vague tool description ever made your agent guess wrong?