Guardrails and output handling

Guardrails are the controls that sit around a model rather than inside it. Training changes what a model tends to do, and a guardrail is a separate component inspecting what went in and what came out, which is why it can be changed without retraining anything.

On the way in

Request classification decides what kind of request this is before the model sees it, meaning support question, code request, medical advice or something outside the product. Routing out of scope requests to a fixed response is cheaper and more reliable than a paragraph of prompt asking the model to stay on topic.

Topic and jailbreak detection looks for categories you have decided not to serve and shapes that try to override your instructions, meaning roleplay framings, encoded text and instructions buried in a pasted document. It is pattern matching against somebody who can rewrite their attempt, so treat it as reducing volume rather than closing a door.

Rate limiting belongs here too and gets forgotten, because it is not about content. It bounds how many attempts one caller gets, which makes an attack needing a hundred rephrasings not worth mounting.

On the way out

Content filtering applies the same categories in reverse, assuming something got through.

Schema validation checks the response is the shape your code expects. If you asked for an object with three fields, parse it, confirm the fields exist and hold the types you assumed, and reject anything else.

Grounding checks compare the response against the sources it was meant to use. Where every claim should trace to a retrieved passage, verifying that citations exist and contain what was attributed to them catches confident invention no content filter can see.

Refusal of malformed responses is the step teams skip. What happens when validation fails is part of the design, whether that means one retry, a fixed fallback or escalation to a person. A system with nothing decided here has undefined behaviour rather than none.

Improper output handling

This is the failure practitioners get wrong most often. It happens when model output reaches something that executes it, meaning a template that renders it, a parser, a database driver, a shell, a browser or a tool call.

Treat model output as untrusted user input, because that is what it is. It was produced from text including a user's request and probably a retrieved document, so anybody who can influence either can influence the output.

In practice that means escaping before rendering, so markup in a response is displayed rather than executed. It means validating before parsing rather than parsing and hoping, never concatenating a response into a query, a shell command, a file path or a request URL, and using parameterised calls instead. And it means constraining the model to a schema and checking the parsed values against an allowed set, rather than trusting free text that looked sensible in testing.

Layers, and where the boundary actually is

Guardrails are probabilistic. Each has a threshold somebody tuned, and tightening it trades false negatives for false positives on real users. Layering helps, since an attack has to survive every layer, and it still does not turn a probability into a boundary.

The boundary is permissions. What the system can do when a guardrail fails is decided by the credentials the code runs with, the scope of the tools an agent may call, and whether its account can write as well as read. A model talked into requesting a deletion deletes nothing if its token is read only. Design so the worst case of a guardrail failure is a bad answer rather than a bad action.

Managed guardrail services exist on every platform, including Guardrails for Amazon Bedrock, Azure AI Content Safety, and Model Armor alongside the safety filters on Google's Agent Platform, with open source options such as Llama Guard and NeMo Guardrails running wherever you host. None does the escaping, the schema checks or the permission scoping, which live in your application.

Practise this

You need one real response from a feature you run, fifteen minutes, and Python for the second half.

Take that response and trace it. Write down every place your application passes it onward unchecked, including rendering it in a page, writing it to a log, using a field as a key, and handing it to a tool. Then run this and watch a polite response fail three checks.

import html, json, re

raw = '{"answer": "<b onmouseover=x>hello</b>", "ticket_id": "42 or 1=1"}'

ALLOWED = {"answer", "ticket_id"}
try:
    data = json.loads(raw)
except json.JSONDecodeError:
    raise SystemExit("malformed, refuse")

if set(data) != ALLOWED:
    raise SystemExit("unexpected fields, refuse")
if not re.fullmatch(r"[0-9]{1,10}", data["ticket_id"]):
    raise SystemExit("ticket_id is not an id, refuse")

print(html.escape(data["answer"]))

What to look for. The payload is inert and the response is inoffensive, so no content filter would have objected. Every check that fires is about shape and destination rather than tone, and the one that matters on your own list is wherever a response reaches something that runs, queries or renders.

It teaches that the useful question is never whether the output was offensive but what your code does with it next.

Common misconceptions

A guardrail blocks the attack.

Every guardrail is a classifier or a rule with a false negative rate, and an attacker gets to rephrase until something passes. Layering them lowers the rate and never reaches zero, which is why the thing that actually bounds the damage is the permission the code holds.

The model refused, so the output was safe.

Safety of content and safety of handling are separate questions. A polite, accurate, entirely inoffensive response can still carry markup, a command fragment or a field your code trusts, and the harm lands in whatever consumes it rather than in what the user reads.

Asking for JSON gets you JSON.

Usually, which is the problem, because the failure is rare enough to reach production untested. Structured output modes and constrained decoding raise the rate and do not remove the need to parse defensively, check the fields and decide what happens when the parse fails.

Where this is examined
AI Safety Practitioner
Controls and Safeguards Around a Model, 23 per cent of the exam.
Related material
Book
Threat Modeling: Designing for Security, On trust boundaries and where untrusted input enters.
Book
AI Engineering, On the controls that sit around a model in production.
Template
Launch checklist, Everything that has to happen from two weeks out to one week after release, grouped by when it falls due, each line with a named owner and a go or no go decision on the day.
Concepts