AI & Machine Learning Engineering

LLM Guardrails: Safety, Moderation, and Filtering Layers

MatterAI
MatterAI
13 min read·

LLM Guardrails: Safety, Moderation, and Filtering Layers

Guardrails are the validation layers around an LLM: they check inputs before the model sees them and outputs before the user does. A model without guardrails is a liability — it can leak data, produce harmful content, or follow instructions embedded in untrusted input. This guide builds a layered guardrail stack and shows where each layer belongs.

The Layered Model

Guardrails belong at every boundary, not just one:

user input ──► [input guardrails] ──► LLM ──► [output guardrails] ──► user
                    │                                    │
              PII redaction                        moderation
              prompt injection                     PII leakage
              policy check                         format validation
              topic allowlist                      hallucination check

Each layer fails closed: if a check cannot run, reject the request rather than pass it through.

Layer 1: Input Guardrails

PII Redaction

Never let sensitive data reach the model. Redact before the prompt is built:

import re

PII_PATTERNS = {
    "email": re.compile(r"\b[\w.+-]+@[\w-]+\.[\w.]+\b"),
    "phone": re.compile(r"\b\+?\d[\d\s-]{8,}\d\b"),
    "ssn": re.compile(r"\b\d{3}-\d{2}-\d{4}\b"),
    "credit_card": re.compile(r"\b(?:\d[ -]?){13,16}\b"),
}

def redact_pii(text: str) -> str:
    for name, pattern in PII_PATTERNS.items():
        text = pattern.sub(f"[REDACTED:{name}]", text)
    return text

def build_prompt(user_input: str) -> str:
    return f"Answer the user's question.\n\nUser: {redact_pii(user_input)}"

Redaction is a first line, not a guarantee. Named-entity models catch more than regexes; use a PII detection model for production, regexes for the cheap first pass.

Prompt Injection Defense

Treat all external content as untrusted. The two structural defenses are input classification and output validation:

def is_injection_attempt(text: str) -> bool:
    """Cheap heuristic layer; pair with a classifier model for production."""
    signals = [
        "ignore previous instructions",
        "ignore all previous",
        "system prompt",
        "you are now",
        "disregard",
        "jailbreak",
        "developer mode",
    ]
    lowered = text.lower()
    return any(s in lowered for s in signals)

Heuristics miss novel attacks. The robust pattern is to separate instructions from data structurally (system prompt vs user content), and to validate that the model's output follows the task, not injected instructions.

Topic and Policy Allowlists

For domain applications, gate the topic before generation:

ALLOWED_TOPICS = {"billing", "shipping", "returns", "account"}

def check_topic(query: str) -> bool:
    topic = classify_topic(query)  # small classifier or LLM call
    return topic in ALLOWED_TOPICS

Layer 2: Output Guardrails

Moderation

Moderate every output before it reaches the user. Use a dedicated moderation model rather than asking the same LLM to police itself:

from openai import OpenAI

client = OpenAI()

def moderate_output(text: str) -> bool:
    result = client.moderations.create(input=text)
    categories = result.results[0].categories
    flagged = result.results[0].flagged
    if flagged:
        print(f"Blocked categories: {[k for k, v in categories.items() if v]}")
    return not flagged

PII Leakage Detection

The model can echo PII that slipped past input redaction, or invent it. Scan outputs with the same redaction patterns and block if anything leaks:

def check_output_leak(text: str) -> bool:
    for name, pattern in PII_PATTERNS.items():
        if pattern.search(text):
            return False  # leak detected, block
    return True

Format Validation

If the model must return JSON, validate it before use. Never trust the model's claim that it produced valid JSON:

import json
from pydantic import BaseModel, ValidationError

class RefundDecision(BaseModel):
    approved: bool
    amount: float
    reason: str

def parse_llm_json(raw: str) -> RefundDecision | None:
    try:
        data = json.loads(raw)
        return RefundDecision(**data)
    except (json.JSONDecodeError, ValidationError) as e:
        print(f"Invalid output: {e}")
        return None

