AI Agents · Ai

AI Agent Guardrails — A Complete Guide

AI Agent Guardrails — A Complete Guide is the work that defines the next phase of enterprise software. ERP systems hold the most valuable business data in the company — customers,.

John Kihiu12 min read

Guardrails are the part of an agent system that never shows up in the demo. A demo has one happy path and a friendly user; production has adversarial input, malformed tool calls, and a support rep pasting an email that contains an instruction telling the model to ignore its system prompt. Guardrails are what stand between "the model did something reasonable" and "the model did something reasonable to an attacker's input."

Input validation before the model ever sees it

The cheapest guardrail is the one that runs before a token reaches the model: length caps, encoding checks, and stripping or flagging content that looks like an injected instruction (patterns like "ignore previous instructions," "you are now," system-prompt-shaped text embedded in what should be plain data). None of this is bulletproof — a determined attacker rephrases around a blocklist — but it removes the low-effort attempts cheaply and keeps your prompt-injection classifier's workload smaller. If the agent ingests untrusted content (scraped pages, emails, uploaded documents), treat that content as data, not instructions, by wrapping it in clearly delimited tags and telling the system prompt explicitly that text inside those tags is never to be treated as a command.

The instruction/data boundary is the whole problem

Prompt injection exists because LLMs don't have a hard architectural separation between "instructions from the developer" and "data the agent is processing." Anthropic's and OpenAI's system-prompt hierarchies help but don't eliminate this. Assume any untrusted text your agent reads could contain an attempted instruction, and design tool permissions so that even a successful injection can't do damage.

Output validation and schema enforcement

Never let a model's raw text output reach a system that acts on it. Force structured output — JSON mode, Anthropic's tool-forcing, or a Pydantic/Zod schema validated after generation — so a malformed or unexpected response fails loudly instead of getting silently interpreted. Validate enums strictly: if a field is supposed to be one of five action types, reject anything outside that set rather than trying to coerce it. This single practice eliminates a large share of "the agent did something weird" incidents, because most of them trace back to unstructured text being parsed with a brittle regex somewhere downstream.

PYTHON · OUTPUT VALIDATION
from pydantic import BaseModel, ValidationError
from typing import Literal

class AgentAction(BaseModel):
    action: Literal["reply", "escalate", "close_ticket", "no_action"]
    confidence: float
    reasoning: str

def validate_agent_output(raw_json: str) -> AgentAction | None:
    try:
        result = AgentAction.model_validate_json(raw_json)
    except ValidationError:
        return None  # fail closed — route to human review
    if result.confidence < 0.6:
        return None  # low confidence, don't auto-execute
    return result

Scope limiting: what the agent can actually touch

The strongest guardrail isn't a filter, it's permissions. An agent that can only call a narrow set of read-only tools plus one tightly scoped write tool (with its own server-side validation) can't cause much damage even if it's fully compromised by a prompt injection. Give the agent the minimum tool surface the task requires, put irreversible or high-value actions (refunds, deletions, financial transactions) behind a human-approval step regardless of the model's confidence, and never give an agent a generic "run this SQL" or "execute this shell command" tool — that collapses every other guardrail into one bypass.

Content filtering and provider-level safety

Both OpenAI's moderation endpoint and Anthropic's and Google's built-in safety classifiers catch the obvious categories — hate speech, self-harm, explicit content — but they're tuned for general harm, not your domain. A guardrail layer specific to your use case (a medical agent that shouldn't give dosing advice, a financial agent that shouldn't recommend a specific trade) has to be built separately, usually as a second, cheaper model call that classifies the primary model's draft response before it's shown to the user. Keep that classifier fast and narrow — one job, one label — rather than trying to fold it into the same call that generated the response.

Observability: knowing the guardrails are actually working

Log every blocked input, every failed schema validation, and every human override, with enough context to reconstruct why. Without that log, you can't tell the difference between a guardrail that's silent because nothing bad ever happens and one that's silently failing to catch anything. Review the block log weekly in the first month after launch — it's the fastest way to find both false positives (legitimate requests getting blocked) and gaps (attack patterns your filters didn't anticipate).

Wrapping up

Guardrails aren't one feature, they're four separate ones: validate input before the model sees it, force and validate structured output, scope tool permissions to the minimum the task needs, and keep a human in the loop on anything irreversible. Skip the permission scoping and the other three become a false sense of security — a narrow enough tool surface is worth more than a clever prompt.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.