Who this is for and what you will be able to do
This guide is for developers building agents that handle sensitive data or high-stakes actions, such as customer service, finance, healthcare, or internal enterprise tools. By the end you should be able to tell rule-based guardrails from model-based ones, redact personal data with the built-in PII middleware, require human approval for sensitive tools, write before- and after-agent checks, and stack them in order.
What a guardrail does and where it runs
Guardrails validate and filter content at key points during agent execution. They can detect sensitive information, enforce content policies, validate outputs, and stop unsafe behavior before it causes harm[1]. Typical uses include preventing PII leakage, detecting and blocking prompt injection attacks, blocking inappropriate or harmful content, enforcing business rules and compliance, and validating output quality and accuracy[1].
Guardrails are implemented as middleware. Middleware can intercept execution before the agent starts, after it completes, or around model and tool calls[1].
Rule-based and model-based guardrails
Rule-based guardrails use regex patterns, keyword matching, or explicit checks. They are fast, predictable, and cost-effective, but they may miss nuanced violations[1]. Model-based guardrails use LLMs or classifiers and understand meaning, so they catch subtle problems that rules miss, at the cost of speed and expense[1]. The two are often used together.
Built-in guardrail one: PII detection
The built-in PII middleware detects common personally identifiable information in conversations, such as email addresses, credit card numbers, and IP addresses[1]. The built-in types are email, credit_card (Luhn validated), ip, mac_address, and url[1].
The strategy parameter decides what happens when PII is found:
redactreplaces the value with[REDACTED_{PII_TYPE}], for example[REDACTED_EMAIL][1].maskpartially obscures the value, such as the last 4 digits[1].hashreplaces the value with a deterministic hash[1].blockraises an exception when PII is detected[1].
The default strategy is redact. User messages are checked by default, while AI messages and tool results are not, unless you enable apply_to_output or apply_to_tool_results[1]. The example below redacts email addresses in user input:
PIIMiddleware(
"email",
strategy="redact",
apply_to_input=True,
),To block a specific key format, pass a custom regex as the detector and set the strategy to block:
PIIMiddleware(
"api_key",
detector=r"sk-[a-zA-Z0-9]{32}",
strategy="block",
apply_to_input=True,
),With apply_to_output=True, the middleware also redacts streamed output, including text deltas, tool-call arguments, tool outputs, and state snapshots, through a registered stream transformer. This requires langchain>=1.3.2[1]. The transformer holds back the last 128 characters of each text block, tool-call argument, and tool output until more text arrives or the block finishes, and then runs the detector on the held text plus the new delta[1].
Built-in guardrail two: human approval
Human-in-the-loop middleware requires a person to approve sensitive operations before they run. It suits financial transactions, deleting or modifying production data, sending communications to external parties, and any operation with significant business impact[1].
The interrupt_on setting decides which tools need approval and which run automatically:
HumanInTheLoopMiddleware(
interrupt_on={
# Require approval for sensitive operations
"send_email": True,
"delete_database": True,
# Auto-approve safe operations
"search": False,
}
),Approval depends on persistence, so add a checkpointer and give each conversation a thread ID. The agent pauses and waits for approval[1]:
# Human-in-the-loop requires a thread ID for persistence
config = {"configurable": {"thread_id": "some_id"}}After the human decides, resume with the same thread ID. The decision is passed with Command; approving looks like {"type": "approve"}[1]:
result = agent.invoke(
Command(resume={"decisions": [{"type": "approve"}]}),
config=config # Same thread ID to resume the paused conversation
)Custom guardrails: before and after the agent
When the built-in guardrails are not enough, write custom middleware that runs before or after the agent. You get full control over validation logic, content filtering, and safety checks[1].
A before-agent hook validates the request once at the start of each invocation. It suits session-level checks such as authentication and rate limiting, or blocking inappropriate requests before any processing starts[1]. The class below blocks requests containing banned keywords:
class ContentFilterMiddleware(AgentMiddleware):
"""Deterministic guardrail: Block requests containing banned keywords."""
def __init__(self, banned_keywords: list[str]):
super().__init__()
self.banned_keywords = [kw.lower() for kw in banned_keywords]A request that contains a banned keyword is stopped before any processing:
# This request will be blocked before any processing
result = agent.invoke({
"messages": [{"role": "user", "content": "How do I hack into a database?"}]
})An after-agent hook validates the final output once, before it is returned to the user. It suits model-based safety checks, quality validation, and final compliance scans[1]. The snippet below asks a model to judge the response:
# Use a model to evaluate safety
safety_prompt = f"""Evaluate if this response is safe and appropriate.
Respond with only 'SAFE' or 'UNSAFE'.
Response: {last_message.content}"""
result = self.safety_model.invoke([{"role": "user", "content": safety_prompt}])Stacking guardrails
Guardrails can be stacked by adding them to the middleware array. They run in order, which gives you layered protection[1].
Limits and common questions
- Rule-based guardrails are fast but can miss violations that depend on meaning, so critical paths often combine both kinds[1].
- Streamed redaction holds back the last 128 characters, which adds a small delay so that matches spanning several chunks can still be detected[1].
- Human approval depends on a checkpointer and a thread ID; without them, the paused run cannot be resumed[1].
Next steps
To learn custom middleware in depth, read the middleware documentation and API reference. The human-in-the-loop page covers approval workflows in full[1].
Adapted from the Guardrails page of LangChain's official documentation[1], released under the MIT License.
Sources
- 1GuardrailsLangChain docs (MIT)
Cite this page: Guardrails in LangChain: Filtering Sensitive Data and Unsafe Output. TellWorld, https://www.tellworld.net/practice/practice-langchain-guardrails. Updated 2026-11-14