Layer 3: Policy Enforcement with Guardrails Frameworks

For complex policies, use a guardrails framework instead of hand-rolled checks. Guardrails AI validates against a schema with validators:

from guardrails import Guard
from guardrails.hub import ToxicLanguage, PIILeakage, ValidJSON

guard = Guard().use_many(
    ToxicLanguage(threshold=0.5, on_fail="exception"),
    PIILeakage(on_fail="exception"),
    ValidJSON(on_fail="exception"),
)

def safe_generate(prompt: str) -> str:
    raw = llm_generate(prompt)
    validated = guard.validate(raw)  # raises if any validator fails
    return validated.validated_output

NeMo Guardrails takes a different approach: rails defined as Colang rules that constrain the conversation flow:

# config/rails.co
define user ask about competitors
  "who are your competitors?"

define flow
  user ask about competitors
  bot inform cannot discuss competitors
  bot ask if anything else
from nemoguardrails import LLMRails, RailsConfig

config = RailsConfig.from_path("./config")
rails = LLMRails(config)

response = rails.generate(messages=[{"role": "user", "content": "Who are your competitors?"}])
# "I can't discuss competitors. Anything else I can help with?"

Layer 4: Hallucination Checks

For grounded systems, verify the output against the source before returning it:

def check_grounded(answer: str, sources: list[str]) -> bool:
    """Verify each factual claim in the answer appears in the sources."""
    claims = extract_claims(answer)  # LLM or NLI model
    for claim in claims:
        if not any(claim_supported(claim, src) for src in sources):
            return False
    return True

If grounding fails, return a fallback ("I couldn't verify that") instead of the unverified answer.

Failure Handling Strategy

Guardrails fail in two ways: false positives (blocking good content) and false negatives (passing bad content). Decide per layer:

  • Hard fail: safety-critical checks (toxicity, PII, injection) block and log.
  • Soft fail: quality checks (format, grounding) trigger a retry with the error fed back to the model.
  • Fallback: when a retry fails, return a canned safe response.
def generate_with_guardrails(prompt: str) -> str:
    if not check_topic(prompt) or is_injection_attempt(prompt):
        return "I can't help with that."
    for attempt in range(2):
        raw = llm_generate(prompt)
        if not moderate_output(raw):
            return "I can't provide that response."
        if not check_output_leak(raw):
            return "I can't provide that response."
        parsed = parse_llm_json(raw)
        if parsed is not None:
            return raw
    return "I couldn't generate a valid response. Please try again."

Monitoring Guardrails

Guardrails need their own observability:

  • Block rate per layer: a spike in moderation blocks means the model drifted or the input mix changed.
  • False positive rate: sample blocked requests and check how many were actually fine.
  • Guardrail latency budget: guardrails should add < 100ms; if they add seconds, they are the bottleneck.

Implementation Checklist

  • Redact PII on input before the prompt is built
  • Separate instructions from untrusted content structurally
  • Moderate every output with a dedicated moderation model
  • Scan outputs for PII leakage
  • Validate structured outputs with a schema, never trust the model
  • Use a guardrails framework for complex multi-policy systems
  • Verify grounding for any system that cites sources
  • Define hard-fail vs soft-fail per layer
  • Monitor block rates and false positives per layer

MatterAI builds frontier AI infrastructure for engineering teams — from inference-optimized models to autonomous coding agents and agentic code reviews.

Explore what we're building:

  • Orbital IDE — Autonomous AI coding agent with background agents and deep codebase memory
  • AI Code Reviews — Agentic pre-commit reviews across GitHub, GitLab, and Bitbucket
  • Axon Models — Frontier-grade reasoning models at 70% lower inference cost

Get started free - https://app.matterai.so


Follow us on X · LinkedIn · GitHub

Share this Guide:

Ship Faster. Ship Safer.

Join thousands of engineering teams using MatterAI to autonomously build, review, and deploy code with enterprise-grade precision.

No credit card requiredSOC 2 Type IISetup in 2 min