This is the fourth post in our Amazon Bedrock series, building on getting started, Knowledge Bases, and Agents.
A system prompt instructing a model to avoid certain topics, refuse certain requests, or stay within a defined scope is a request to the model, evaluated by the model, using the same probabilistic process that generates every other response — which means it can be worked around, misunderstood, or simply fail under an unusual or adversarial input, the same category of concern we raised about trusting an agent's judgment alone for consequential actions earlier in this blog. Bedrock Guardrails apply policy enforcement as a separate, independent layer — checking both what goes in and what comes out, regardless of what the model itself decided.
Creating a Guardrail
aws bedrock create-guardrail \
--name "novuspark-support-guardrail" \
--blocked-input-messaging "I can't help with that request." \
--blocked-outputs-messaging "I'm not able to provide that information." \
--content-policy-config '{
"filtersConfig": [
{"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "VIOLENCE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "PROMPT_ATTACK", "inputStrength": "HIGH", "outputStrength": "NONE"}
]
}' \
--topic-policy-config '{
"topicsConfig": [
{
"name": "CompetitorDiscussion",
"definition": "Any discussion comparing NovuSpark to named competitor training companies",
"type": "DENY"
}
]
}'Two distinct filter types are doing different jobs here. Content filters (HATE, VIOLENCE, and others, including PROMPT_ATTACK specifically — detecting attempts to manipulate the model into ignoring its own instructions) are pre-built categories AWS maintains and continually improves. Topic policies are genuinely custom, defined by you — here, blocking any discussion of named competitors, a business rule specific to this application, not a general content-safety concern at all.
Guardrails apply independent of what the model decided
response = client.invoke_model(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
body=json.dumps({...}),
guardrailIdentifier="novuspark-support-guardrail",
guardrailVersion="1",
)
result = json.loads(response["body"].read())
if result.get("amazon-bedrock-guardrailAction") == "INTERVENED":
print("Guardrail blocked this response")
else:
print(result["content"][0]["text"])This is the structural point worth being precise about: the Guardrail check happens as a separate evaluation step, applied to both the input before it ever reaches the model and the output before it's returned — regardless of whether the model itself would have refused the request on its own. A system prompt asking the model to avoid a topic is a request the model interprets and can misjudge; a Guardrail configured to DENY that same topic is enforced independent of the model's own reasoning about the specific input in front of it.
Sensitive information filtering: PII detection and redaction
{
"sensitiveInformationPolicyConfig": {
"piiEntitiesConfig": [
{"type": "EMAIL", "action": "ANONYMIZE"},
{"type": "PHONE", "action": "ANONYMIZE"},
{"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"}
]
}
}ANONYMIZE replaces detected PII with a placeholder (an email address becomes {EMAIL} in the actual response) rather than passing it through unmodified; BLOCK refuses to process the request entirely when specific, genuinely sensitive categories are detected — a credit card number appearing in either a user's input or a model's generated output being the clearest example of something that should never pass through unexamined, in either direction.
Guardrails apply to more than just direct model calls
response = client.invoke_agent(
agentId="AGENT123",
agentAliasId="ALIAS456",
sessionId="session-789",
inputText=user_message,
# Guardrails configured on the agent itself apply automatically to every turn
)A Guardrail attached to a Bedrock Agent (from the previous post in this series) applies automatically across every turn of a multi-step, potentially tool-calling conversation — not something you have to re-check manually after every individual model call within a longer agent interaction. This matters specifically because an agent's actual path through a conversation, including which tools it calls and in what order, isn't fully predictable in advance — the same unpredictability flagged for LangChain agents in our earlier series — and a Guardrail applied at the agent level provides a consistent enforcement boundary regardless of that path.
Guardrails are a layer, not a complete solution on their own
Guardrails catch a genuinely important, well-defined category of risk — harmful content categories, defined-topic violations, PII exposure, direct prompt-injection attempts. They do not replace careful system prompt design, the IAM-level least-privilege scoping covered for agents and tools in the previous post, or human review for genuinely consequential actions, covered as human-in-the-loop patterns in our LangGraph series. Responsible AI in a real production system is several distinct layers working together — Guardrails are one specific, valuable layer, not a substitute for the others.
What to actually remember from this post
- A Guardrail is a separate, independent enforcement layer — applied regardless of what the model itself decided, unlike a system prompt's request-based instruction.
- Content filters are pre-built AWS-maintained categories; topic policies are genuinely custom, defined for your own specific business rules.
- PII filtering can anonymize or outright block sensitive data categories, in both directions — user input and model output.
- Guardrails attached to an Agent apply automatically across a whole multi-turn, multi-tool conversation — and they're one layer among several, not a complete responsible-AI solution on their own.
Next in the series: Choosing the Right Foundation Model on Amazon Bedrock, the final post — covering how to actually decide between the many models Bedrock provides access to.
