Moderation & Output Guardrails

Implement content moderation, PII redaction, output schema guardrails, and refusal cascades for safe AI deployment.

TL;DR

  1. Screen inputs and outputs with moderations.create() before they reach users.
  2. Mask emails and phone numbers with maskPII() before prompting.
  3. Validate model output against a zod schema before delivery.

OpenAI Moderation API

    Content Moderation Screen

    Detect hate, harassment, self-harm, and violence.

    import OpenAI from 'openai';
    const client = new OpenAI();
    
    async function isFlagged(
      input: string
    ): Promise<boolean> {
      const mod = await client.moderations.create({
        model: 'omni-moderation-latest',
        input,
      });
      return mod.results[0]?.flagged ?? false;
    }
    Category Score Threshold Gate

    Flag inputs exceeding custom safety score thresholds.

    function checkHarassmentScore(
      result: any, maxScore = 0.5
    ) {
      const scores = result.category_scores;
      if (scores.harassment > maxScore) {
        const err = 'Input exceeds harassment threshold';
        throw new Error(err);
      }
    }
    Dual Input-Output Moderation Gate

    Moderate both incoming user prompt and outgoing model reply.

    async function safeTurn(userInput: string) {
      if (await isFlagged(userInput)) {
        throw new Error('Unsafe user input');
      }
      const answer = await callLLM(userInput);
      if (await isFlagged(answer)) {
        throw new Error('Unsafe model answer');
      }
      return answer;
    }

Personally Identifiable Information (PII) Redaction

    Regex Pattern PII Redactor

    Mask emails, phone numbers, and SSNs with placeholder tokens.

    function redactPII(text: string): string {
      const EMAIL_RE = /[^@\s]+@[^@\s]+\.[^@\s]+/g;
      const PHONE_RE = /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g;
      return text
        .replace(EMAIL_RE, '[EMAIL]')
        .replace(PHONE_RE, '[PHONE]')
        .replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]');
    }
    Credit Card Luhn Algorithm Redactor

    Detect and mask valid credit card numbers in text strings.

    function redactCreditCards(text: string): string {
      const CARD_RE = /\b(?:\d[ -]*?){13,16}\b/g;
      return text.replace(CARD_RE, '[CARD]');
    }
    PII Audit Logger

    Record redaction event without logging raw sensitive values.

    function logRedactionEvent(type: string) {
      securityMetrics.increment(
        'pii_redacted', 1, { type }
      );
    }

Output Schema Guardrails with Zod

    Strict Output Schema Assertion

    Enforce domain constraints on generated JSON outputs.

    import { z } from 'zod';
    
    const SafeOutputSchema = z.object({
      recommendation: z.string().max(200),
      riskLevel: z.enum(['low', 'medium', 'high']),
      confidence: z.number().min(0).max(1),
    });
    
    function validateOutput(rawJson: string) {
      return SafeOutputSchema.parse(JSON.parse(rawJson));
    }
    HTML Injection Sanitizer

    Escape HTML tags to prevent cross-site scripting (XSS).

    function escapeHtml(str: string) {
      return str
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
    }
    Schema Retry Fallback Handler

    Retry request with schema correction when output validation fails.

    async function getWithRetry(q: string, attempts = 2) {
      for (let i = 0; i < attempts; i++) {
        try {
          const raw = await callLLM(q);
          return validateOutput(raw);
        } catch (e) { /* retry */ }
      }
      throw new Error('Failed schema validation');
    }

Refusal Cascades & Policy Management

    Graceful Refusal Formatter

    Deliver empathetic and helpful policy refusal messages.

    function formatRefusal(reason: string) {
      const msg = `Cannot assist with ${reason}.`;
      return {
        success: false,
        message: msg,
        alternative: 'Can help with general info.',
      };
    }
    Topic Blocklist Guard

    Intercept forbidden operational topics before LLM dispatch.

    const BANNED_TOPICS = [
      'medical_advice', 'crypto_speculation',
    ];
    function checkTopic(topic: string) {
      if (BANNED_TOPICS.includes(topic)) {
        return formatRefusal(topic);
      }
    }
    Safety Telemetry Incident Hook

    Log safety violation events for compliance audits.

    function recordSafetyViolation(
      cat: string, usr: string
    ) {
      complianceLogger.warn('policy_violation', {
        category: cat,
        userId: usr,
        timestamp: new Date().toISOString(),
      });
    }

Tips

  1. Execute omni-moderation-latest checks asynchronously on streaming tokens to catch safety violations without inflating initial Time-to-First-Token latency.
  2. Mask credit cards and Social Security numbers using client-side regex filters prior to transmitting prompts across provider network boundaries.

Warnings

  1. Never display unvalidated LLM output containing user-generated HTML directly in browsers without strict HTML escaping.
  2. Avoid hardcoded naive keyword blocklists that produce frequent false positive refusals on legitimate medical or technical inquiries.

In Practice

FAQ