A model in production will eventually produce a sentence you cannot defend. A made-up policy. A competitor named in a recommendation. A caller’s phone number read back in the clear. The model has no idea it did anything wrong, because to the model it was all just the next likely token.
The agent you built in Part 13 can now take actions in the world, which is exactly when you want a fence around what it says and does. This part is that fence. I define every policy the first time it appears, show both ways to call the service, work the real cost, and spend the back half on where it trips people, because the failures here are quiet ones.
What Guardrails checks, and where it sits
A guardrail is a set of rules Bedrock applies to text before it reaches the model and again before the model’s reply reaches the user. It sits in the request path on both sides. On the way in, it reads the user prompt and can block it, so a prompt that tries to jailbreak the model or asks for something off-limits never gets generated against. On the way out, it reads the model’s response and can block or mask it, so an answer that names a banned topic or leaks a Social Security number never lands in front of the user. Same rules, two checkpoints.
The important design point is that a guardrail is its own resource, not a setting on a model. You create it once, give it a version, and then attach it to as many model calls as you like. That separation is what lets one moderation policy cover every application in an account, and it is why the same guardrail can screen a Bedrock model on one call and a model running somewhere else on the next. The model does the reasoning. The guardrail decides what is allowed to pass in either direction.
The six policies you turn on
A guardrail is built from six policy types, and each one is optional and configured on its own. You enable the ones your application needs and leave the rest off. Understanding what each catches, and what it does not, is the whole job of setting one up well.
| Policy | What it catches | You configure |
|---|---|---|
| Content filters | Hate, Insults, Sexual, Violence, Misconduct, Prompt Attack | A strength per category, on input and output |
| Denied topics | Subjects you declare off-limits for this app | A short name and a plain description each |
| Word filters | Specific words, profanity, custom block lists | Your word list plus the managed profanity set |
| Sensitive information | PII such as names, emails, card and account numbers | Block or mask, per PII type or regex |
| Contextual grounding | Answers not grounded in a supplied source, or off topic | A grounding and a relevance threshold |
| Automated Reasoning | Claims that break a set of encoded logical rules | A policy built from your source documents |
Content filters and denied topics are the two most teams start with. Sensitive information is free and worth enabling almost everywhere.
A few of these deserve a plain-language definition. A denied topic is a subject you describe in a sentence or two, such as investment advice for a bank’s support bot, and the guardrail keeps the conversation off it without you listing every phrasing. Sensitive information filters detect personally identifiable information, the fields that identify a real person, and either block the response or mask the value so an email or card number comes back as a placeholder. Contextual grounding is the hallucination check: give it the source passages and the user question, and it scores whether the answer actually followed from the source, so a confident invention gets caught. Automated Reasoning is the newest and most specialized, turning a body of policy documents into formal logical rules and checking model claims against them, which is how you catch an answer that is fluent but logically wrong.
Classic tier or Standard tier?
Content filters and denied topics come in two tiers, and the choice changes how well they hold up against real inputs. The Classic tier is the original detection. The Standard tier, added in mid 2025, detects the same categories but with better resistance to the tricks that get past a naive filter: typos, spacing, and rephrasings, along with support for up to 60 languages and detection of harmful content hidden inside code, such as comments and string literals. The price is the same for both tiers, so the tradeoff is not money.
The tradeoff is the routing. Standard tier requires you to opt in to cross-region inference, which means a request can be served from a model in another Region inside the same geography to find capacity. For a lot of workloads that is fine and already how they run. For a workload with strict data residency rules, it is a real constraint you have to clear before you turn Standard on. My default is Standard for its stronger detection and its language coverage, and I only fall back to Classic when residency rules forbid the cross-region hop. Decide this deliberately, because it touches where your data is processed. [VERIFY current tier language count and cross-region requirement]
Two ways to call a guardrail
The first way is inline. Pass a guardrailIdentifier and a guardrailVersion on your Converse or InvokeModel call, and Bedrock runs the guardrail on the input and the output as part of the same request. This is the path you want when the model is a Bedrock model and you are already calling it, because there is one call and the guardrail is part of it. The response tells you whether the guardrail intervened, so your code can branch on a block.
resp = bedrock.converse(
modelId='amazon.nova-pro-v1:0',
guardrailConfig={'guardrailIdentifier': 'gr-abc123',
'guardrailVersion': 'DRAFT'},
messages=[{'role': 'user', 'content': [{'text': user_input}]}],
)
print(resp['stopReason']) # guardrail_intervened when a policy fires
The second way is standalone, and it is the one that surprises people. The ApplyGuardrail API runs a guardrail against any text you hand it, with no model call at all. That means you can screen the output of a self-hosted model, a model on another provider, or text from anywhere in your pipeline, and get a consistent policy decision across all of them. It is also how you check a retrieved passage before it ever reaches the model. Here is a full call that screens a model answer on the output side.
import boto3
bedrock = boto3.client('bedrock-runtime', region_name='us-east-1')
resp = bedrock.apply_guardrail(
guardrailIdentifier='gr-abc123',
guardrailVersion='DRAFT',
source='OUTPUT', # or INPUT
content=[{'text': {'text': model_answer}}],
)
print(resp['action']) # NONE or GUARDRAIL_INTERVENED
if resp['action'] == 'GUARDRAIL_INTERVENED':
print(resp['outputs'][0]['text']) # your blocked or masked text
for a in resp['assessments']:
print(list(a.keys())) # which policy fired
action prints NONE for clean text, or GUARDRAIL_INTERVENED with the replacement text and the name of the policy that fired, such as a content filter or a sensitive information rule. Failure mode: a ValidationException on source means it must be exactly INPUT or OUTPUT. A ThrottlingException means you passed the ApplyGuardrail request rate, so batch your checks or ask for a quota increase before you fan out. Field names in the assessment payload are precise; confirm them against the current API reference before you ship. [VERIFY]Before you change production
Attaching a guardrail to a live endpoint changes what real users receive on the next request, and a strict setting can start blocking valid traffic immediately. Test against the DRAFT version, cut a numbered version, point production at that version deliberately, and keep the previous version so you can roll back in one call. Watch the block rate for the first hour. This is general guidance, not a substitute for your own change review.
How grounding and Automated Reasoning catch a hallucination
These two policies target the failure the content filters cannot see: an answer that is polite, on topic, and wrong. Contextual grounding needs three things on the call, the source passages, the user question, and the model answer, and it returns two scores between 0 and 1. The grounding score measures how well the answer is supported by the source. The relevance score measures how well it addresses the question. You set a threshold on each, and an answer that falls below either gets blocked. Pair this with the knowledge base from Part 12 and the source passages are already in hand, which makes grounding the natural output check for a retrieval application.
Automated Reasoning goes further and is more work to set up. You feed it your policy documents, and it builds a formal logical model of the rules in them. At check time it tests the model’s claims against that logic and can tell you a statement is valid, invalid, or unsupported by the rules, rather than just scoring a similarity. That precision is worth it for regulated answers where a wrong statement has consequences, and it is overkill for a general chatbot. Start with grounding, which covers most retrieval hallucinations for a fraction of the effort, and reach for Automated Reasoning only where the cost of a confident-but-wrong answer is high. [VERIFY Automated Reasoning current availability and status]
What Guardrails costs
Guardrails bills per text unit, where one text unit is up to 1,000 characters of the text it evaluates. Content filters cost 0.15 dollars per 1,000 text units, and denied topics cost the same, each charged for whichever text you screen through it. Sensitive information filters are free. And a request the guardrail blocks is not billed, so the money follows the text that actually passes through a paid policy. Contextual grounding and Automated Reasoning are priced on their own meters, which you should confirm before you lean on them. [VERIFY grounding and Automated Reasoning rates]
Worked example
A support chatbot handles 100,000 requests a month. Each request screens about 2,000 characters total, the input prompt plus the model answer, which rounds to 2 text units per request. Turn on content filters and denied topics on both sides, and each request passes 2 units through each of the two paid policies. Content filters cost 100,000 times 2 units at 0.15 dollars per 1,000 units, about 30 dollars. Denied topics cost the same, about 30 dollars. Sensitive information filtering runs on every request for free.
Total guardrail spend is roughly 60 dollars a month at 100,000 requests, on top of the model tokens. That is small next to the model bill, and it stays a straight line as volume grows because there is no fixed floor here. The real cost of Guardrails is rarely the invoice. It is the latency each check adds and the valid traffic a strict setting blocks.
| Policy | Rate | Units per request | Monthly at 100k |
|---|---|---|---|
| Content filters | 0.15 per 1,000 units | 2 | 30 dollars |
| Denied topics | 0.15 per 1,000 units | 2 | 30 dollars |
| Sensitive information | Free | 2 | 0 dollars |
| Total, paid policies | 60 dollars |
Grounding and Automated Reasoning sit on separate meters and are left out of this total; verify their rates before enabling.
Plot the paid total against request volume and the line is flat and cheap. Ten thousand requests is about 6 dollars, a hundred thousand about 60, a million about 600, all on paid content filters and denied topics. There is no capacity floor to amortize and no step change, so cost is never the reason to skip Guardrails. Latency is the number to design around, since each check adds time to the request, and a strict configuration blocking real users is the risk that actually costs you.
Where Guardrails trips you in production
The first trap is over-blocking. Set every content filter to its highest strength on day one and you will block valid questions along with the bad ones, because a high filter reads borderline language as a violation. A medical support bot set too strict refuses to discuss symptoms. Start each filter at a middle strength, watch the block rate against real traffic, and tighten only the categories that actually let bad content through. The right setting is the one your traffic proves, not the strictest one available.
The second is latency. Every guardrail check is work in the request path, and on a streaming response the output check has to buffer enough text to evaluate before it releases tokens, which users feel as a pause. It is usually worth it, but you have to measure it and decide, not assume it is free. The third is scope confusion: an inline guardrail on a Converse call screens that call, and nothing else. If your application also pulls context from a knowledge base or calls a tool, that text is not screened unless you screen it, which is exactly what ApplyGuardrail is for. A guardrail covers the text you route through it and not one character more.
My take
I treat Guardrails as required on anything user-facing, and I turn on sensitive information filtering everywhere because it is free and catches the leak that embarrasses you most. But I do not trust a guardrail as the only line. It is a strong second layer over a well-written system prompt and a model chosen for the job, not a substitute for either. The mistake I see is teams cranking every filter to maximum, watching valid traffic get blocked, and then turning the whole thing off in frustration. Middle settings, measured against real traffic, tuned per category, beat both extremes. Contextual grounding is the policy I would add second, right after content filters, on any retrieval app. The failure I see most is a hate or violence filter set to maximum on a support bot that legitimately discusses account security, so valid tickets get blocked, users complain, and the team switches the guardrail off instead of dialing one category down. Tune per category against real traffic and you keep the protection without the collateral damage.
Start with denied topics and grounding, tune the filters against real traffic
Here is the posture I ship. Create one guardrail as its own resource and attach it across your applications rather than rebuilding a policy per app. Turn on sensitive information filtering everywhere, since it is free and stops the worst leaks. Add content filters at a middle strength and denied topics described in plain sentences, then watch the block rate on real traffic and tune per category instead of guessing. On any retrieval application add contextual grounding as the output check, because it catches the confident hallucination the content filters never see. Save Automated Reasoning for regulated answers where a wrong claim has a real cost. Prefer the DRAFT version while you tune, cut a numbered version before production, and keep the last one so a rollback is one call.
Use the inline guardrailIdentifier when you own the Bedrock call, and ApplyGuardrail when the text comes from a self-hosted model, another provider, a retrieved passage, or a tool result, so one policy covers your whole pipeline. If you also build on Azure, its equivalent is Azure AI Content Safety, covered in the Azure Gen AI guide. Next in this series I move from safety to control of the prompt itself, with Prompt Management, Flows, and caching, where the guardrail you just built becomes one stage in a managed pipeline. Before you read on, run one ApplyGuardrail call against your ugliest test prompt and read which policy fires. That is the fastest way to feel where your fence actually stands.
Related reading: the vendor-neutral guide to guardrails and responsible AI explains what these checks catch and miss at the concept level, without the Bedrock specifics.
References
• Detect and filter harmful content with Amazon Bedrock Guardrails
• Use contextual grounding check to filter hallucinations
• Use the ApplyGuardrail API in your application
• Amazon Bedrock pricing


DrJha