ZYVOPMulti-Platform Sync
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZYVOPMulti-Platform Sync

The Developer Publishing Hub. Write once, publish everywhere, and make your work citation-ready with built-in SEO, AEO, and GEO discovery support. Zero reader paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Developer API & CLI
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

ยฉ 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls ยท Full content ownership
All systems operational
HomeAntiSlop-vLLM: Architectural Review & Integration Assessment

AntiSlop-vLLM: Architectural Review & Integration Assessment

How AntiSlop-vLLM's backtracking sampler works, and why it can't run against a Groq-backed pipeline without real per-token logprobs.

Tomson Alex
Tomson Alex
Blogger
September 6, 2026
7 min read
AntiSlop-vLLM: Architectural Review & Integration Assessment
#AntiSlop-vLLM#Groq API#LLM sampling#AI content quality#logprobs
๐Ÿ‘2

Which "anti-slop" this covers

The name is heavily overloaded right now. A quick survey turns up at least six unrelated tools sharing the branding. There's a Rust/npm linter that flags AI-generated code stubs and placeholders (skew202/antislop), a GitHub Action that auto-closes low-quality AI-generated PRs (peakoss/anti-slop), a set of design rules aimed at generic AI-generated UI (miqdadbadjuber/anti-slop), a Claude Code skill bundle focused narrowly on code-generation slop and PR hygiene (iCodeCraft/anti-slop), and a generic sampling-technique entry inside a broader PyTorch sampler library.

The one this review actually covers is sam-paech/antislop-vllm, a generation-time text-quality tool for LLM output. Your AiDraftService generates editorial blog roundups from an LLM, so this is almost certainly the one you meant, and that's the subject below. If you were actually after the code-linter or PR-gate variants, say so and I'll redo this against that repo instead.

antislop-vllm is an evolution of the original antislop-sampler. The original worked directly against local Hugging Face transformers models; this version targets remote OpenAI-compatible inference servers (vLLM, TGI, llama.cpp, and similar) instead.

What it actually does

The core idea is generate-validate-backtrack, applied at the token level during generation rather than as a pass over finished text:

  1. Text streams in from an OpenAI-compatible completions endpoint, either in fixed-size chunks or token-by-token.

  2. Each new piece of text is checked against three validator types: an exact banned-phrase list, a regex blocklist, and an n-gram frequency filter.

  3. When a validator flags a violation at a given token position, the sampler doesn't re-query the model. It re-uses the top-logprobs already returned by the API for that position and picks a different candidate token from that same distribution.

  4. The revised continuation is re-validated. This can repeat up to a configured retry limit, and a force_backtrack setting will progressively relax the sampling constraints (temperature, top-p, top-k, min-p) to widen the search for a compliant token.

  5. If no compliant alternative turns up after the retry budget, that specific violation is suppressed at that position and generation moves on rather than stalling.

flowchart TD
    A[Prompt] --> B[Request chunk/stream from /v1/completions]
    B --> C[Validators: phrase list / regex / n-gram]
    C -->|clean| D[Emit chunk, continue]
    C -->|violation| E[Pull top-logprobs for that token position]
    E --> F[Resample alternative token]
    F --> C
    F -->|retries exhausted| G[Suppress violation, emit anyway]
    D --> H{More tokens?}
    G --> H
    H -->|yes| B
    H -->|no| I[Final compliant text]

The critical detail sits in step 3, and it's the one that decides whether this tool is usable at all in a given stack: backtracking only works because the API hands back real per-token top-logprobs on /v1/completions. Without that, there's nothing to resample from. The whole mechanism collapses to "generate once, check, give up."

Project layout

  • main.py: entry point for single-prompt and batch-dataset generation.

  • core/sampler.py: ApiAntiSlopSampler, the actual generate/validate/backtrack loop.

  • state/generation_state.py: tracks the in-progress sequence, retry counts, and suppressed-violation log.

  • validators/: SlopPhraseValidator, RegexValidator, NGramValidator, each independently toggleable.

  • api_client/: thin wrapper around the OpenAI client pointed at your api_base_url.

  • banlists/: example phrase/regex/n-gram JSON files; the README is explicit that the shipped lists are starting points and effectiveness lives or dies on curating your own.

  • auto_unslop.py: an iterative outer loop: generate a batch, compare its n-gram and phrase frequencies against a human-writing reference corpus, fold the over-represented ones into the ban lists, repeat. This is the same technique used in the author's separate slop_forensics project.

