Hemil087/content_moderation_env
Content Moderation Environment
An OpenEnv environment where an LLM agent reviews social media posts, retrieves precedent cases, and makes moderation decisions under platform policy constraints.
HF Space: https://hemil087-content-moderation-env.hf.space
Overview
Content moderation is one of the hardest real-world challenges facing social media platforms. Moderators must balance free expression against harmful content, handle ambiguous edge cases, and maintain consistency across millions of decisions. This environment simulates that task for LLM agents.
The agent receives a reported post with rich metadata (author history, engagement metrics, reporter credibility, automated classifier scores), the platform's community policy, and access to a database of 20 precedent cases. It must decide whether to remove, allow, label, escalate, or (for appeals) overturn/uphold prior decisions.
Tasks
Episodes are selected via episode_index in reset options (default: 0). Each episode has deterministic grading — no randomness in scoring.
Action Space
from models import ContentModerationAction
# Retrieve precedents
action = ContentModerationAction(
action_type="retrieve_precedents",
query="hate speech dehumanizing ethnicity"
)
# Make a final decision with reason (citing policy clause improves score)
action = ContentModerationAction(
action_type="remove_content",
reason="Dehumanizing language targeting protected ethnic group"
)Observation Space
After each step, the agent receives:
Post Metadata Fields
Each post includes realistic Trust & Safety queue metadata:
Reward Structure
Final episode score is clamped to 0.0–1.0.
Maximum achievable score: 0.90 (retrieve relevant + correct decision + relevant precedent bonus + policy clause citation)
Adjacent action pairs that receive reduced penalty (-0.15 instead of -0.30):
remove_content↔add_warning_labelallow_content↔add_warning_labeloverturn_removal↔allow_contentuphold_removal↔remove_content
Quick Start
Install
pip install openenv-core
pip install git+https://huggingface.co/spaces/Hemil087/content_moderation_envUse (Sync)
from client import ContentModerationEnv
from models import ContentModerationAction
with ContentModerationEnv(base_url="https://hemil087-content-moderation-env.hf.space").sync() as env:
result = env.reset(options={"task_id": "easy"})
print(result.observation.post_content)
# Retrieve precedents
action = ContentModerationAction(
action_type="retrieve_precedents",
query="hate speech dehumanizing"
)
result = env.step(action)
print(result.observation.precedents)
# Make final decision
action = ContentModerationAction(
action_type="remove_content",
reason="Dehumanizing language targeting protected group"
)
result = env.step(action)
print(f"Score: {result.reward}, Done: {result.done}")Use (Async)
import asyncio
from client import ContentModerationEnv
from models import ContentModerationAction
async def main():
async with ContentModerationEnv(base_url="https://hemil087-content-moderation-env.hf.space") as env:
result = await env.reset(options={"task_id": "medium"})
print(result.observation.post_content)
asyncio.run(main())Running Inference
The baseline agent uses an LLM via the OpenAI-compatible API:
export HF_TOKEN=your_hf_token_here
export API_BASE_URL=https://router.huggingface.co/v1
export MODEL_NAME=Qwen/Qwen2.5-72B-Instruct
python inference.pyBaseline Scores
Model: llama-3.3-70b-versatile via Groq
Local Development
# Clone and install
git clone https://github.com/Hemil087/content-moderation-env.git
cd content-moderation-env
pip install -e .
# Start server
uvicorn server.app:app --reload
# Test endpoints
curl http://localhost:8000/health
curl -X POST http://localhost:8000/reset -H "Content-Type: application/json" \
-d '{"options": {"task_id": "easy", "episode_index": 0}}'Project Structure
content-moderation-env/ ← repo root = environment root
├── openenv.yaml # Environment manifest
├── pyproject.toml # Package config
├── uv.lock
├── models.py # Action + Observation definitions
├── client.py # WebSocket client
├── __init__.py
├── README.md
├── inference.py # LLM agent script
└── server/
├── app.py # FastAPI application
├── content_moderation_env_environment.py # Core environment logic
├── __init__.py
├── Dockerfile
└── requirements.txtEnvironment Design
Precedent Database
20 fixed precedent cases covering hate speech, political criticism, satire, news reporting, graphic content, and more. Precedents are retrieved via keyword search — deterministic, no external API calls.
Grading
All grading is deterministic (pure Python, no LLM calls). The grader checks:
- Was the final action correct?
- Did the agent retrieve relevant precedents?
- Did the agent cite the correct policy clause in their reason?
- Did the agent provide a reason at all?
Precedent Conflict Detection
When retrieved precedents have conflicting decisions (e.g., one says "allowed", another says "removed"), the environment flags this in the message, forcing the agent to reason about which precedent applies.
License
BSD 3-Clause License
