Astra Moderation: a self-hosted moderation API in one Go binary
Vision-LLM moderation with 15 categories, tenant keys, webhooks and Prometheus — plus the benchmark numbers and the latency trick that matters most.

On this page
Why another moderation API
Most moderation stacks are either closed SaaS with per-image pricing and no data-control story, or a thin wrapper around one NSFW classifier with no video, no policy engine and no tenancy. Astra Moderation sits in the middle: bring a vision-capable model, and the service adds what a product actually needs.
It is a single Go binary with zero third-party Go dependencies. FFmpeg and ffprobe are the only runtime requirements, and only for video.
What is inside
- 15-category taxonomy: nudity, sexual content, suggestive, violence, graphic violence, weapons, drugs, alcohol, tobacco, hate symbols, harassment, self-harm, gore, child safety, gambling.
- OpenAI-compatible POST /v1/moderations — drop-in for existing clients.
- Images and video: native video_url, with automatic ffmpeg frame sampling when the upstream disables video.
- Tenant keys, per-key RPM limits, per-tenant policy overrides, two thresholds per category.
- Async video jobs with HMAC-SHA256-signed webhooks.
- Prometheus metrics, structured logs, append-only event log.
The numbers, with caveats
Sanity benchmark on 40 explicit vs 40 benign images with Qwen3.8-27B, review threshold 0.40:
| Metric | Value |
|---|---|
| AUC | 0.988 |
| Precision | 1.00 |
| Recall | 0.97 |
| F1 | 0.99 |
| False positives | 0 / 40 |
| Latency p50 | 18.5 s (shared GPU, guided decoding) |
An extended 100-image positives-only run hit 98% recall with two misses, one label-noise case and one anime-style false negative. These are sanity checks on clean-vs-explicit data, not a production guarantee — validate on your own distribution.
The latency trick: disable thinking
Moderation is a classification task, not a reasoning task. Sending chat_template_kwargs {enable_thinking: false} cuts the token budget dramatically:
| Task | Thinking on | Thinking off |
|---|---|---|
| Short text reply | 5.5 s | 1.1 s |
| Video moderation (2 s clip) | 14.7 s | 4.3 s |
Guided JSON decoding has its own fixed overhead (~10–18 s per request on a shared GPU), independent of thinking mode. If latency matters, plan for that before blaming the model.
Running it
One command with Docker, or a Go build plus an upstream URL. The repo includes a vLLM serving example and an honest benchmark document with methodology and label caveats.
git clone https://github.com/codewith-aditya/astra-moderation cd astra-moderation && cp .env.example .env docker compose up -d --build curl -s localhost:8096/health
MIT licensed, extracted from a production gateway deployment. If you run a vision model and need moderation in front of user-generated media, this is the shortest path we know.
The artifact
Read the full source behind this post.

Aditya Wakharkar
Founder, Tantra AI Labs. Models, inference infrastructure and offensive security.