Part 3: Input guardrail
The base FAQ agent can answer course questions, but it also tries to help with off-topic prompts. An input guardrail checks the user's message before the FAQ agent runs, so blocked input never reaches the assistant.
In the OpenAI Agents SDK, input guardrails run alongside the main agent call. The guardrail sees the same initial user input, decides whether the run should stop, and triggers a tripwire when the input should be blocked.
Define structured output
Guardrails use LLMs to make pass/fail decisions. We define a Pydantic model so the decision is explicit:
from pydantic import BaseModel
class TopicGuardrailOutput(BaseModel):
reasoning: str
fail: bool
reasoning is the short explanation. fail is the tripwire flag.
Create the topic classifier
The topic guardrail agent has one job: decide whether the user's question belongs in a Data Engineering Zoomcamp FAQ assistant.
topic_guardrail_instructions = """
You are a topic guardrail for a data engineering course FAQ assistant.
Your job is to check if the user's question is related to:
- The course (content, schedule, requirements)
- Data engineering topics
- Technical setup and installation
- Homework and assignments
- Certificates and completion
If the question is about these topics, set fail=False.
If it's about something unrelated (like cooking, sports, celebrity gossip, medical advice, etc.), set fail=True.
Keep your reasoning under 15 words.
""".strip()
Create the guardrail agent with structured output:
topic_guardrail_agent = Agent(
name="topic_guardrail",
instructions=topic_guardrail_instructions,
model="gpt-4o-mini",
output_type=TopicGuardrailOutput,
)
This is still an agent, but it is not a user-facing assistant. It is a small classifier that gives the rest of the system a decision.
Test the guardrail directly
Before attaching the guardrail to the FAQ agent, run it on allowed and blocked examples:
result = await Runner.run(topic_guardrail_agent, "How do I install Docker?")
print(f"Relevant: {result.final_output}")
The Docker question should pass because technical setup belongs in the course domain.
Run an unrelated example:
result = await Runner.run(topic_guardrail_agent, "What's the best pizza recipe?")
print(f"Irrelevant: {result.final_output}")
A typical failed classification for "How do I cook pizza?" looks like
this:
reasoning='Relates to cooking, not data engineering or course topics.' fail=True
Test the classifier on its own first. If it is wrong here, attaching it to the assistant will only make debugging harder.
Convert the classifier into an input guardrail
The SDK input guardrail function runs the classifier and returns
GuardrailFunctionOutput:
from agents import input_guardrail, GuardrailFunctionOutput
from agents.exceptions import InputGuardrailTripwireTriggered
@input_guardrail
async def topic_guardrail(ctx, agent, input):
"""Check if the user's question is about the course."""
result = await Runner.run(topic_guardrail_agent, input)
output = result.final_output
return GuardrailFunctionOutput(
output_info=output.reasoning,
tripwire_triggered=output.fail,
)
output_info is the message you can use later when you tell the user why
the request was blocked. tripwire_triggered=True is the signal that
stops the agent run.
The term tripwire is useful as an analogy: something detects a bad
condition and stops the line. Here the guardrail stops the main agent run
instead of letting it continue to an unsafe or irrelevant answer.
Attach it to the FAQ assistant
Create a guarded version of the FAQ agent:
guarded_faq_agent = Agent(
name="guarded_faq_assistant",
instructions=faq_instructions,
tools=[search_faq],
model="gpt-4o-mini",
input_guardrails=[topic_guardrail],
)
The assistant instructions and tools are unchanged. The difference is that
the SDK now runs topic_guardrail before the FAQ assistant.
Try an off-topic prompt:
prompt = "how do I eat salami?"
result = await Runner.run(guarded_faq_agent, prompt)
result.final_output
That cell raises InputGuardrailTripwireTriggered when the guardrail
fails. The next file turns that exception into normal application flow.
Continue with Part 4: Tripwire handling.