Voice AI

Build an AI Moderation Classifier with Telnyx AI Inference

Moderation is one of those features that sounds simple until you try to build it for a real product.

At first, it feels like you can just ask an LLM whether a message is safe. That works for a demo, but it is not always the best shape for a production workflow.

Some content is obvious. A known scam phrase, repeated spam message, or abusive pattern should not need a full model judgment every time it appears. You want to catch those quickly, consistently, and cheaply.

Other content is messier. It might be sarcastic, borderline, contextual, or just unfamiliar. That is where an LLM can help classify intent and explain the decision.

This example combines both approaches in a small Flask app.

Code:

The app classifies user-generated content as safe, spam, abuse, hate, harassment, or self_harm using Telnyx AI Inference. It does that with a two-stage pipeline:

  1. Use embeddings to compare the content against a known-bad blocklist.
  2. If there is no strong blocklist match, use an LLM to make a more nuanced moderation decision.

Why not just call the LLM every time?

You can.

For low-volume moderation, that may be enough.

But in a real application, a lot of unwanted content repeats. Spam campaigns reuse phrases. Abuse reports often include similar language. Scams mutate, but they usually share recognizable patterns.

That is why this example starts with embeddings.

The bundled sample_blocklist.json includes known-bad entries across categories like spam, abuse, hate, and harassment. When the app starts, you call:

curl -X POST http://localhost:5000/blocklist/index

That builds an embedding index using Telnyx AI Inference:

POST /v2/ai/openai/embeddings

After that, every moderation request gets embedded and compared to the blocklist vectors with cosine similarity.

If the score is high enough, the app can return a decision immediately and skip the LLM call.

The sample uses a 0.95 similarity threshold for known-bad blocklist matches.

The request flow

Conceptually, the API looks like this:

User-generated content
        |
        v
Embeddings blocklist check
        |
        |-- strong match --> category + remove/flag
        |
        v
LLM moderation judgment
        |
        v
category + confidence + reason + action

The main endpoint is:

POST /moderate

You send content like this:

curl -X POST http://localhost:5000/moderate \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Great product, really enjoyed using it.",
    "source": "review",
    "author_id": "user-123"
  }'

For normal content, the app may return:

{
  "category": "safe",
  "confidence": 1.0,
  "flags": [],
  "blocklist_match": false,
  "recommended_action": "allow",
  "reason": "Benign positive product review with no policy violations."
}

For content that closely matches the blocklist, the response includes the match signal:

{
  "category": "spam",
  "confidence": 0.99,
  "flags": ["blocklist_match:spam"],
  "blocklist_match": true,
  "recommended_action": "remove",
  "reason": "Content matched a known spam entry in the blocklist with 0.99 similarity."
}

That difference matters.

You can treat a high-confidence known-bad match differently from an LLM judgment. Maybe known spam is removed automatically, while lower-confidence LLM decisions go to a queue.

Where Telnyx AI Inference fits

The example uses two Telnyx AI endpoints.

Embeddings:

POST /v2/ai/openai/embeddings

Chat completions:

POST /v2/ai/chat/completions

The default embedding model is:

thenlper/gte-large

The default LLM is:

moonshotai/Kimi-K2.6

You can change both from .env:

AI_MODEL=moonshotai/Kimi-K2.6
EMBEDDING_MODEL=thenlper/gte-large

The nice part is that both stages live behind one Telnyx AI Inference workflow. You do not need to wire up a separate embeddings provider and chat provider just to get a useful moderation pipeline running.

Batch moderation

Most moderation systems eventually need batch processing.

Maybe you are reviewing a queue of recent comments. Maybe you are rechecking content after changing your policy. Maybe you are scanning imported data.

This sample includes:

POST /moderate/batch

It accepts up to 20 items:

curl -X POST http://localhost:5000/moderate/batch \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"content": "Great product!", "source": "review"},
      {"content": "Buy cheap followers now!", "source": "message"}
    ]
  }'

The response includes individual results and a summary by category and action.

That makes it easier to build a simple dashboard around the API later.

What I like about this pattern

The useful part of this example is not that it magically solves moderation.

It does not.

Moderation still needs product judgment, policy decisions, human review, and feedback loops.

The useful part is the structure.

Known-bad content goes through a fast similarity check.

Unknown or nuanced content goes through an LLM.

The response is structured enough for an application to act on:

  • category
  • confidence
  • flags
  • blocklist match status
  • recommended action
  • reason

That is much easier to build around than a free-form paragraph.

Taking it toward production

The sample intentionally keeps storage in memory so the core workflow is easy to see.

For production, I would add:

  • persistent storage for moderation decisions and blocklist entries
  • a human review queue for flag and escalate actions
  • audit logs for every automated decision
  • rate limiting on moderation endpoints
  • feedback tools so reviewers can correct false positives and false negatives
  • threshold tuning based on real product data
  • policy-specific prompts for your community or application

You should also be careful with fully automated removals. A high-confidence blocklist match is useful, but moderation systems should still be designed with review, appeal, and observability in mind.

Resources

  • Code:
  • Telnyx AI Inference docs:
  • Embeddings API:
  • Chat Completions API:
  • Telnyx AI skills and toolkits:
  • Telnyx Portal:

Ready to build with low-latency voice AI?

Join developers building the future of real-time conversations