Getting started

Requirements are Python 3.8+ and an OpenAI-compatible endpoint that implements /v1/completions (not just /v1/chat/completions) and returns real top-logprobs. That second part is the load-bearing one; everything below assumes you have it.

git clone https://github.com/sam-paech/antislop-vllm.git
cd antislop-vllm
pip install -r requirements.txt
cp config-example.yaml config.yaml

Edit config.yaml for api_base_url, model_name, ban-list paths, and generation defaults (max_new_tokens, temperature, top_p, top_k, min_p, chunk_size, request_mode).

Single-prompt mode, useful for iterating on ban lists:

python main.py \
    --api-base-url "http://localhost:8000/v1" \
    --api-key "xxx" \
    --model-name "Qwen/Qwen3-4B" \
    --chat-template-model-id "Qwen/Qwen3-4B" \
    --slop-phrases-file "banlists/slop_phrases.json" \
    --regex-blocklist-file "banlists/regex_not_x_but_y.json" \
    --ngram-banned-file "banlists/banned_ngrams.json" \
    --max-new-tokens 500 \
    --prompt "Write a short story about a brave knight and a mischievous dragon."

Batch dataset mode, for producing a cleaned corpus against a self-hosted vLLM backend:

vllm serve unsloth/gemma-3-4b-it --port 8000 --api-key xxx
python main.py --config config.yaml \
    --output-jsonl "results/generations.jsonl" \
    --input-hf-dataset "your/dataset" --threads 40 --max-prompts 100

OpenAI-compatible proxy mode is the integration shape most relevant to a service like yours. It fronts your backend and applies filtering transparently to any OpenAI client:

python main.py --openai-api --openai-api-port 8080 \
    --api-base-url "http://localhost:8000/v1" \
    --model-name "unsloth/gemma-3-4b-it" \
    --slop-phrases-file "banlists/slop_phrases.json"

Point your existing openai client at http://localhost:8080/v1 instead of the raw backend, and filtering happens without touching call sites.

Feasibility against your actual pipeline

Your AiDraftService generates editorial roundups through Groq, currently on openai/gpt-oss-120b after the llama-3.3-70b-versatile deprecation. I rechecked this against Groq's current API reference directly, pulling the full endpoint list rather than trusting a snippet.

The current surface is /v1/chat/completions, /v1/responses (beta), audio transcription/translation/speech, models, batches, and files. There's no /v1/completions endpoint anywhere in it. It isn't deprecated-but-present; it's just absent. Batch jobs are explicitly restricted to /v1/chat/completions too.

On the one endpoint that does exist, both request-side knobs antislop-vllm would need are called out by name as unimplemented. logprobs is marked "not yet supported by any of our models," and top_logprobs gets the identical line.

The newer /v1/responses endpoint's response schema lists a top_logprobs field, but there's no matching request parameter to set it, so that doesn't change anything here. A separate, explicitly-deprecated older Groq doc set shows a legacy /openai/v1/completions route existed at some point before the current SDK. It's gone from the docs now, and wouldn't have returned logprobs anyway.

That's a hard blocker for antislop-vllm as designed, on both counts that matter: no completions endpoint to target, and no logprobs even on the endpoint that does exist. Pointing it at Groq wouldn't degrade gracefully. It would either error out, or quietly reduce to "generate once, then suppress every violation," which is worse than not running it at all.

Two ways to actually use this against your stack

Self-host a side model. Stand up a local vLLM or llama.cpp instance serving an open-weight model, put antislop-vllm's proxy mode in front of it, and route the roundup-generation call through that instead of Groq. That's the real mechanism working as intended, with live token-level backtracking instead of a workaround.

The cost is GPU infrastructure you don't currently have, plus a second model whose editorial voice you'd need to validate separately against your existing QC standards. Given everything else runs through Vercel and managed services, this adds a genuinely new piece of infrastructure to operate rather than something you slot in quietly.

Port the technique, not the mechanism. The three validators and the auto_unslop.py corpus-comparison technique are conceptually separable from the live backtracking loop. Comparing n-gram and phrase frequency in already-generated text against a human-writing baseline doesn't need logprobs at all.

