A guardrail-less LangGraph agent is one bad tool call away from a headline. Not hypothetically — this is the exact failure mode we catalogued in 16 Reasons Why Agentic Automation Programs Fail: the agent that started approving things it was never authorized to approve, the pipeline that silently produced output nobody checked. LangGraph gives you precise control over how an agent moves through a task. It does not, by itself, stop that agent from leaking a customer’s SSN, answering a question it should have refused, or hallucinating a policy that doesn’t exist. That’s a separate layer, and Amazon Bedrock Guardrails is one of the more complete implementations of it — governance controls that work whether your model is on Bedrock, self-hosted, or a third-party API entirely.
- What Bedrock Guardrails Actually Checks
- Why This Matters More in LangGraph Than in a Simple Chatbot
- Building It: A Guarded LangGraph Support Agent
- Step 1: Install dependencies
- Step 2: Create the guardrail
- Step 3: Attach the guardrail to the model inside LangGraph
- Step 4: Wire it into a graph with an explicit intervention branch
- Step 5: Guard content the model never generated — RAG results and tool output
- Production Considerations
- How It Compares to the Other Guardrail Options
- The Verdict
- Key Takeaways
- FAQs
- References
This guide does two things. First, it walks through wiring Bedrock Guardrails into a real LangGraph agent — not the console click-through, the actual code. Second, it puts Bedrock Guardrails side by side with the other guardrail options a LangGraph developer will realistically run into: NVIDIA NeMo Guardrails, Guardrails AI, Azure AI Content Safety, and — since a good share of this audience is building on UiPath — the guardrails built into the UiPath LangChain SDK itself.
What Bedrock Guardrails Actually Checks
Amazon Bedrock Guardrails is a policy layer that sits between your application, the prompt, and the model response — evaluating both directions against six configurable safeguards (AWS, Bedrock Guardrails documentation):
- Content filters — detect and filter Hate, Insults, Sexual, Violence, Misconduct, and Prompt Attack content, with configurable strength per category. The Standard tier extends this detection into code elements — comments, variable names, string literals — which matters if your agent generates or reviews code.
- Denied topics — you define topics that are simply off-limits for your application (AWS’s own example: a banking app blocking fiduciary/investment advice), and the guardrail blocks them regardless of how the prompt is phrased.
- Word filters — exact-match blocking of custom words or phrases: profanity, competitor names, internal project codenames.
- Sensitive information filters — probabilistic PII detection (SSN, date of birth, address, and more) with block-or-mask actions, plus custom regex patterns for things PII detection won’t catch on its own, like internal account number formats.
- Contextual grounding checks — flags model responses that aren’t actually supported by your retrieved source material, or that don’t answer the user’s question. This is the RAG-hallucination check most guardrail products don’t have.
- Automated Reasoning checks — validates a response against a set of formal logical rules rather than a probabilistic classifier. AWS claims up to 99% accuracy on this check and describes it as the first guardrail feature to use formal logic (rather than another LLM) to catch hallucinations — a meaningfully different approach from every other product in this comparison. (AWS, Bedrock Guardrails product page)
AWS states its content filters block up to 88% of harmful content with these safeguards active. Guardrails can be invoked two ways: automatically during a model inference call (attach a guardrailIdentifier and guardrailVersion to the request), or independently via the standalone ApplyGuardrail API, which evaluates content against your policies without calling a foundation model at all — useful for gating retrieved documents or tool output before they ever reach the LLM.
Why This Matters More in LangGraph Than in a Simple Chatbot
A single-turn chatbot has one place to add a safety check: right before the response goes out. A LangGraph agent has many — the user’s initial input, every tool call’s arguments, every tool’s return value, every intermediate LLM turn, and the final output. LangGraph’s whole architectural pitch (see our LangGraph vs. CrewAI vs. Microsoft Agent Framework vs. Google ADK comparison) is that you get explicit control over every node and edge in that flow — which means you also get to decide exactly where guardrails sit, rather than accepting a single bolt-on filter at the edges.
Building It: A Guarded LangGraph Support Agent
We’ll build a banking customer-support agent — the same domain AWS uses in its own guardrails examples — that answers account questions but must never give investment advice, must redact PII in both directions, and must stay grounded in retrieved account documentation rather than inventing policy details.
Step 1: Install dependencies
pip install boto3 langgraph langchain-aws
Step 2: Create the guardrail
This is a one-time setup step, typically run once via a script or the console, not on every agent invocation:
import boto3
bedrock = boto3.client(service_name="bedrock", region_name="us-east-1")
guardrail = bedrock.create_guardrail(
name="banking-support-guardrail",
description="Blocks investment advice, redacts PII, checks grounding for banking support agent.",
topicPolicyConfig={
"topicsConfig": [{
"name": "Investment Advice",
"definition": "Personalized recommendations on investing, trading, or asset allocation.",
"examples": [
"Should I move my savings into stocks?",
"What's a good retirement investment strategy?",
],
"type": "DENY",
}]
},
contentPolicyConfig={
"filtersConfig": [
{"type": "SEXUAL", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "VIOLENCE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "INSULTS", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "MISCONDUCT", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "PROMPT_ATTACK", "inputStrength": "HIGH", "outputStrength": "NONE"},
]
},
sensitiveInformationPolicyConfig={
"piiEntitiesConfig": [
{"type": "EMAIL", "action": "ANONYMIZE"},
{"type": "PHONE", "action": "ANONYMIZE"},
{"type": "NAME", "action": "ANONYMIZE"},
{"type": "US_SOCIAL_SECURITY_NUMBER", "action": "BLOCK"},
{"type": "US_BANK_ACCOUNT_NUMBER", "action": "BLOCK"},
{"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"},
]
},
contextualGroundingPolicyConfig={
"filtersConfig": [
{"type": "GROUNDING", "threshold": 0.75},
{"type": "RELEVANCE", "threshold": 0.75},
]
},
blockedInputMessaging="I can't help with that request through this channel. Please contact support directly.",
blockedOutputsMessaging="I'm not able to provide that information here. Let me connect you with a specialist.",
)
# Snapshot the working draft into a stable, deployable version
version = bedrock.create_guardrail_version(
guardrailIdentifier=guardrail["guardrailId"],
description="v1 - initial banking support policy",
)
(This mirrors the structure in AWS’s own Guardrail API notebook — worth reading directly if you want the console-driven version of the same workflow, which the dev.to walkthrough by Dipayan Das covers screenshot-by-screenshot.)
Step 3: Attach the guardrail to the model inside LangGraph
langchain-aws exposes a guardrail_config parameter directly on ChatBedrockConverse — every call through this model object is automatically evaluated against your guardrail, in both directions:
from langchain_aws import ChatBedrockConverse
guarded_llm = ChatBedrockConverse(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
region_name="us-east-1",
guardrail_config={
"guardrailIdentifier": guardrail["guardrailId"],
"guardrailVersion": version["version"],
"trace": "enabled", # populates response_metadata["trace"] for auditing
},
)
A useful optimization for multi-turn conversations: set guard_last_turn_only=True alongside guardrail_config if you only need the guardrail to inspect the newest user message rather than re-scanning the entire conversation history on every turn — this cuts guardrail latency in longer-running agent sessions. (langchain-aws reference, BedrockBase.guardrails)
Step 4: Wire it into a graph with an explicit intervention branch
This is the part a plain chatbot integration skips, and where LangGraph’s explicit control actually earns its keep. When the guardrail intervenes, the response includes stopReason: "guardrail_intervened" in response_metadata — check for it and route accordingly, the same confidence-gated pattern we used for human-in-the-loop classification on UiPath:
from typing import Literal
from langgraph.graph import StateGraph, START, END, MessagesState
from langgraph.types import Command
async def call_guarded_model(state: MessagesState) -> Command:
response = await guarded_llm.ainvoke(state["messages"])
return Command(update={"messages": [response]})
def route_on_guardrail(state: MessagesState) -> Literal["respond", "handle_intervention"]:
last_message = state["messages"][-1]
if last_message.response_metadata.get("stopReason") == "guardrail_intervened":
return "handle_intervention"
return "respond"
async def handle_intervention(state: MessagesState) -> Command:
# Log the trace for audit, notify a human reviewer, or route to a specialist queue.
trace = state["messages"][-1].response_metadata.get("trace")
# ... send `trace` to your logging/observability pipeline here ...
return Command(update={})
async def respond(state: MessagesState) -> Command:
return Command(update={}) # deliver state["messages"][-1] to the user
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_guarded_model)
builder.add_node("handle_intervention", handle_intervention)
builder.add_node("respond", respond)
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", route_on_guardrail, ["respond", "handle_intervention"])
builder.add_edge("respond", END)
builder.add_edge("handle_intervention", END)
graph = builder.compile()
Step 5: Guard content the model never generated — RAG results and tool output
Model-level guardrail_config only inspects what the LLM says. If your agent retrieves documents or calls tools, that content can carry PII or violate policy before the model ever sees it. This is exactly what the standalone ApplyGuardrail API is for — call it directly as its own graph node, without invoking a foundation model at all:
import boto3
bedrock_runtime = boto3.client("bedrock-runtime", region_name="us-east-1")
async def guard_retrieved_content(state: MessagesState) -> Command:
retrieved_text = state.get("retrieved_context", "")
result = bedrock_runtime.apply_guardrail(
guardrailIdentifier=guardrail["guardrailId"],
guardrailVersion=version["version"],
source="OUTPUT", # evaluating content as if it were a model response
content=[{"text": {"text": retrieved_text}}],
)
if result["action"] == "GUARDRAIL_INTERVENED":
return Command(update={"retrieved_context": "[content withheld by policy]"})
return Command(update={})
Because ApplyGuardrail doesn’t invoke a model, it’s cheap and fast enough to run on every tool output as a matter of course — a pattern worth adopting even for agents where the LLM itself is already guarded.
Production Considerations
Tiers matter. Bedrock Guardrails ships Classic and Standard safeguard tiers; Standard extends coverage into code elements and is the one to pick for coding agents or DevOps-adjacent workflows.
Cross-account and cross-region. For organizations running multiple AWS accounts, Bedrock Guardrails supports centralized cross-account enforcement — one policy applied automatically across organizational units, rather than reconfiguring the same guardrail per account. Guardrail inference can also be distributed across regions for latency and resilience.
It’s not Bedrock-only. The ApplyGuardrail API works against any foundation model — including self-hosted models and third-party APIs like OpenAI and Google Gemini — so a Bedrock guardrail policy isn’t locked to Bedrock-hosted models. If your LangGraph agent calls multiple model providers, you can still centralize policy enforcement through one guardrail.
Turn on trace, always. "trace": "enabled" costs nothing and gives you the assessment breakdown — which specific policy fired, at what confidence — for every intervention. Skipping this is the single most common mistake in the walkthroughs we reviewed for this guide; without it, you know a guardrail blocked something but not why, which makes tuning thresholds pure guesswork.
How It Compares to the Other Guardrail Options
| Amazon Bedrock Guardrails | UiPath Guardrails (LangChain SDK) | NVIDIA NeMo Guardrails | Guardrails AI | Azure AI Content Safety | |
|---|---|---|---|---|---|
| Model | Managed AWS service | Open-source middleware/decorator (uipath_langchain) | Open-source toolkit (Apache 2.0) | Open-source Python library | Managed Azure service |
| Integration style | guardrail_config on the model, or standalone ApplyGuardrail API call | middleware=[...] on create_agent(), or @guardrail decorator on any LangGraph node | Colang DSL defining rails around your LLM calls | Guard object wrapping validator checks | REST API / SDK call |
| Works across model providers? | Yes — ApplyGuardrail is explicitly model-agnostic, including OpenAI and Gemini | Yes, within LangChain/LangGraph regardless of model provider | Yes, framework-agnostic by design | Yes, any Python LLM call | Primarily Azure OpenAI-native |
| Unique strength | Automated Reasoning checks — formal-logic hallucination detection, not just classifier-based | Native EscalateAction → UiPath Action Center human review, built for LangGraph out of the box | Deepest dialog/topical control via Colang; sub-100ms GPU-accelerated checks | Largest library of pre-built validators (50+ on Guardrails Hub) | Groundedness detection tightly coupled to Azure RAG pipelines |
| Human-in-the-loop | Not built-in — you wire it yourself (as in Step 4 above) | Built-in — EscalateAction suspends the run and creates an Action Center task | Not built-in | Not built-in | Not built-in |
| Learning curve | Low if you already use boto3/langchain-aws | Low if you’re already on create_agent(); two clear patterns (middleware vs. decorator) | Moderate — Colang is a new DSL to learn | Low — plain Python validators | Low — REST API |
| Best fit | AWS-native stacks, especially where Automated Reasoning’s audit trail matters for regulated decisions | Teams deploying LangGraph agents into UiPath Orchestrator who want guardrail violations to become Action Center tasks automatically | Teams needing fine-grained conversational flow control across a topic list | Python teams wanting composable, testable output validators independent of any cloud vendor | Azure OpenAI / Azure AI Foundry shops already inside that ecosystem |
A few things worth calling out that the table can’t fully capture:
UiPath’s guardrails are the most natural fit if you’re already following this site’s LangGraph-on-UiPath deployment pattern. The EscalateAction we referenced doesn’t just log a violation — it calls the same interrupt(CreateEscalation(...)) primitive from our UiPath human-in-the-loop coverage, suspending the graph and creating a real Action Center task for a human reviewer, with Approve/Reject resuming or terminating the run. Bedrock Guardrails gives you the block/log/mask decision; it doesn’t hand you a human review workflow for free the way UiPath’s does. Nothing stops you from combining both — Bedrock Guardrails as the detection layer, UiPath’s EscalateAction pattern (or the manual conditional-edge approach in Step 4) as the review layer.
NeMo Guardrails is the deepest option if “guardrail” means “stay on-topic” more than “block harmful content.” Its five rail types (input, dialog, retrieval, execution, output) let you script entire permitted conversation flows, not just filter categories — genuinely different from the policy-filter model every other product here uses.
Guardrails AI is the right call if vendor neutrality is the actual requirement. It’s a plain Python library with no cloud dependency, which matters if your LangGraph agent needs to run identically whether it’s calling Bedrock, Azure OpenAI, or a local model.
Azure AI Content Safety is the one to reach for only if you’re already committed to Azure OpenAI — its groundedness detection is strong, but the tightest value is inside that specific ecosystem, similar to how Bedrock Guardrails’ Automated Reasoning checks are strongest when your models already live on Bedrock.
The Verdict
Use Bedrock Guardrails when Automated Reasoning’s formal-logic hallucination check matters for your use case (regulated decisions, financial or medical adjacent content), or when you want one guardrail policy that stays consistent whether your LangGraph agent calls Bedrock-hosted or third-party models via ApplyGuardrail.
Use UiPath’s LangChain guardrails when you’re deploying into UiPath Orchestrator anyway and want a policy violation to become an Action Center task without hand-building the escalation graph yourself — the tightest fit for this site’s core audience.
Use NeMo Guardrails when the problem is conversational scope control as much as harmful-content filtering — you need the agent to stay strictly on a defined set of topics and flows.
Use Guardrails AI when cloud-vendor neutrality is a hard requirement and you want a large library of ready-made validators without adopting a managed service.
Use Azure AI Content Safety only if your models already live in Azure OpenAI or Azure AI Foundry — outside that ecosystem it doesn’t offer enough over the alternatives to justify the integration.
None of these are mutually exclusive within a single LangGraph graph — a defense-in-depth approach (a fast local validator on tool inputs, a managed cloud guardrail on model calls, a human escalation path for anything in between) is a reasonable default for anything touching regulated or customer-facing data.
Key Takeaways
- Bedrock Guardrails checks six policies — content filters, denied topics, word filters, sensitive information, contextual grounding, and Automated Reasoning — and can run either attached to a model call or standalone via
ApplyGuardrail. - In LangGraph, attach
guardrail_configtoChatBedrockConversefor automatic model-level checks, and useApplyGuardrailas its own graph node to check RAG content and tool output the model never generated. - Always check
response_metadata["stopReason"] == "guardrail_intervened"and route it through an explicit conditional edge — don’t let a guardrail block silently disappear into a generic error path. ApplyGuardrailis model-agnostic — it works against OpenAI, Gemini, and self-hosted models, not just Bedrock-hosted ones.- UiPath’s own LangChain guardrails are the only option in this comparison with human-in-the-loop escalation built in natively — worth combining with Bedrock Guardrails’ detection strength rather than choosing one exclusively.
- Turn on
tracefrom day one; it’s free and it’s the only way to actually tune your thresholds instead of guessing.
FAQs
Do I need Bedrock Guardrails if I’m already using UiPath’s guardrails middleware? Not necessarily one instead of the other. UiPath’s middleware is strong on PII/harmful-content detection and has human-in-the-loop escalation built in; Bedrock Guardrails adds contextual grounding checks and formal-logic Automated Reasoning checks that UiPath’s guardrails don’t currently offer. Many production setups layer both.
Does ApplyGuardrail cost the same as running the guardrail through a model call? ApplyGuardrail is priced separately from model invocation and doesn’t incur foundation model inference costs since no model is called — check current Bedrock pricing for exact rates, but it’s meaningfully cheaper to run on every tool output than routing that content through an LLM call just to check it.
Can I use Bedrock Guardrails with a non-Anthropic, non-Amazon model? Yes — through ApplyGuardrail, guardrails work with any foundation model, including third-party APIs like OpenAI and Google Gemini, not just models hosted on Bedrock.
What’s the difference between BlockAction and masking/redaction in Bedrock Guardrails? Content filters and denied topics generally block outright; sensitive information filters give you the choice per PII type — BLOCK refuses the response entirely, ANONYMIZE/mask replaces the sensitive span and lets the rest of the response through.
Is Automated Reasoning the same as contextual grounding checks? No — grounding checks verify a response is supported by retrieved source material (a RAG-specific check). Automated Reasoning validates a response against formal logical rules you define, independent of any retrieved documents — it’s closer to a policy compliance check than a hallucination-in-RAG check, though both catch overlapping failure modes.
References
- Amazon Bedrock Guardrails documentation — docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html
- Amazon Bedrock Guardrails product page — aws.amazon.com/bedrock/guardrails
- Guardrail API Example notebook — AWS Bedrock Samples
- Using Guardrails in Amazon Bedrock (console walkthrough) — Dipayan Das, DEV Community
- Amazon Bedrock Guardrails: Essential Setup Guide 2026 — Tech Jacks Solutions
langchain-awsguardrails reference — reference.langchain.comlangchain-awsGuardrails and Content Filtering internals — DeepWiki- UiPath LangChain SDK Guardrails documentation — uipath.github.io/uipath-python/langchain/guardrails
- NVIDIA NeMo Guardrails (GitHub) — github.com/NVIDIA-NeMo/Guardrails
- Guardrails AI LangChain integration — guardrailsai.com/docs/integrations/langchain






