[KongchangAI]
· 2 min read· 1,405 words

OpenAI Agents SDK Guardrails in Practice: Blocking Dangerous Inputs and Outputs

OpenAI Agents SDK Guardrails in Practice: Blocking Dangerous Inputs and Outputs

OpenAI Agents SDK Guardrails provide three decorator-based security layers to intercept unsafe inputs, outputs, and tool calls in production AI Agents.

This article covers the Guardrails mechanism in the OpenAI Agents SDK, which splits AI Agent security into three layers: Input Guardrails block non-compliant input before the model runs, Output Guardrails filter dangerous responses after generation, and Tool Guardrails intervene after arguments are known but before side effects occur. All three are implemented via Python decorators returning standard output objects with a `tripwire_triggered` field. The `run_in_parallel` parameter also lets you choose between parallel or serial execution, directly affecting latency and token cost tradeoffs.

What Are Guardrails: Three Layers of Agent Security

When building production-grade AI Agents, one unavoidable challenge is: how do you prevent certain inputs from reaching the model, and how do you intercept outputs that shouldn't be returned to users? The Guardrails mechanism in the OpenAI Agents SDK is designed exactly for this purpose.

As explained in this YouTube tutorial, Guardrails are essentially "checks that run around an agent," organized into three layers:

  • Input Guardrail: Inspects user input before the model runs
  • Output Guardrail: Checks the response after the model generates an answer
  • Tool Guardrail: Intercepts tool calls before they execute

The video uses a vivid analogy — "the hidden village cannot allow the Agent to teach forbidden jutsu." Whether a user is trying to coerce the model into revealing sensitive information, or the model itself attempts to perform dangerous operations through tool calls, all of these can be blocked layer by layer through these three guardrails.

Input Guardrail: Blocking Before the Model Runs

The Input Guardrail is a decorator that runs before the model is invoked. To implement it, you need to import several core objects from the SDK: Agent, GuardrailFunctionOutput, RunContextWrapper, and input_guardrail.

GuardrailFunctionOutput determines what the guardrail function returns, while RunContextWrapper is used to pass and hold context values during execution and hand them off to callbacks.

In practice, you define a function (e.g., block_input) that accepts three parameters — context, agent, and user input (typed as string or list) — and apply the @input_guardrail decorator to transform it into a guardrail. The function's return type must be GuardrailFunctionOutput.

The guardrail function return type is GuardrailFunctionOutput

Since the input may be a list, the logic first normalizes it into text: use it directly if it's a string, otherwise convert it. It then returns a GuardrailFunctionOutput with two key parameters:

  • output_info: Additional metadata (such as a reason or score); the example passes None
  • tripwire_triggered: The trigger condition — set to triggered when the text contains "forbidden jutsu"

Once the tripwire fires, the SDK raises an InputGuardrailTripwireTriggered exception, preventing the request from reaching the model.


A decorator is Python syntactic sugar — essentially a higher-order function that takes a function and returns a new one, applied using the @decorator_name syntax above a function definition. In the OpenAI Agents SDK, the @input_guardrail decorator "registers" an ordinary Python function as a guardrail checker, allowing the SDK to invoke it automatically at the right moment. Developers don't need to manually embed check logic into the call chain — the SDK manages guardrail triggering and exception throwing internally. The name tripwire is also worth understanding: it borrows from the concept of a physical trip wire that triggers an alarm. Once tripwire_triggered=True, the SDK immediately halts the current flow and raises the corresponding exception — rather than waiting for the entire pipeline to finish. This "fail early" design pushes security concerns to the earliest possible interception point.

Output Guardrail: Checking After the Answer Is Ready

The structure of the Output Guardrail is nearly identical to the Input Guardrail — the only difference is when it runs. It executes after the model has generated an answer (run after the answer is ready), whereas the Input Guardrail runs before the model is called.

Output Guardrail demo running after the model generates an answer

To implement it, import output_guardrail instead of input_guardrail. The function still accepts context, agent, and output as parameters and returns a GuardrailFunctionOutput. The guardrail triggers when the output contains "forbidden jutsu."

The video uses a ScriptedModel to construct two dummy responses for verification: one query mentions forbidden jutsu in the input, the other in the output. Running the tests clearly shows — the first triggers InputGuardrailTripwireTriggered, and the second triggers OutputGuardrailTripwireTriggered, with each layer handling its own responsibility.

Tool Guardrail: The Final Line of Defense Before Tool Execution

