Bedrock Guardrails
Guardrails are safety as a configurable layer: content filters, PII redaction, denied topics, and grounding checks that run on input and output, independent of the model.
- AWS credentials (
aws configure) + Bedrock model access enabled in your region +pip install boto3 - AWS credentials (
aws configure) +pip install boto3
Learning objectives
- Create a Bedrock Guardrail with content filters, denied topics, and PII handling.
- Apply a guardrail to a Converse call and read the intervention result.
- Use contextual grounding checks to catch hallucinations in RAG answers.
- Decide what belongs in a guardrail vs. in your application code.
30-second recap
- Bedrock & Claude: Amazon Bedrock hosts Claude and other models behind AWS IAM and billing; you call them with the AWS SDK instead of a vendor API key.
- The LLM threat model: Anything the model reads can carry instructions: direct injection comes from the user, indirect injection hides in documents, web pages and tool results.
code/aws6-guardrails/ in the course, with a README on how to run it. Read here, run there — no need to copy-paste.Safety as a configurable layer essential
Here is the failure this section exists to prevent. A team ships a support chatbot on Bedrock. It works beautifully in the demo. Two weeks later a user pastes their full credit-card number into the chat, the model happily quotes it back in its reply, and now that number is sitting in your CloudWatch logs and your conversation history — a compliance incident that started as a helpful answer. Another team's bot cheerfully dispenses legal advice it was never authorized to give. A third confidently answers a question its knowledge base never covered, inventing a policy that does not exist. None of these are model bugs. The model did exactly what a helpful model does. The missing piece was a layer that says "no" before the harmful text ever reaches the user or the logs — and that layer is a guardrail.
Think of a guardrail the way you think of a metal detector at an airport. The detector is not part of any individual traveller, it does not care which airline you fly, and you can upgrade it or retune its sensitivity without changing a single passenger. It simply stands in the doorway and inspects everything that passes in and everything that passes out. A Bedrock Guardrail is that detector for text: a policy object that lives outside the model and screens the conversation in both directions, so the same rules protect every model call you attach it to.
Why make it a separate, configurable layer instead of just writing "please be safe" in the system prompt? Because a prompt is advice the model may or may not follow, while a guardrail is enforcement that runs regardless of what the model decides. Prompts can be jailbroken, ignored under pressure, or forgotten as the conversation grows long; a guardrail is deterministic policy applied by the platform, not by the model's goodwill. It also means your safety rules live in one auditable place — the security team can own them, you can diff them in code review, and you can reuse the identical policy across ten different bots instead of copy-pasting prompt text into each. The single most common mistake here is treating "the model is well-behaved" as your safety strategy; the professional stance is that the model is one layer and the guardrail is an independent second one that does not trust the first.
A Guardrail is a policy object you attach to model calls. It filters harmful content, blocks topics you deny, redacts PII, and can check that a RAG answer is grounded in the retrieved context. It runs on both the input and the output, independent of the model.
Follow the arrows around the loop: text flows left → right into the model, then right → left back to the user, and the amber box in the middle sits on every leg of that trip.
- The left blue box is the user and the right white box is the Bedrock model. The amber box between them is the guardrail — deliberately drawn outside the model, because it is a separate policy object, not part of the model.
- The top pair of arrows is the input path (user → guardrail → model); the lower pair is the output path (model → guardrail → user). The guardrail screens both, which is why the same rules protect the whole conversation.
- The red box is the payoff: when either direction violates a rule, the guardrail substitutes a safe fallback message and the offending text never reaches the model or the user.
In short: a guardrail is a bidirectional screen bolted onto the doorway, enforcing one policy on everything that passes in and out.
Create a guardrail essential
The mistake to avoid is scattering safety checks through your code. The tempting first instinct is to sprinkle if "credit card" in text and a pile of regexes directly into every handler that touches the model. That path leads to safety logic duplicated across ten endpoints, drifting out of sync, impossible to audit, and untestable in one place. Bedrock's answer is to make the policy a single object you create once — the way you'd define one firewall ruleset for a whole network rather than re-deriving the rules at every port.
Reading the lab below, notice that a guardrail is built on the control plane — the management API (the bedrock client) whose whole job is to create and configure resources, as opposed to the runtime that actually runs models. That distinction matters and trips people up constantly: you create a guardrail with the bedrock client, but later you apply it with the bedrock-runtime client. Creating returns a durable identifier and a version number; applying happens on every call using that identifier. Two clients, two jobs.
The policy itself is assembled from independent, opt-in sections — you turn on only the ones you need, and each is just data (dictionaries and lists), which is exactly why adding a new protection later is a one-line edit rather than a code change:
- Content filters score text against harm categories (such as hate or violence) at a strength you choose. Crucially, each category has a separate strength for input (what the user sends) and output (what the model replies) — a higher strength blocks more aggressively but risks catching borderline-benign text, so it is a dial, not a switch.
- PII handling lets you name personal-data entity types and pick an action per type. This is where the two-actions idea lives: some data can pass through masked (anonymized), while some data should stop the request entirely (blocked) — different risk, different action, same policy.
- Denied topics let you refuse a whole subject, not just a word. You give the topic a plain-English definition plus a few example utterances, and Bedrock detects the topic semantically — so a paraphrase you never listed still gets caught, which a keyword blocklist would miss.
The two fallback-message fields are easy to overlook but they are the user's entire experience of a block: when the guardrail refuses, the caller receives that polite text instead of the real content, so it is worth writing something honest and on-brand rather than leaving a terse default. Keep an eye on the returned id and version in the final line — those two values are the handle you must save, because without them no model call can be told which policy to enforce.
create the guardrail once on the bedrock control plane — stacking only the sections you need — and it hands back an id + version you later pass to the bedrock-runtime client to apply it.
Read the big left box first (what the policy is made of), then follow the arrows rightward and downward (how it is created and later used).
- The left white box is a single
create_guardrailcall. The three amber strips inside it are the independent, opt-in sections — content filters, PII handling, denied topics — each just data, so adding one is a one-line edit. - The blue box is the
bedrockcontrol-plane client that creates the policy; the solid arrow into it is the create call, and the arrow down to the green box is what it returns: the id and version you must save. - The dashed arrow to the purple box is the deferred step — applying the guardrail happens later on the separate
bedrock-runtimeclient. Two different clients handle create vs apply, which is the distinction people trip over.
In short: compose the policy from the sections you need, create it once on the control plane, and keep the returned id + version — that handle is what runtime needs to enforce it.
create_guardrail.pyimport boto3
bedrock = boto3.client("bedrock", region_name="us-east-1")
g = bedrock.create_guardrail(
name="support-guardrail",
blockedInputMessaging="I can't help with that request.",
blockedOutputsMessaging="I can't provide that response.",
contentPolicyConfig={"filtersConfig": [
{"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "VIOLENCE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
]},
sensitiveInformationPolicyConfig={"piiEntitiesConfig": [
{"type": "EMAIL", "action": "ANONYMIZE"},
{"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"},
]},
topicPolicyConfig={"topicsConfig": [
{"name": "legal-advice", "definition": "Providing legal advice.",
"type": "DENY", "examples": ["Should I sue my employer?"]},
]},
)
print("guardrail id:", g["guardrailId"], "version:", g["version"])
This script builds a safety policy once and registers it with Bedrock. A guardrail is a rule-set object that AWS stores for you; later you attach it to model calls by ID. Nothing about the model changes — the guardrail is a separate layer that inspects text going in and coming out. (Running it needs AWS credentials and Bedrock access, but the structure is the whole lesson.)
boto3.client("bedrock", region_name="us-east-1")opens a connection to the Bedrock control plane (the management API where you create/configure guardrails) in the US East region.create_guardrail(name=...)is the one call that makes the policy. The two...Messaginglines set the polite fallback text the caller sees when input or output is blocked, instead of the real content.- Content filters —
contentPolicyConfigturns on category filters. HereHATEandVIOLENCEare set toHIGHstrength on bothinputStrength(what the user sends) andoutputStrength(what the model replies). Higher strength = blocks more aggressively. - PII handling —
sensitiveInformationPolicyConfiglists personal data types.EMAILusesANONYMIZE(the email is redacted, replaced with a placeholder), whileCREDIT_DEBIT_CARD_NUMBERusesBLOCK(the whole request is refused). - Denied topics —
topicPolicyConfigdefines subjects to refuse. Thelegal-advicetopic has a plain-Englishdefinitionand anexampleslist; Bedrock uses these to recognize the topic even when worded differently. - The final
printshows the two values AWS hands back: aguardrailIdand aversion— you need both to attach it later.
What the output means: You'd see something like guardrail id: gr-abc123 version: 1. Save that ID — it's the handle you pass to every model call you want protected.
Try this: Add a line for {"type": "SEXUAL", "inputStrength": "HIGH", "outputStrength": "HIGH"} to the filters list. Adding safety categories is just adding dictionary entries — no model retraining involved.
Apply it to a call intermediate
A guardrail you created but never attached protects nothing. This is a genuinely common oversight: an engineer builds a polished policy, sees "guardrail created" in the console, ships — and the bot is exactly as exposed as before, because creating a guardrail and using it are two separate acts. The policy sits on the shelf until you hand its identifier to a specific model call. Think of the guardrail as a security badge you had printed: printing it does nothing; it only works when you actually tap it at the door on the way in.
Attaching it is deliberately small: you pass one extra argument — guardrailConfig, carrying the identifier and version from the previous step — to the same converse call you already make. Nothing else about your request changes. That minimalism is the design goal: safety should be a bolt-on you can add (or, in testing, remove) without rewriting your calling code.
The part worth internalizing is how you learn a block happened, because your code must react to it rather than blindly print a reply. Bedrock does not throw an exception when a guardrail fires; it returns a normal, successful response whose stopReason field has changed. A clean completion carries a stop reason like end_turn; when the guardrail intervenes, that field becomes guardrail_intervened. So stopReason is your control signal: branch on it. When it says the guardrail acted, the text already sitting in the response is your fallback message, not the model's real words — the platform has substituted it for you, and the offending content never came back to your application at all. The mistake to avoid is ignoring stopReason and treating every response as trustworthy model output; a blocked call looks structurally identical to a successful one until you read that one field.
Pass guardrailConfig to converse. If the guardrail intervenes, stopReason is guardrail_intervened and you get the safe fallback message instead of raw model output.
stopReason is your control signal. A blocked call looks structurally identical to a clean one — no exception is thrown — so you must branch on stopReason: end_turn means trust the text, guardrail_intervened means the text is the fallback and the real output never came back.
Read left to right: make the call, read one field on the response, then take one of two branches depending on its value.
- The left blue box is your
conversecall withguardrailConfigattached. It always returns a normal, successful response — Bedrock does not raise an exception when a guardrail fires. - The white middle box is the one line that matters: reading
stopReason. The two arrows out of it are the branch — the solid one to the green box, the dashed one to the red box. - The green box (
end_turn) means a clean completion, so the response text is the model's real answer. The red box (guardrail_intervened) means a rule tripped, so the text is your safe fallback and the model's real output never reached you.
In short: the guardrail turns a block into a changed stopReason, not an error — branch on that field or you will print a fallback as if it were a real answer.
apply_guardrail.pyimport boto3
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
resp = brt.converse(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": [{"text": "My card is 4111 1111 1111 1111, is it valid?"}]}],
guardrailConfig={"guardrailIdentifier": "GR123", "guardrailVersion": "1"},
)
print("stop reason:", resp["stopReason"])
print(resp["output"]["message"]["content"][0]["text"])
stop reason: guardrail_intervened
I can't provide that response.
Now we use the guardrail on a normal chat call. The user message deliberately contains a credit-card number — which the policy above set to BLOCK — so we can watch the guardrail step in and stop the response.
boto3.client("bedrock-runtime", ...)connects to the runtime API (the one that actually runs models), which is different from thebedrockcontrol-plane client used to create the guardrail.brt.converse(modelId=..., messages=[...])is the standard Bedrock chat call. Themessageslist holds the conversation; here one user turn asks whether a card number is valid.- The key line:
guardrailConfig={"guardrailIdentifier": "GR123", "guardrailVersion": "1"}attaches the policy by the ID and version you got in Lab W6.1. That single argument is what turns safety on for this call. resp["stopReason"]tells you why the reply ended. Normally it's something likeend_turn; when a guardrail acts it becomesguardrail_intervened.- The last
printdigs into the nested response to pull the text out:output→message→ firstcontentblock → itstext.
What the output means: stop reason: guardrail_intervened confirms the guardrail blocked the call, and the printed text is your safe fallback message (I can't provide that response.) — not anything the model actually said. The card number never reached the model unfiltered.
Try this: Change the message to a harmless question like "What are your support hours?" and you'd expect stop reason: end_turn with a real answer — the guardrail only intervenes when a rule is triggered.
Contextual grounding for RAG advanced
You have felt this failure even if you have never built a bot. You ask an assistant a question its documents cannot actually answer, and instead of admitting it, the model produces a fluent, confident, completely invented answer — the classic hallucination. In a RAG system this is the cardinal sin: the retrieval step handed the model some context, the user's question was slightly outside what that context covers, and the model filled the gap with plausible fiction. Content filters and denied topics do nothing here — the answer is not hateful or off-topic, it is simply unsupported. That is the exact hole a contextual-grounding check is built to plug.
The mental model is a diligent fact-checker sitting between the model and the user. The fact-checker holds two things: the source context that retrieval pulled, and the answer the model wrote. Its job is to ask, "Is this answer actually backed by that context, and is it even relevant to what was asked?" It does not judge whether the answer is true in some absolute sense — it judges whether the answer is grounded in the material you gave the model. An answer can be perfectly true in reality and still fail grounding because your documents never mentioned it, and that failure is the point: you want the bot to answer from your corpus, not from the model's training-time memory.
Because "grounded or not" is a matter of degree, the check produces a score rather than a yes/no, and you set a threshold below which the answer is refused. This turns a fuzzy safety concern into a dial you can tune: raise the threshold and the bot becomes stricter (it refuses more, hallucinates less, but sometimes declines answerable questions); lower it and it answers more freely at the cost of letting weaker-supported replies through. Choosing that number is a product decision about how much unsupported confidence you can tolerate. The common mistake is assuming grounding is binary or that a high score guarantees truth — it guarantees support by the provided context, which is what you can actually enforce, and it is a far stronger defense than hoping the model stays honest on its own.
The grounding check scores whether an answer is supported by the source context and relevant to the query. Below a threshold, the guardrail blocks the answer — a managed defense against the hallucination problem you evaluated in Ch 5.
Read left to right: two inputs feed a score, the score meets a threshold, and the threshold decides between two outcomes on the right.
- The two left white boxes are the fact-checker's inputs — the retrieved source context and the model's answer. Both arrows feed the amber box.
- The amber box is the grounding score (0–1): how well the context supports the answer. It flows down into the blue "vs threshold" box — the dial you choose.
- The branch on the right is the payoff: at or above threshold the green box returns the answer; below it the red box refuses. A high score guarantees support by your context, not absolute truth — which is exactly the defense you can enforce.
In short: grounding scores answer-against-context and refuses below your threshold, catching confident-but-unsupported replies that content filters and denied topics would miss.
Exercise W6.1 — Ground your W4 KB
Context: The whole point of guardrails on a RAG stack is to stop hallucination on questions your corpus cannot answer. Attaching a contextual-grounding check to your existing W4 Knowledge Base call is the canonical way to prove the safety layer actually earns its place.
Your task: Attach a guardrail with a contextual-grounding check to your W4 retrieve_and_generate call, then ask a question your docs do not answer and confirm the guardrail blocks a confident-but-unsupported reply.
Requirements:
- Reuse the W4 Knowledge Base /
retrieve_and_generatepath - Attach a guardrail whose grounding check is active on the call
- Pose a question with no support anywhere in the indexed docs
- Confirm the response is blocked/refused rather than an invented answer
- Contrast with an in-corpus question that still answers normally
💡 Hint: Pick a question that sounds in-domain but is genuinely absent from the docs — that is what exposes weak grounding, not obvious nonsense.
🪜 Practice ladder beginner → industry
Six graded exercises, easy to real-world. Try each before opening its solution.
Context: Guardrails are a safety layer that lives outside the model, configured on the Bedrock control plane and applied to calls independently of the prompt. Content filters are the starting point: they score input and output per harm category at a chosen strength.
Your task: Use bedrock.create_guardrail to block HATE and VIOLENCE at HIGH strength on both input and output, with fallback messaging, and print the returned id and version.
Requirements:
- Create the guardrail via the
bedrockcontrol-plane client - Set both
blockedInputMessagingandblockedOutputsMessaging contentPolicyConfig.filtersConfiglists HATE and VIOLENCE- Each filter sets
inputStrengthandoutputStrengthto HIGH - Print
guardrailIdandversion; needs AWS creds
💡 Hint: The guardrail is created on the control plane and referenced by id later — it is not part of any single prompt.
Show solution
Guardrails are a separate safety layer configured on the control plane; content filters set input/output strengths per category.
import boto3
bedrock = boto3.client("bedrock", region_name="us-east-1")
resp = bedrock.create_guardrail(
name="support-guardrail",
blockedInputMessaging="I can't help with that request.",
blockedOutputsMessaging="Response withheld by policy.",
contentPolicyConfig={"filtersConfig": [
{"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "VIOLENCE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
]},
)
print(resp["guardrailId"], resp["version"])
Context: A guardrail does nothing until you attach it to a runtime call. When it fires, the response comes back with a distinctive stop reason and the safe fallback text instead of the model's output — and your code must branch on that.
Your task: Pass guardrailConfig to a converse call on the bedrock-runtime client and detect the guardrail_intervened stop reason.
Requirements:
- Use the
bedrock-runtimeclient and theconverseAPI - Supply
guardrailConfigwith aguardrailIdentifierandguardrailVersion - Inspect
r["stopReason"]after the call - When it equals
guardrail_intervened, report the block instead of printing model text - Otherwise print the normal completion; needs AWS creds
💡 Hint: Treat stopReason as the control signal — the fallback message is already substituted for you when the guardrail intervenes.
Show solution
When a guardrail fires, stopReason is "guardrail_intervened" and the caller gets the safe fallback text.
import boto3
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
r = brt.converse(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role":"user","content":[{"text":"...user text..."}]}],
guardrailConfig={"guardrailIdentifier": "GR123", "guardrailVersion": "1"},
)
if r["stopReason"] == "guardrail_intervened":
print("blocked; safe fallback returned")
else:
print(r["output"]["message"]["content"][0]["text"])
Context: Handling personal data safely is often a compliance requirement, not a nicety. Bedrock's PII policy lets you mask some entity types and hard-block others in the same guardrail, so emails can be redacted while card numbers stop the request cold.
Your task: Extend a guardrail with a sensitiveInformationPolicyConfig that ANONYMIZEs EMAIL and BLOCKs CREDIT_DEBIT_CARD_NUMBER.
Requirements:
- Configure
piiEntitiesConfigas a list of entity/action pairs EMAILuses actionANONYMIZE(masked, not refused)CREDIT_DEBIT_CARD_NUMBERuses actionBLOCK(refused)- Keep the required blocked-messaging fields set
- Explain the difference between anonymize and block; needs AWS creds
💡 Hint: ANONYMIZE and BLOCK are two different actions on the same policy — pick per entity based on whether the data may pass through masked or must stop the call.
Show solution
The PII policy lists entity types with an action: ANONYMIZE masks, BLOCK refuses.
import boto3
bedrock = boto3.client("bedrock", region_name="us-east-1")
bedrock.create_guardrail(
name="pii-guardrail",
blockedInputMessaging="blocked", blockedOutputsMessaging="blocked",
sensitiveInformationPolicyConfig={"piiEntitiesConfig": [
{"type": "EMAIL", "action": "ANONYMIZE"},
{"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"},
]},
)
print("pii guardrail created")
Context: Sometimes the risk is a whole subject, not a word: a support bot that must never give financial advice, for instance. A denied-topic policy detects the topic semantically, and its accuracy depends on giving it a crisp definition plus example utterances to anchor detection.
Your task: Add a topicPolicyConfig that denies financial advice, with a name, a definition, type="DENY", and example utterances.
Requirements:
topicsConfigholds one topic withtype="DENY"- Provide a precise
definitionof what counts as the topic - Include a few
examplesof in-topic questions to anchor detection - Keep
blockedInputMessaging/blockedOutputsMessagingset - Needs AWS creds to create
💡 Hint: Examples are not decoration — the more representative the sample utterances, the better the topic classifier generalizes to paraphrases.
Show solution
A denied topic needs a name, a definition, type="DENY", and example utterances to anchor detection.
import boto3
bedrock = boto3.client("bedrock", region_name="us-east-1")
bedrock.create_guardrail(
name="topic-guardrail",
blockedInputMessaging="I can't advise on that.",
blockedOutputsMessaging="Withheld.",
topicPolicyConfig={"topicsConfig": [{
"name": "FinancialAdvice",
"definition": "Recommendations to buy/sell specific securities.",
"type": "DENY",
"examples": ["Should I buy TSLA?", "What stock will go up?"],
}]},
)
print("topic guardrail created")
Context: In a real org the security team, not the app engineer, owns policy. Expressing the guardrail as a small data spec that a builder turns into create_guardrail kwargs lets non-engineers edit it and lets you diff the policy in code review.
Your task: Write build_guardrail_config(pii, denied_topics) that assembles the create_guardrail kwargs from a simple spec, adding each policy section only when its input is non-empty.
Requirements:
- Always include the base fields (name and blocked-messaging)
- When
piiis given, buildsensitiveInformationPolicyConfig.piiEntitiesConfigfrom (type, action) pairs - When
denied_topicsis given, buildtopicPolicyConfig.topicsConfigwithtype="DENY" - Omit a section entirely when its spec input is empty
- Runs offline; verify by printing the resulting config keys
💡 Hint: Build a base dict, then conditionally add each policy block — a comprehension over the spec tuples keeps the entity/topic lists tidy.
Show solution
Expressing policy as data lets non-engineers edit it and lets you diff it in review.
def build_guardrail_config(pii, denied_topics):
cfg = {"name": "house-guardrail",
"blockedInputMessaging": "blocked",
"blockedOutputsMessaging": "blocked"}
if pii:
cfg["sensitiveInformationPolicyConfig"] = {"piiEntitiesConfig":
[{"type": t, "action": a} for t, a in pii]}
if denied_topics:
cfg["topicPolicyConfig"] = {"topicsConfig":
[{"name": n, "definition": d, "type": "DENY", "examples": ex}
for n, d, ex in denied_topics]}
return cfg
c = build_guardrail_config(
pii=[("EMAIL","ANONYMIZE"),("SSN","BLOCK")],
denied_topics=[("Legal","Legal advice",["Can I sue?"])])
print(list(c.keys()))
Context: A RAG bot's cardinal sin is a confident answer the retrieved context does not support. Contextual grounding scores how well an answer is backed by its context; below a threshold you refuse. In production this decision sits alongside the guardrail stop reason as a single gate.
Your task: Write gate(grounding_score, stop_reason, threshold=0.75) that returns a decision dict: block when the guardrail intervened, refuse when grounding is below threshold, otherwise answer.
Requirements:
- A
guardrail_intervenedstop reason short-circuits to a blocked result - A
grounding_scorebelowthresholdreturns a refuse action with the reason and score - Otherwise return an answer action carrying the score
- Threshold is a parameter with a sensible default (e.g. 0.75)
- Demonstrate all three branches; runs offline
💡 Hint: Check the guardrail signal before the score — a hard block outranks a grounding judgement, so order the conditions accordingly.
Show solution
Contextual grounding scores how well the answer is supported by the context; below threshold you refuse, defending against hallucination.
def gate(grounding_score, stop_reason, threshold=0.75):
if stop_reason == "guardrail_intervened":
return {"action": "blocked_by_guardrail"}
if grounding_score < threshold:
return {"action": "refuse", "reason": "insufficient grounding",
"score": grounding_score}
return {"action": "answer", "score": grounding_score}
print(gate(0.91, "end_turn")) # answer
print(gate(0.40, "end_turn")) # refuse
print(gate(0.99, "guardrail_intervened")) # blocked_by_guardrail
✓ Checkpoint — you can move on when you can…
- Create a guardrail with content, PII, and topic policies.
- Apply a guardrail to Converse and detect an intervention.
- Explain what a contextual-grounding check defends against.
- Draw the line between guardrail policy and application authorization.
Knowledge check check yourself
A guardrail runs independent of the model on both input and output. What stopReason indicates it acted, and what does the caller receive instead of raw model output?
Show answer
Where do you draw the line between what belongs in a guardrail versus your application code?