Building Guardrails for AI Agents
One agent issued 400 refunds in an hour because nobody set a limit. AI agent guardrails are the layer that stops confident mistakes from becoming expensive ones — here's how to build them.
class SpendLimiter:
def __init__(self, per_action_max, hourly_total_max):
self.per_action_max = per_action_max
self.hourly_total_max = hourly_total_max
self.spent_this_hour = 0
def check(self, amount):
if amount > self.per_action_max:
raise GuardrailError(f"Refund {amount} over per-action limit")
if self.spent_this_hour + amount > self.hourly_total_max:
raise GuardrailError("Hourly refund budget exhausted — escalating to human")
self.spent_this_hour += amountA support agent at a subscription company issued around 400 refunds in a single hour before anyone noticed. It wasn't hacked. It wasn't even wrong, exactly — a promo email had triggered a wave of "cancel and refund me" messages, and the agent did precisely what it was built to do, at machine speed, with no ceiling. By the time a human looked, the money was gone.
That's what missing AI agent guardrails cost. Guardrails are the layer between an agent's confident decisions and the real world's irreversible consequences. Get them right and an agent can act fast without acting recklessly. Skip them and every capability you add is also a new way to lose money, leak data, or embarrass the brand.
What Are AI Agent Guardrails?
Guardrails are the constraints and checks that sit around an agent's inputs, actions, and outputs — the rules an agent cannot talk its way past. They're deliberately not part of the model. The model reasons and can be persuaded, distracted, or confused. Guardrails are plain code that runs no matter what the model decides, which is exactly why they hold when the model wanders.
They come in three layers. Input guardrails check what comes in before the agent acts on it. Action guardrails limit what the agent can actually do — how much, how often, to whom. Output guardrails validate what comes out before it reaches a user or another system. You want all three, because each catches failures the others miss.
Here's an action guardrail that would have stopped the refund flood:
[object Object], ,[object Object],:
,[object Object], ,[object Object],(,[object Object],):
,[object Object],.per_action_max = per_action_max
,[object Object],.hourly_total_max = hourly_total_max
,[object Object],.spent_this_hour = ,[object Object],
,[object Object], ,[object Object],(,[object Object],):
,[object Object], amount > ,[object Object],.per_action_max:
,[object Object], GuardrailError(,[object Object],)
,[object Object], ,[object Object],.spent_this_hour + amount > ,[object Object],.hourly_total_max:
,[object Object], GuardrailError(,[object Object],)
,[object Object],.spent_this_hour += amountWhat this does: it enforces both a per-refund cap and an hourly total budget in plain code, so no prompt, jailbreak, or unlucky email wave can push spending past a hard limit.
Why AI Agent Guardrails Matter
The core reason is speed. A human making 400 refund decisions would slow down, notice the pattern, and stop to ask a question. An agent won't — it applies the same logic to the four-hundredth case as fast and as blindly as the first. Speed is the whole point of an agent, and it's exactly what turns a small mistake into a large one without any pause for doubt.
The second reason is that models are steerable, and not always by you. A prompt-injection buried in a document, a confusingly worded request, an edge case nobody imagined — any of these can push a model off its intended path. Guardrails don't try to make the model unfoolable. They accept that it can be fooled and put hard limits outside it, where persuasion doesn't reach.
Three quick scenarios show the range. A fintech company caps the dollar value and daily count of any automated transaction, so a compromised or confused agent can't drain an account. A healthcare startup runs output guardrails that block any response containing patient identifiers from leaving the system, regardless of what the model intended. A marketing agency validates every agent-generated post against a banned-claims list before it can be scheduled, so no agent ever promises a result the legal team hasn't cleared.
⚡ Pro tip: Write guardrails as code that runs outside the model, never as instructions inside the prompt. "Please don't refund more than $500" is a suggestion a model can be talked out of. A function that raises an error at $501 is a wall. Only one of those survives a determined edge case.
Building Input and Action Guardrails
Input guardrails are your cheapest defense because they stop bad work before it starts. Validate structure, check for injection patterns, and confirm the request is even in scope before the agent spends a token on it.
[object Object], ,[object Object],(,[object Object],):
,[object Object], ,[object Object],(request) > ,[object Object],:
,[object Object], GuardrailError(,[object Object],)
,[object Object], re.search(,[object Object],, request, re.I):
,[object Object], GuardrailError(,[object Object],)
,[object Object], ,[object Object], looks_in_scope(request):
,[object Object], ,[object Object],
,[object Object], requestWhat this does: it rejects oversized inputs, flags a common injection phrasing, and turns away out-of-scope requests before the agent runs — cutting off whole categories of misuse at the door.
Action guardrails are the ones that save you real money and reputation. Every tool an agent can call needs limits: how much it can spend, how many times it can act per window, which records it's allowed to touch, and which actions require a human's sign-off. The spend limiter above is one example; rate limits, allow-lists, and approval gates are the others.
Action guardrails also have to be stateful to be worth much. A per-call limit is easy; the hard and important part is limits across calls — total spend this hour, total records touched this session, total emails sent today. Stateless checks catch the single outrageous action but miss the slow drip of many small ones that add up to the same damage. The refund flood was death by a thousand reasonable-looking cuts, each of which sailed through a per-action check without complaint, because nothing was keeping a running total.
⚡ Pro tip: Make the highest-risk actions require explicit human approval, but keep that list short. If everything needs approval, you've built a form, not an agent, and people will start rubber-stamping. Reserve the human gate for the irreversible and expensive — refunds over a threshold, data deletion, external emails to customers.
⚡ Pro tip: Give every guardrail a clear, logged failure message that names what tripped and why. When an agent stops, "hourly refund budget exhausted — escalating" tells the on-call engineer exactly what happened. A silent block or a generic error just moves the confusion downstream.
Building Output Guardrails and a Kill Switch
Output guardrails are your last line before an agent's words or actions reach the world. Validate format, scan for sensitive data, and check claims against policy before anything ships. For a customer-facing agent, that might mean confirming the response contains no internal IDs, no unhedged legal claims, and nothing that contradicts the knowledge base.
Above all of it, build a kill switch — one flag that halts every agent instantly. When something goes wrong at 3 a.m., you want a single switch a human can flip, not a frantic hunt for the right service to restart.
[object Object], ,[object Object],(,[object Object],):
,[object Object], kill_switch.active():
,[object Object], GuardrailError(,[object Object],)
,[object Object], g ,[object Object], guardrails:
g.check(action)
,[object Object], action.execute()What this does: it checks a global kill switch first, runs every guardrail second, and only then lets an action execute — giving you one place to stop everything and one place every action must pass through.
Output guardrails deserve one extra habit: fail closed, not open. When an output check itself errors — the validator throws, the policy service is unreachable — the safe default is to block the response and escalate, never to let it through unchecked. A healthcare startup learned this when their identifier scanner timed out under load and the fallback quietly shipped unscanned responses for an hour. A guardrail that disappears the moment it's under stress is worse than none at all, because you've stopped watching for the exact failure it was built to catch, and you don't know it.
⚡ Pro tip: Instrument your guardrails so a spike in trips pages a human. A sudden jump in blocked actions usually means one of two things — an attack, or a legitimate change in traffic your limits are now wrongly rejecting. Both need a person to look, and both are invisible if guardrail trips only ever land silently in a log nobody reads until the postmortem.
Common Mistakes
⚠️ Common mistake: Putting your guardrails inside the prompt and calling it done. Prompt-based limits are guidance the model can be argued out of by a clever input. Real guardrails live in code the model can't edit, on the path every action has to travel. If a guardrail can be defeated by rephrasing the request, it was never a guardrail.
The second common error is guarding inputs and outputs but forgetting actions — the layer in the middle where the actual money and data live. The refund flood happened not because the input was malicious or the output was ugly, but because no limit sat on the action itself.
The third is building guardrails with no observability. If a guardrail blocks something and nobody logs it, you can't tell whether it's protecting you or quietly breaking legitimate work. Every trip should be recorded and reviewable.
⚡ Pro tip: Rehearse a failure on purpose. Once a quarter, deliberately trip your kill switch and your key guardrails in a safe environment. A guardrail you've never watched fire is a guess, not a guarantee — the day you need it is the wrong day to learn it doesn't work.
Conclusion
AI agent guardrails are what let you give an agent real power without holding your breath. Layer them across inputs, actions, and outputs; keep them in code rather than prompts; log every trip; and put a single kill switch over the whole thing. Speed is the reason agents are worth building and the reason they're dangerous without limits — guardrails are how you keep the first without the second.
The good news is that guardrails are highly reusable. The spend limiter, injection check, and output validator you write once will fit the next agent with light edits. Teams that keep these patterns in a shared library like PromptABCD ship new agents faster because safety is something they assemble from proven parts, not rebuild under pressure after the first expensive surprise.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
