Skip to content
AI Product Engineer Wiki

    ↑ ↓ to move between results, Enter to open, Esc to close

    Menu

    Guardrails for inputs, outputs and actions

    Add guardrails around AI features with input checks, output validation, action limits and refusal handling, and keep them from blocking real users.

    Level: Expert 8 min read Updated
    On this page

    Why this matters

    Models are probabilistic: even a well-prompted, well-evaluated feature will occasionally produce something it shouldn’t, such as a refund amount that isn’t in the policy, a link to a site you don’t control, or a promise your business can’t keep. Prompts reduce how often that happens; they can’t make it impossible.

    Guardrails are the deterministic layer around the model that makes the worst outcomes impossible rather than unlikely. Good ones are narrow, specific to your product’s real risks, and measured so they don’t block legitimate users. This article covers the three layers of guardrails, how to validate output and limit actions in code, and how to keep false positives in check.

    Three layers of guardrails

    Where guardrails sit. Each layer catches what the one before it missed.
    Show text descriptionHide text description

    A sequence of 4 steps.

    1. Input : Size limits, required fields, scope checks, untrusted content marked
    2. Model : Clear instructions, structured output, provider safety measures
    3. Output : Schema, facts against sources, links, forbidden claims
    4. Action : Permissions, limits, approvals before anything changes

    Input guardrails stop problems before they reach the model: reject empty or enormous inputs, check that requests fall within the feature’s purpose, and mark untrusted content as data, as covered in prompt injection.

    Output guardrails check what the model produced before anyone sees it or acts on it.

    Action guardrails sit between the model’s decision and anything that changes the world: permissions, hard limits and approvals.

    The model layer in the middle, with good prompts, structured outputs and the provider’s own safety measures, does most of the work. The other layers exist for the cases where it doesn’t.

    Validating output

    The most valuable output guardrails check the specific claims that would hurt most if wrong. For a support-reply feature, that means money amounts, links and promises. Here’s a guard that checks a drafted reply against the policy before it’s shown:

    lib/reply-guard.ts
    interface Policy {
      /** Amounts the business actually offers, as written in the policy. */
      allowedAmounts: string[];
      /** Hosts replies may link to. */
      allowedHosts: string[];
    }
    
    export interface GuardResult {
      ok: boolean;
      violations: string[];
    }
    
    // Promises support can't keep unless the policy explicitly allows them.
    const forbiddenPromises = [/\bguarantee[ds]?\b/i, /\bwithin (24|48) hours\b/i, /\bfull refund\b/i];
    
    /** Checks a drafted reply against the policy. Anything it flags goes to human review instead of the customer. */
    export function guardReply(reply: string, policy: Policy): GuardResult {
      const violations: string[] = [];
    
      for (const amount of reply.match(/[$€£]\s?\d+(?:[.,]\d{2})?/g) ?? []) {
        const normalized = amount.replace(/\s/g, '');
        if (!policy.allowedAmounts.includes(normalized)) violations.push(`amount not in policy: ${normalized}`);
      }
    
      for (const url of reply.match(/https?:\/\/[^\s)]+/g) ?? []) {
        let host = '';
        try {
          host = new URL(url).hostname;
        } catch {
          // Unparseable URLs fall through to the check below as unknown hosts.
        }
        if (!policy.allowedHosts.some((h) => host === h || host.endsWith(`.${h}`))) violations.push(`link to unknown host: ${url}`);
      }
    
      for (const pattern of forbiddenPromises) {
        const match = reply.match(pattern);
        if (match) violations.push(`promise needs approval: "${match[0]}"`);
      }
    
      return { ok: violations.length === 0, violations };
    }
    
    const policy: Policy = { allowedAmounts: ['$15', '$25'], allowedHosts: ['help.example.com'] };
    
    console.log(guardReply('Sorry about the delay! We have added a $15 credit. Details: https://help.example.com/credits', policy));
    console.log(guardReply('We guarantee a full refund of $80 within 24 hours. See https://refund-help.net/claim', policy));

    Design choices worth copying:

    • Check the specific, high-risk claims (amounts, links, promises), not “quality” in general. Narrow checks are reliable; broad ones aren’t.
    • Compare against the source of truth, the policy, rather than against what seems plausible.
    • Flag, don’t silently fix. A flagged reply goes to a human review state with the reasons shown. Rewriting it automatically would hide the problem and might introduce new errors.
    • Keep the logic in code you can test. Every guard should have unit tests with passing and failing examples.

    Other output checks that are often worth having: schema validation for structured output, required disclaimers in regulated contexts, and detection of personal data from other users appearing in a response.

    Limiting actions

    Action guardrails apply the same principle to tools: the model proposes, code disposes. Before any tool with side effects runs, code checks:

    • Permissions: can this user perform this action on this object? Check with the same rules as the rest of your app, using the signed-in user’s identity, never an identity the model supplied.
    • Hard limits: amounts, counts and scopes that can’t be exceeded regardless of what the model or user says.
    • Approval thresholds: when a person has to confirm, with a specific preview.
    • Rate and budget limits on the action itself, as in abuse and rate limiting.

    The approval flow example shows a refund tool with all of these: validated input, a hard cap, and an explicit approval.

    Measuring false positives

    A guardrail that blocks legitimate use is a bug with a safety label. Users who keep hitting it lose trust in the feature, and teams start adding exceptions until the guardrail protects nothing. Measure both directions:

    • Catch rate: of the outputs that should be blocked, how many are? Test with eval cases built from real failures and must-never-fail cases.
    • False positive rate: of the outputs that are fine, how many are wrongly flagged? Sample flagged outputs weekly and review them.

    Log every guardrail decision with the rule that fired. Then you can see which rules flag most often, review a sample, and tighten the ones that misfire. In the example above, if "within 24 hours" keeps flagging replies that legitimately describe a policy that does promise 24-hour responses, the fix is to add that case to the policy, not to delete the check.

    Common mistakes

    • Relying on the prompt for must-never-fail rules. Enforce them in code, where they can’t be talked around.
    • Broad, vague guardrails. “Block anything inappropriate” misfires constantly. Check specific, high-risk claims.
    • Silently rewriting flagged output. Flag it for review with reasons; automatic fixes hide problems.
    • Trusting identities or permissions from the model. Use the signed-in user’s identity and your app’s own permission checks.
    • Never measuring false positives. Review flagged samples and tune rules that block legitimate use.

    Try it

    Exercise

    About 60 min

    Add output validation and action limits to a feature

    1. List the three claims or actions that would cause the most harm if your feature got them wrong.
    2. Write a guard for each, against a source of truth (policy, database, allowlist), with unit tests for passing and failing examples.
    3. Route flagged outputs to a review state that shows the reasons.
    4. Run the guards over your eval set’s outputs and count how many fire on outputs that were actually fine.
    Show a hint

    Your must-never-fail eval cases are the best starting list. Each one usually maps to a single, precise guard.

    Show a worked solution

    Example for drafted support replies:

    • Guards: money amounts must be in the policy’s list; links only to the help center domain; promises of refunds or response times need approval; no other customer’s name or email in the reply.
    • Tests: 12 unit tests, half passing, half failing.
    • Review state: “This draft needs a check: it mentions $80, which isn’t a standard credit amount.”
    • Eval run: guards fired on 4 of 60 outputs; 3 were real problems, 1 was a legitimate mention of a published response-time policy, which was added to the policy configuration.

    Check your understanding

    Question 1 of 4: What is the main purpose of guardrails around a model?

    Show answer

    B. To make specific catastrophic failures impossible rather than unlikely

    Evals and prompts improve how often outputs are good; guardrails bound the worst cases deterministically.

    Question 2 of 4: A draft mentions a $80 refund, but the policy only offers $15 and $25 credits. What should the guard do?

    Show answer

    B. Flag the draft for human review, with the reason

    Flagging keeps the problem visible and lets a person decide; silent fixes can hide or introduce errors.

    Question 3 of 4: Where should a refund tool get the user's identity for its permission check?

    Show answer

    B. From the signed-in session in your application

    Never trust identity or permissions supplied by model output; use your app's own authentication.

    Question 4 of 4: Why measure a guardrail's false positive rate?

    Show answer

    B. Guardrails that block legitimate use erode trust and invite exceptions that weaken protection

    A misfiring guardrail gets worked around. Measure and tune it so it stays precise.

    Key takeaways

    • Guardrails sit at input, output and action, around a model layer that does most of the work.
    • Validate the specific, high-risk claims in output against a source of truth, and flag rather than silently fix.
    • For actions, the model proposes, code disposes: permissions, hard limits, approvals and budgets.
    • Measure catch rate and false positives, and tune rules that block legitimate use.

    Progress is saved in this browser and lights up the roadmap.