Comment moderation with AI: Python example

Spam, insults, ads, genuine comments — the model labels them and sends unclear cases to a moderator. Here's the code and what it costs.

3 min · · development · бизнес

Moderating comments by hand is tedious: every comment needs a read and a decision — fine, spam, insult, or ad. With thousands of comments a day the queue grows faster than anyone can clear it. Below is an API-based auto-moderation setup with a review queue for borderline cases, batch processing, and honest cost math.

How moderation works

Each comment gets a label:

  • ok: normal comment, publish.
  • spam: obvious spam, delete.
  • insult: insult, hide.
  • ads: advertising, delete.

Plus a confidence value. If the model is unsure (confidence below a threshold), the comment goes to a moderator queue. Automation takes the obvious cases, a human decides the borderline ones.

Fast moderation with glm-5.3-flash

Start with Zukko's cheapest model — glm-5.3-flash ($0.04/$0.04 per 1M tokens). Whether it fits your comments, we'll check below on a labeled sample.

bash
import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.zukko.pro/v1",
    api_key="fetch_your_key",
)

LABELS = ["ok", "spam", "insult", "ads"]

SYSTEM_PROMPT = """You are a comment moderator. Judge the comment and pick a label.

Labels:
- ok: normal comment, publish

Routing: automatic or to a human

Not every case is clear. If confidence is below the threshold, the comment goes to a moderator:

bash
ACTIONS = {"ok": "publish", "spam": "delete", "insult": "hide", "ads": "delete"}

def route_comment(text: str, threshold: float = 0.8) -> dict:
    """Decide: publish, delete, or send for review"""
    result = moderate_comment(text)
    confidence = float(result.get("confidence", 0))
    if confidence < threshold or result["label"] not in ACTIONS:
        return {
            "action": "manual_review",
            "suggested_label": result["label"],
            "confidence": confidence,
            "reason": result.get("reasoning", ""),
        }
    return {"action": ACTIONS[result["label"]], "label": result["label"], "confidence": confidence}

if __name__ == "__main__":
    for comment in ["Great article!", "Maybe this is an ad, maybe not", "SPAM!!!!"]:
        print(comment, "->", route_comment(comment)["action"])

The model sets confidence itself; it is not a calibrated probability. A threshold of 0.8 is a starting point; tune your own on a sample where people have already assigned the correct labels.

Batch processing: dozens of comments per request

For an overnight pass or an archive cleanup, send comments in batches of 20–50. Ask the model to return the comment number so answers don't get mixed up:

bash
def moderate_batch(comments: list[str], model: str = "glm-5.3-flash") -> dict[int, dict]:
    """Moderate a batch of comments, return {number: result}"""
    batch_text = "\n---\n".join(f"Comment {i}:\n{c}" for i, c in enumerate(comments, 1))
    system_for_batch = SYSTEM_PROMPT + """
You received several comments. For EACH one output a single line of JSON:
{"id": <comment number>, "label": "...", "confidence": 0.9}
One line per object, no extra text.
"""
    response = client.chat.completions.create(
        model=model,
        max_tokens=60 * len(comments) + 100,
        messages=[
            {"role": "system", "content": system_for_batch},
            {"role": "user", "content": batch_text},

Moderator queue

Low-confidence comments pile up in a separate queue. A moderator confirms or corrects the decision:

bash
class ModerationQueue:
    def __init__(self):
        self.items = []  # in a real project, a database table

    def add(self, comment_id: str, text: str, suggestion: dict):
        self.items.append({
            "id": comment_id,
            "text": text,
            "suggestion": suggestion,  # what the model proposed
            "status": "pending",
        })

    def resolve(self, comment_id: str, final_label: str):
        """The moderator made a decision"""

Store the moderator's final decision together with the model's suggestion: these pairs become a labeled sample for re-measuring accuracy and tuning the threshold.

Cost

Estimate for 10,000 comments per month on glm-5.3-flash, averaging 200 input and 50 output tokens per comment:

(10,000 × 200 × 0.04 / 1M) + (10,000 × 50 × 0.04 / 1M) = $0.08 + $0.02 = $0.10 per month

If you re-check borderline comments on claude-sonnet-5 ($0.30/$0.30), every thousand re-checks adds 1,000 × 250 × 0.30 / 1M = $0.075. What share ends up borderline depends on your site and threshold — measure it on your own data.

Current prices and models: GET https://api.zukko.pro/v1/models or the Models page in your dashboard.

Set up the key

Create a key in the Zukko dashboard, allow only the models you need, and set a monthly limit — $1 comfortably covers 10,000 comments. See also the quick start and Python examples.

FAQ

How often should the queue be reviewed?

It depends on the site. Where comments appear immediately and reaction time matters (news, social), the queue is cleared during the day. For forums and blogs, once or twice a day is enough.

Can the model learn from moderator decisions?

Not by itself. But you can add moderator decisions to the prompt as examples ("a comment like this is ads") and periodically re-measure accuracy. If accuracy drops, route borderline cases to another model and compare results on the same sample.

What about comments in several languages?

Say in the prompt that comments may be in different languages, and add examples in each language to your test sample. Compare the accuracy of glm-5.3-flash and claude-sonnet-5 on those examples — that tells you whether you need the pricier model.

Should I moderate old comments?

If the archive was never checked, batch processing lets you go through it cheaply: 10,000 comments on glm-5.3-flash cost about $0.10.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

Comment moderation with AI via API: Python example · Zukko