Build / AI /

Guardrails and Safety

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

TL;DR

  1. Screen toxic user inputs and completions using OpenAI moderations.create() APIs.
  2. Redact sensitive personally identifiable information via regex maskPII() filters.
  3. Validate generated outputs against strict type schemas using zod 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