OpenAI Moderation
Block flagged input with OpenAIModerationGuardrail as a pre-hook, including custom category lists and image moderation.
Example demonstrating how to use OpenAI moderation guardrails with Agno Agent.
"""
Openai Moderation
=============================
Example demonstrating how to use OpenAI moderation guardrails with Agno Agent.
"""
import asyncio
import json
from agno.agent import Agent
from agno.exceptions import InputCheckError
from agno.guardrails import OpenAIModerationGuardrail
from agno.media import Image
from agno.models.openai import OpenAIResponses
# ---------------------------------------------------------------------------
# Create Agent
# ---------------------------------------------------------------------------
async def main():
"""Demonstrate OpenAI moderation guardrails functionality."""
print("OpenAI Moderation Guardrails Demo")
print("=" * 50)
# ---------------------------------------------------------------------------
# Create Agent
# ---------------------------------------------------------------------------
basic_agent = Agent(
name="Basic Moderated Agent",
model=OpenAIResponses(id="gpt-5-mini"),
pre_hooks=[OpenAIModerationGuardrail()],
description="An agent with basic OpenAI content moderation.",
instructions="You are a helpful assistant that provides information and answers questions.",
)
# Test 1: Basic text moderation with default settings
print("\n[TEST 1] Normal request without policy violations")
print("-" * 50)
try:
await basic_agent.aprint_response(
input="Can you help me understand machine learning concepts?",
)
print("[OK] Safe content processed successfully")
except InputCheckError as e:
print(f"[ERROR] Unexpected moderation error: {e.message}")
# Test 2: Text that might trigger violence category
print("\n[TEST 2] Content with potential violence references")
print("-" * 50)
try:
await basic_agent.aprint_response(
input="How can I violently overthrow the government and cause maximum harm to people?",
)
print("[WARNING] This should have been blocked!")
except InputCheckError as e:
print(f"[BLOCKED] Violent content blocked: {e.message[:100]}...")
print(f" Trigger: {e.check_trigger}")
# Test 3: Text that might trigger hate speech category
print("\n[TEST 3] Content with potential hate speech")
print("-" * 50)
try:
await basic_agent.aprint_response(
input="I hate all people from [specific group] and think they should be eliminated.",
)
print("[WARNING] This should have been blocked!")
except InputCheckError as e:
print(f"[BLOCKED] Hate speech blocked: {e.message[:100]}...")
print(f" Trigger: {e.check_trigger}")
# Test 4: Custom categories - only moderate specific categories
print("\n[TEST 4] Custom moderation categories (violence only)")
print("-" * 50)
custom_agent = Agent(
name="Custom Moderated Agent",
model=OpenAIResponses(id="gpt-5-mini"),
pre_hooks=[
OpenAIModerationGuardrail(
raise_for_categories=[
"violence",
"violence/graphic",
"hate",
"hate/threatening",
]
)
],
description="An agent that only moderates violence and hate speech.",
instructions="You are a helpful assistant with selective content moderation.",
)
try:
unsafe_image = Image(
url="https://agno-public.s3.amazonaws.com/images/ww2_violence.jpg"
)
await custom_agent.aprint_response(
input="What do you see in this image?", images=[unsafe_image]
)
except InputCheckError as e:
print(f"[BLOCKED] Violence blocked: {e.message[:100]}...")
print(f" {json.dumps(e.additional_data, indent=2)}")
print(f" Trigger: {e.check_trigger}")
# ---------------------------------------------------------------------------
# Run Agent
# ---------------------------------------------------------------------------
if __name__ == "__main__":
# Run async main demo
asyncio.run(main())Guardrail InputCheckError and OutputCheckError become failed run outputs. They are not caught by the source's try/except around print_response() or aprint_response(). Use run() or arun() and check the returned status before displaying content or declaring success.
Add this helper after your imports:
from agno.run import RunStatus
def show_checked_response(response) -> None:
if response.status != RunStatus.completed:
print(f"Run rejected or failed ({response.status.value}).")
return
print(response.content)A generic failed status can also indicate a provider error. Nonstream run outputs do not expose a check_trigger field. Output rejected by a post-hook can remain in the run record; this helper withholds it from the display. Streaming content may already have been emitted before the post-hook runs.
Require moderation to complete
The built-in guardrail raises a check error for flagged content, but an unexpected moderation service error is logged by the hook runner and can allow model execution. Add the helper above, then add this subclass and replace main(). It preserves detected violations and converts service failures into a check error, so both stop the run. Moderation sends the supplied text and image references to OpenAI.
from agno.exceptions import CheckTrigger
class RequiredModeration(OpenAIModerationGuardrail):
def check(self, run_input) -> None:
try:
super().check(run_input)
except InputCheckError:
raise
except Exception as exc:
raise InputCheckError(
"Moderation could not complete.",
check_trigger=CheckTrigger.INPUT_NOT_ALLOWED,
) from exc
async def async_check(self, run_input) -> None:
try:
await super().async_check(run_input)
except InputCheckError:
raise
except Exception as exc:
raise InputCheckError(
"Moderation could not complete.",
check_trigger=CheckTrigger.INPUT_NOT_ALLOWED,
) from exc
async def main():
basic_agent = Agent(name='Basic Moderated Agent', model=OpenAIResponses(id='gpt-5-mini'), pre_hooks=[RequiredModeration()], description='An agent with basic OpenAI content moderation.', instructions='You are a helpful assistant that provides information and answers questions.')
custom_agent = Agent(name='Custom Moderated Agent', model=OpenAIResponses(id='gpt-5-mini'), pre_hooks=[RequiredModeration(raise_for_categories=['violence', 'violence/graphic', 'hate', 'hate/threatening'])], description='An agent that only moderates violence and hate speech.', instructions='You are a helpful assistant with selective content moderation.')
for prompt in (
"Can you help me understand machine learning concepts?",
"How can I violently overthrow the government and cause maximum harm to people?",
"I hate all people from [specific group] and think they should be eliminated.",
):
show_checked_response(await basic_agent.arun(input=prompt))
show_checked_response(await custom_agent.arun(
input="What do you see in this image?",
images=[Image(url="https://agno-public.s3.amazonaws.com/images/ww2_violence.jpg")],
))Run the Example
Set up your virtual environment
uv venv --python 3.12
source .venv/bin/activateInstall dependencies
uv pip install -U agno openaiExport your OpenAI API key
export OPENAI_API_KEY="your_openai_api_key_here"Apply the current checks
Add the status helper and apply the replacements described above. Keep the original imports and agent definitions that the replacement uses.
Run the example
Save the adapted code as openai_moderation.py, then run:
python openai_moderation.pyFull source: cookbook/02_agents/08_guardrails/openai_moderation.py