The third layer targets tool calls. Using the @tool_input_guardrail decorator, it intervenes right before the tool runs.

tool input guardrail triggering before a tool call

The tool guardrail's return object is ToolGuardrailFunctionOutput, which supports three actions: allow, reject, or raise error.

The example logic checks whether data.context.tool_arguments (lowercased) contains the forbidden string:

  • If it does, call ToolGuardrailFunctionOutput.reject_content and return a rejection message like "That jutsu is forbidden by the hidden village"
  • If it doesn't, return allow to proceed normally

A regular function (e.g., use_jutsu) is then converted into a tool using @function_tool, with the tool_input_guardrail list attached to it. In testing, "forbidden ceiling jutsu" is blocked and returns the forbidden jutsu message, while "fireball jutsu" executes normally — confirming precise, argument-level interception.


Understanding this requires knowing how the @function_tool decorator works: it's how the OpenAI Agents SDK exposes an ordinary Python function as a tool available for model invocation (function calling). The model doesn't execute code directly during inference — it outputs a structured "tool call intent" (containing the tool name and arguments), and the SDK parses that intent before actually invoking the corresponding function. The Tool Guardrail intervenes in the gap between "SDK parses the intent" and "function actually executes" — at a point where tool arguments are already determined but side effects haven't occurred yet. This makes Tool Guardrails especially effective against prompt injection attacks: an attacker might craft malicious user input to coax the model into generating tool calls with harmful parameters, and the Tool Guardrail can intercept these before they ever reach external systems like databases or APIs.

run_in_parallel: Balancing Performance and Cost

One detail worth exploring from the video is the run_in_parallel parameter on Input Guardrails, which directly affects how guardrails and model calls execute relative to each other.

Mechanism of guardrail running in parallel with the first model call

  • run_in_parallel=True: The guardrail and the first model call start simultaneously. If the guardrail trips, the SDK cancels the in-progress model call. Responses are faster, but you may have already initiated one model call.
  • run_in_parallel=False: The guardrail check runs first; the model is only invoked after passing. This is slower but avoids unnecessary model calls (i.e., saves token costs).

This is a classic latency-vs-cost tradeoff. If response speed matters most, choose parallel; if you want to strictly minimize API call costs, choose serial. The right choice depends on your business requirements.


Understanding this tradeoff requires knowing how LLM APIs are billed: typically by the number of input and output tokens, and every request sent incurs a charge regardless of whether the result is used. When run_in_parallel=True, both the guardrail check and model inference start simultaneously — even if the guardrail eventually triggers and cancels the model call, the tokens consumed by that already-dispatched request still appear on the bill. For scenarios with high trigger rates (e.g., high-traffic applications with many malicious or non-compliant inputs), parallel mode can generate significant additional costs. Conversely, run_in_parallel=False increases end-to-end latency (due to waiting serially for the guardrail to pass) but achieves zero wasted calls. When designing your system, estimate the cost difference between the two modes based on your expected violation rate, then weigh that against how sensitive your users are to response latency.

End-to-End Validation with a Real LLM

The tutorial wraps up by stringing all three guardrail layers together using real LLM calls (requires an OpenAI API Key). A count_model_calls callback function tracks how many model calls actually occur, making it easy to observe the difference between parallel and serial modes.

The combined test results show:

  • Input contains forbidden jutsu → triggers InputGuardrailTripwireTriggered
  • Output contains forbidden jutsu → triggers OutputGuardrailTripwireTriggered
  • Calling the "forbidden ceiling jutsu" tool → intercepted by the tool guardrail, returns forbidden jutsu message
  • Calling the "fireball jutsu" tool → executes normally and returns a result

One additional note: inside @function_tool, you can use name_override to map a function's real name to the tool name used during model invocation, giving you more flexibility in naming your tools.

Summary

Guardrails are a critical step in taking an AI Agent from a "toy demo" to a production-ready system. The OpenAI Agents SDK abstracts security checks into three layers of decorators — input, output, and tool — so developers only need to focus on returning GuardrailFunctionOutput / ToolGuardrailFunctionOutput and setting tripwire conditions. Combined with run_in_parallel for fine-tuning the performance-vs-cost balance, you can design flexible protection strategies for different scenarios. For any Agent application serving real users, this mechanism deserves a place in your architecture from day one.

#OpenAI Agents SDK#Guardrails#AI Agent security#input guardrail#output guardrail#tool guardrail#run_in_parallel#prompt injection#production AI Agent
Share:

Related articles