Agent Instructions Are Not a System Prompt
The instruction field is one variable interpolated into Bedrock's orchestration template, which is why prompt techniques that work on a raw model quietly fail on an agent.
Every Bedrock agent has an instruction: a natural-language description of what the agent is and how it should behave. It looks like a system prompt and it is written like one, but it is not one, and treating it as one is the most common reason an agent misbehaves in ways its author cannot explain.
What actually happens to your instruction
Bedrock owns the prompt. For each stage of the loop it holds a base template, and your instruction is substituted into the orchestration template at the $instruction$ placeholder. Around it, the template supplies the tool-use format the model must emit, the rendered action group and knowledge base descriptions, the conversation history, and the prompt session attributes. So your text is a paragraph inside a much larger document that you did not write.
Three consequences follow. First, you cannot dictate the output format of a tool call from the instruction; the template already specifies it, and instructions that fight it produce parse failures. Second, your instruction does not describe the tools — the action group and operation descriptions do. Writing "use the get_claim_status tool when the user gives a reference" in the instruction is weaker than putting that trigger condition in the operation's own description, because the description sits right next to the schema the model is reading. Third, the instruction is versioned with the agent. Changing it edits the DRAFT and does nothing to a published alias until you cut a new version.
Writing one that works
The field has a minimum length — around forty characters — precisely because one-liners produce vague agents. Aim for role, scope, boundaries and escalation:
- Role and audience: who the agent is and who it is talking to.
- What it may assert without a tool: the single most effective anti-hallucination line is a rule that figures, dates and statuses must come from a tool result.
- What is out of scope, and what to say instead.
- When to ask rather than assume — this pairs with the
AMAZON.UserInputaction group; without that group enabled, an instruction telling the agent to ask questions has nothing to act on.
Keep it behavioural. Do not paste your entire policy manual in: that is what a knowledge base is for, and text in the instruction is re-sent on every single model call in the loop, so it is paid for repeatedly.
When the instruction is not enough
If you truly need to change the scaffolding — a different reasoning style, a stricter pre-processing filter, custom inference parameters per stage, or your own parser for the model's output — you override the templates themselves through promptOverrideConfiguration. Each entry names a promptType (PRE_PROCESSING, ORCHESTRATION, POST_PROCESSING, KNOWLEDGE_BASE_RESPONSE_GENERATION, MEMORY_SUMMARIZATION), can be enabled or disabled, and carries a basePromptTemplate plus an inferenceConfiguration. Start from the console's copy of the default template rather than writing one from scratch, because the template must keep the placeholders and the output format the runtime parses. Overriding orchestration is powerful and it is also how you inherit the maintenance burden of a prompt that AWS would otherwise keep improving.
Example
INSTRUCTION = """
You are the claims assistant for a UK motor insurer, speaking to policyholders.
Rules:
- Only state a claim status, settlement figure, excess or date that you have
retrieved from a tool in this conversation. Never estimate one.
- If the policyholder has not given a claim reference, ask for it. Do not guess.
- Cancelling a claim is irreversible: summarise the consequences and get an
explicit yes before calling the cancellation action.
- Complaints, legal threats and injury claims are out of scope. Say you are
transferring them and call the escalation action.
- Write in plain British English, short sentences, no insurance jargon
unless the policyholder used it first.
"""
cp.update_agent(
agentId=agent_id,
agentName="claims-assistant",
agentResourceRoleArn=ROLE_ARN,
foundationModel="anthropic.claude-3-5-sonnet-20241022-v2:0",
instruction=INSTRUCTION,
promptOverrideConfiguration={
"promptConfigurations": [
{
# Disabling a step keeps the default template, so creation mode
# stays DEFAULT. OVERRIDDEN requires a basePromptTemplate.
"promptType": "POST_PROCESSING",
"promptState": "DISABLED", # skip the extra rewrite pass
"promptCreationMode": "DEFAULT",
"parserMode": "DEFAULT",
},
{
"promptType": "ORCHESTRATION",
"promptState": "ENABLED",
"promptCreationMode": "OVERRIDDEN",
"parserMode": "DEFAULT",
"basePromptTemplate": open("orchestration_template.txt").read(),
"inferenceConfiguration": {"temperature": 0.0, "topP": 1.0, "maximumLength": 2048},
},
]
},
)
cp.prepare_agent(agentId=agent_id) # instruction changes are inert until you prepareWhen to use it
- Tightening an agent that quotes plausible-sounding prices it never retrieved, by forbidding unsourced figures in the instruction.
- Disabling the post-processing template on a latency-sensitive assistant where the extra rewrite pass adds no value.
- Overriding the orchestration template to pin temperature to zero so tool selection stops varying between identical runs.
Discussion