You could run that analysis offline against your own back-catalog of Groq-generated drafts, mining a project-specific banned-phrase and n-gram list (the recurring "in today's fast-paced world" and "it's important to note" style tells), independent of whether generation itself supports backtracking.

Groq won't let you resample a single flagged token, so replace token-level backtracking with response-level rejection sampling instead. Check the full draft against the banlist after generation, and on a hit, regenerate the whole response with a bumped temperature and an explicit negative instruction, rather than trying to patch one token.

That slots in next to the automated QC checks and rewrite cycles your editorial pipeline already runs. It's one more gate, not a new subsystem.

A rough shape for that gate, illustrative rather than drop-in:

// slop-guard.service.ts
@Injectable()
export class SlopGuardService {
  constructor(
    private readonly banlist: BanlistLoader,   // loads your curated phrase/regex/n-gram lists
    private readonly aiDraftService: AiDraftService,
  ) {}

  async generateClean(prompt: string, maxAttempts = 3): Promise<string> {
    let attempt = 0;
    let draft = await this.aiDraftService.generate(prompt);

    while (attempt < maxAttempts) {
      const violations = this.banlist.check(draft); // phrase / regex / n-gram hits
      if (violations.length === 0) return draft;

      attempt++;
      const nudge = `Avoid these overused phrases: ${violations.join(', ')}.`;
      draft = await this.aiDraftService.generate(`${prompt}\n\n${nudge}`, {
        temperature: this.bumpedTemp(attempt),
      });
    }

    this.logSuppressed(violations, draft); // ship it, log what got through
    return draft;
  }
}

That buys most of the practical benefit (fewer recognizably AI-flavored stock phrases in published posts) without new infra, and it fits the shape of a pipeline you've already built rather than asking you to bolt on a second inference stack.

Worth flagging, since it turned up while rechecking sources: there's already a packaged version of roughly this idea. A Claude Code skill literally named anti-slop, published by an individual ("rand," via cc-polymath on GitHub) and distributed through mcp.directory rather than Anthropic's own catalog.

It ships a detect_slop.py that scores text 0-100 against a curated phrase/pattern list, and a clean_slop.py that rewrites flagged lines, plus separate pattern references for code and design slop. It uses the same core technique as the option above, phrase matching over finished text with no logprobs involved, just pre-built rather than something you'd write yourself.

Install counts are hard to pin down. Different third-party skill aggregators (mcp.directory, vibeindex.ai, tomevault.io) list different numbers for it, none higher than the low hundreds across the whole cc-polymath repo it ships from. Single maintainer, no Anthropic involvement. I'd treat it as a reference for pattern ideas or a fork starting point, not something to pull into a production editorial pipeline unvetted.

Bottom line

antislop-vllm is well-built for what it targets, but what it targets is narrower than the name suggests. It's a generation-time sampler modification, not a general slop-detection tool, and it hard-depends on an API surface (/v1/completions with real top-logprobs) that Groq doesn't currently expose.

Don't point it at Groq directly. It won't fail loudly; it'll just quietly stop doing the thing that makes it useful.

Either take on a local vLLM instance for the real mechanism, or take the two ideas that are actually backend-agnostic (offline corpus analysis for banlist curation, and response-level rejection sampling instead of token-level backtracking) and wire those into the QC layer you already run. The second path is less exotic, and it's the one that actually fits what you've built.

Comments (0)

Login to post a comment.

Tomson Alex
Tomson Alex

Blogger

Passionate developer sharing knowledge about modern web technologies and best practices.

Subscribe to Tomson Alex's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.

More from Tomson Alex

View profile

watermarks-remover: Architecture Review & Getting-Started Guide

An architecture-focused review of watermarks-remover, examining its three-layer design, skill/service split, detection pipeline, file-format handling, security posture, optional research backends, and the important distinction between verifiable removal and best-effort rewriting.

9 minSep 4

Building a Zero-Trust Internal API on AWS

A DynamoDB table, a read-only Lambda, an API Gateway locked to IAM auth, and an EC2 client with no SSH key: a full zero-trust internal API on AWS, with working Python and Node.js signing code and a private-API hardening step.

6 minJul 26