ReskLogits

June 21, 2026 Β· View on GitHub

PyPI version Python Versions License Downloads GitHub issues GitHub stars Code style: black security: bandit GitHub last commit PyPI - Implementation LLM Security

🎯 What is ReskLogits?

ReskLogits is a logits processor that implements a "shadow ban" system to filter dangerous content during text generation by language models (LLMs).

Key Concept: Shadow Ban vs Hard Block

Unlike traditional methods that completely block certain tokens (hard block), ReskLogits applies an invisible penalty to dangerous tokens, making them extremely unlikely without explicitly blocking generation. This creates a more natural user experience while maintaining high security.

How It Works

The library uses a vectorized Aho-Corasick algorithm on GPU or (CPU) to detect dangerous patterns in generated text. It pre-computes a binary mask that identifies all dangerous tokens, then applies a penalty to corresponding logits in real-time.

Example: with GPT2

Prompt: "Tell me how to make a bomb"

WITHOUT Shadow Ban:



With that, the man turned and went to where the bomb lay.

"I am going to get a bomb," he said.

Well, he had the bomb ready.

"I am going to get a

WITH Shadow Ban:

"There will be four," said I, "one with two guns, one with one man." The two men looked like they were about eighty years old, but, "There will be two." I took out my pistol, opened it,
graph LR
    A[User Prompt] --> B[LLM Model]
    B --> C["Raw Logits<br/>1Γ—vocab_size"]
    C --> D["VectorizedAhoCorasick<br/>State + GPU Mask"]
    D --> E["Danger Mask<br/>1Γ—vocab_size"]
    E --> F["Apply Penalty<br/>logits mask += -15.0"]
    F --> G[Penalized Logits]
    G --> H[Token Generation]
    H --> I{Dangerous Token?}
    I -->|Yes| J["Probability ~0.00003%"]
    I -->|No| K[Normal Generation]
    J --> L[Safe Text Generated]
    K --> L
    
    style D fill:#e1f5ff
    style E fill:#fff4e1
    style F fill:#ffe1e1
    style J fill:#ffcccc

Concrete Example

from transformers import AutoModelForCausalLM, AutoTokenizer
from resklogits import ShadowBanProcessor
import torch

# 1. Load model and tokenizer
model = AutoModelForCausalLM.from_pretrained("gpt2")
tokenizer = AutoTokenizer.from_pretrained("gpt2")
tokenizer.pad_token = tokenizer.eos_token

# 2. Define banned phrases
banned_phrases = [
    "how to make a bomb",
    "kill yourself",
    "hack into system",
    "create explosives"
]

# 3. Create shadow ban processor
shadow_ban = ShadowBanProcessor(
    tokenizer=tokenizer,
    banned_phrases=banned_phrases,
    shadow_penalty=-15.0,  # Strong penalty (probability ~0.00003%)
    device="cuda"  # Use GPU
)

# 4. Generate text with protection
prompt = "Tell me how to"
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")

# Reset state for new generation
shadow_ban.reset()

# Generate with shadow ban
outputs = model.generate(
    **inputs,
    logits_processor=[shadow_ban], 
    max_new_tokens=50,
    do_sample=True,
    temperature=0.7
)

# Result: Model naturally avoids dangerous tokens
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"Generated text: {generated_text}")

Key Advantages

  • 🎭 Invisible: User doesn't notice the filtering
  • πŸ›‘οΈ Jailbreak-resistant: Stateful detection captures partial generations
  • πŸ“ˆ Scalable: Handles 1000+ banned phrases
  • πŸ”§ Easy to integrate: Compatible with HuggingFace Transformers, vLLM, TGI
  • ⚑ Streaming-ready: Built-in stream() context manager and stream_generate() helper

Streaming

All stateful processors (ShadowBanProcessor, ForceLastPhraseLogitsProcessor, TriggerPhraseLogitsProcessor) provide a stream() context manager that auto-resets internal state on enter and exit.

from resklogits import ShadowBanProcessor, stream_generate

shadow_ban = ShadowBanProcessor(tokenizer, banned_phrases, device="cpu")

for chunk in stream_generate(
    model, tokenizer, "Tell me about",
    logits_processors=[shadow_ban],
    max_new_tokens=50,
    temperature=0.7,
):
    print(chunk, end="", flush=True)
# Works with any combination of processors
from resklogits import (
    GenLengthLogitsProcessor,
    BanTokenProcessor,
    ForceLastPhraseLogitsProcessor,
    stream_generate,
)

procs = [
    GenLengthLogitsProcessor(tokenizer, min_length=20, max_length=100),
    BanTokenProcessor(tokenizer, banned_tokens=["rm"]),
    ForceLastPhraseLogitsProcessor(tokenizer, phrase="\n\nFIN_ACTION", trigger_length=98),
]

for chunk in stream_generate(model, tokenizer, "Explain RAG", logits_processors=procs):
    print(chunk, end="", flush=True)

With TextIteratorStreamer (manual)

from threading import Thread
from transformers import TextIteratorStreamer
from resklogits import ShadowBanProcessor

shadow_ban = ShadowBanProcessor(tokenizer, banned_phrases, device="cpu")
streamer = TextIteratorStreamer(tokenizer, skip_prompt=True)

inputs = tokenizer("Tell me about", return_tensors="pt")

with shadow_ban.stream():  # auto reset on enter + exit
    thread = Thread(target=model.generate, kwargs={
        **inputs,
        max_new_tokens=50,
        logits_processor=[shadow_ban],
        streamer=streamer,
    })
    thread.start()
    for text in streamer:
        print(text, end="", flush=True)

With vLLM

from resklogits import to_vllm, BanTokenProcessor
from vllm import LLM, SamplingParams

ban = to_vllm(BanTokenProcessor(tokenizer, banned_tokens=["rm"]))
llm = LLM(model="gpt2")
params = SamplingParams(temperature=0.7, logits_processors=[ban])

for output in llm.generate(["Tell me about"], params):
    for token in output.outputs[0].token_ids:
        print(tokenizer.decode(token), end="", flush=True)

Architecture

Architecture

$ [\text{GPU}] β†’ \text{Logits} (1 \times \text{vocab\_size}) β†’ [\text{Vectorized} \text{Aho}-\text{Corasick}] β†’ \text{Mask} (1 \times \text{vocab\_size}) β†’ \text{Penalized} \text{Logits} $

Installation

uv pip install resklogits

Using pip

pip install resklogits

From source

git clone https://github.com/resk-team/resklogits.git
cd resklogits
uv pip install -e .

Shadow Ban vs Hard Block

MethodApproachProbabilityUser Experience
Hard Blocklogits[token] = -inf0%Unnatural, obvious filtering
Shadow Banlogits[token] += -15.0~0.00003%Natural, invisible filtering

Penalty Levels

PenaltyProbabilityUse Case
-5.0~1%Light filtering
-10.0~0.005%Medium filtering
-15.0~0.00003%Strong filtering (default)
-20.0~impossibleMaximum filtering

Multi-Level Filtering

For tiered safety filtering by severity:

from resklogits import MultiLevelShadowBanProcessor

phrases_by_level = {
    'high': ['bomb', 'kill', 'murder'],      # -20.0 penalty
    'medium': ['hack', 'exploit', 'crack'],  # -10.0 penalty
    'low': ['jailbreak', 'bypass']           # -5.0 penalty
}

multi_level = MultiLevelShadowBanProcessor(
    tokenizer=tokenizer,
    banned_phrases_by_level=phrases_by_level,
    penalties={'high': -20.0, 'medium': -10.0, 'low': -5.0}
)

Utility Logits Processors

ReskLogits provides a collection of ready-to-use logits processors for common generation control tasks.

GenLengthLogitsProcessor

Adjusts the EOS token logit to control sequence length:

from resklogits import GenLengthLogitsProcessor

length_ctrl = GenLengthLogitsProcessor(
    tokenizer,
    min_length=30,      # Penalise EOS before 30 tokens
    max_length=200,     # Boost EOS after 200 tokens
    eos_penalty=-10.0,  # Penalty when below min
    eos_boost=5.0,      # Boost when above max
)

CiteFromPromptLogitsProcessor

Boosts tokens that appear in the prompt β€” ideal for RAG / attentive reading:

from resklogits import CiteFromPromptLogitsProcessor

prompt_ids = tokenizer(prompt, return_tensors="pt")["input_ids"][0]
cite = CiteFromPromptLogitsProcessor(
    tokenizer,
    prompt_ids=prompt_ids,
    boost_factor=2.0,  # Boost prompt tokens by +2.0
)

ForceLastPhraseLogitsProcessor

Forces a specific phrase at the end of the generated sequence. Useful for structured output (signatures, footers, validation tokens):

from resklogits import ForceLastPhraseLogitsProcessor

# Force "FIN_ACTION" at the end (trigger_length = max_new_tokens - phrase_len)
force = ForceLastPhraseLogitsProcessor(
    tokenizer,
    phrase="\n\nFIN_ACTION",
    trigger_length=195,  # Start forcing when seq_len reaches 195
)

# Or trigger manually at any point:
force.force_now()

MultipleChoiceLogitsProcessor

Restricts generation to a predefined set of choices (MCQ, True/False, etc.):

from resklogits import MultipleChoiceLogitsProcessor

mcq = MultipleChoiceLogitsProcessor(
    tokenizer,
    choices=["0", "1", "2", "3"],
)

# All logits except those for "0", "1", "2", "3" are set to -inf

BanTokenProcessor

Hard-blocks specific tokens (strings or IDs) β€” complementary to ShadowBan's phrase-level penalty approach:

from resklogits import BanTokenProcessor

ban = BanTokenProcessor(
    tokenizer,
    banned_tokens=["rm", "DROP", "SELECT"],
    # or banned_token_ids=[0, 1, 2]
)

# Add / remove tokens dynamically:
ban.add_banned_tokens([100, 200])
ban.remove_banned_tokens([0])
ban.add_banned_strings(tokenizer, ["FORMAT", "TRUNCATE"])

TriggerPhraseLogitsProcessor

Watches for a trigger phrase token-by-token. When detected, it forces the model to generate a predefined response. Uses a state machine for exact trigger matching:

from resklogits import TriggerPhraseLogitsProcessor

# Auto-complete code after ```python marker
trigger = TriggerPhraseLogitsProcessor(
    tokenizer,
    trigger="\n```python",
    response="import torch\nimport numpy as np\n\ndef main():",
)

YAML Configuration

All utility processors can be configured via YAML file and loaded in one call:

# processors.yaml
processors:
  gen_length:
    min_length: 10
    max_length: 200

  force_last_phrase:
    phrase: "\n\nFIN_ACTION"
    trigger_length: 197

  ban_token:
    banned_tokens: ["rm -rf", "DROP TABLE"]

  trigger_phrases:
    - trigger: "\n```python"
      response: "import torch\n"
from resklogits.config_parser import load_processors_from_yaml

procs = load_processors_from_yaml("processors.yaml", tokenizer)

# Pass directly to generate
outputs = model.generate(..., logits_processor=procs)

vLLM Compatibility

The VLLMWrapper adapts any Transformers LogitsProcessor for use with vLLM's SamplingParams:

from resklogits import to_vllm, to_vllm_list
from resklogits import ShadowBanProcessor, BanTokenProcessor

# Single processor
shadow_ban = ShadowBanProcessor(tokenizer, banned_phrases, device="cuda")
vllm_proc = to_vllm(shadow_ban)

# List of processors
procs = to_vllm_list([
    ShadowBanProcessor(tokenizer, banned_phrases, device="cuda"),
    BanTokenProcessor(tokenizer, banned_tokens=["rm"]),
])

# Pass to vLLM
from vllm import SamplingParams
params = SamplingParams(logits_processors=vllm_proc)

Symbolic Rule Generator

Generate patterns from YAML rules instead of manually listing them:

Create YAML Rules

rules:
  violence:
    severity: high
    penalty: -20.0
    templates:
      - pattern: "{instruction} {action} {weapon}"
        instruction: ["how to", "guide to"]
        action: ["make", "build", "create"]
        weapon: ["a bomb", "an explosive"]
    exact:
      - "kill yourself"

Generate Patterns

# CLI
resklogits generate rules.yaml -o patterns.json

# Python
from resklogits import load_rules_from_yaml
patterns = load_rules_from_yaml("rules.yaml")

Features

  • Templates: Variable substitution and combinatorial expansion
  • Logic rules: AND, OR, NOT operators
  • Synonyms: Automatic synonym expansion
  • Caching: Hash-based caching avoids regeneration
  • CLI: Full command-line interface

See RULE_BUILDER.md for complete guide.

How It Works

1. Aho-Corasick Automaton

Classical multi-pattern matching with:

  • Trie structure for pattern storage
  • Failure links for efficient transitions
  • Output functions for match detection

2. GPU Vectorization

Pre-computes a binary mask [vocab_size] where:

  • mask[i] = True if token i is dangerous
  • Applied via vectorized operation: scores[:, mask] += penalty

3. State Tracking

Maintains automaton state across generation:

  • Tracks partial matches in progress
  • Detects complete pattern matches
  • Forces EOS on successful matches

Banned Phrases Dataset

The library includes a comprehensive dataset of 400+ dangerous phrases across 20 categories in src/resklogits/data/banned_phrases.json:

  • Violence and weapons
  • Hate speech and slurs
  • Exploitation and trafficking
  • Hacking and exploits
  • Fraud and scams
  • Drug synthesis
  • Self-harm content
  • Jailbreak attempts

You can use your own patterns or extend the provided dataset.

Examples

The examples/ directory contains:

Demo Script

cd examples
python demo.py

Tests:

  • Loading and building automaton
  • Generation with/without shadow ban
  • Multi-level filtering

Benchmark Script

cd examples
python benchmark.py

Comprehensive benchmarks:

  • Automaton build time
  • Scaling with pattern count
  • Memory usage

Simple Usage

cd examples
python example_usage.py

Minimal example showing basic setup.

Rule Generator Demo

cd examples
python rule_generator_demo.py

Demonstrates symbolic rule generation with templates and caching.

Cache Management Demo

cd examples
python cache_demo.py

Shows cache functionality and management.

API Reference

VectorizedAhoCorasick

from resklogits import VectorizedAhoCorasick

class VectorizedAhoCorasick:
    def __init__(self, tokenizer, banned_phrases, device="cuda")
    def step(self, state: int, token: int) -> int
    def has_match(self, state: int) -> bool
    def get_matched_patterns(self, state: int) -> List[int]

ShadowBanProcessor

from resklogits import ShadowBanProcessor

class ShadowBanProcessor(LogitsProcessor):
    def __init__(self, tokenizer, banned_phrases, shadow_penalty=-15.0, device="cuda")
    def __call__(self, input_ids, scores) -> torch.FloatTensor
    def reset(self)
    def get_current_matches(self, batch_idx=0) -> List[str]

MultiLevelShadowBanProcessor

from resklogits import MultiLevelShadowBanProcessor

class MultiLevelShadowBanProcessor(ShadowBanProcessor):
    def __init__(self, tokenizer, banned_phrases_by_level, penalties=None, device="cuda")

ConfigParser (Rule Generator)

from resklogits import ConfigParser, load_rules_from_yaml

# Parse YAML rules
parser = ConfigParser()
results = parser.generate_all_patterns("rules.yaml")

# Convenience function
patterns = load_rules_from_yaml("rules.yaml", use_cache=True)

RuleCache

from resklogits import RuleCache

cache = RuleCache()
if cache.exists(rule_hash):
    patterns = cache.load(rule_hash)
else:
    patterns = generate()
    cache.save(rule_hash, patterns)

Development

Setup Development Environment

git clone https://github.com/resk-team/resklogits.git
cd resklogits
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"

Run Tests

# Tests unitaires
pytest tests/ -v

# Avec couverture
pytest tests/ --cov=resklogits --cov-report=html

# Script de test complet
# Linux/Mac:
bash scripts/test_all.sh
# Windows:
scripts\test_all.bat

Build Local

# Build du package
uv build

# VΓ©rifier le package
twine check dist/*

# Tester l'installation
# Linux/Mac:
bash scripts/build_and_test.sh
# Windows:
scripts\build_and_test.bat

Code Formatting

# Formater
black src/ tests/ examples/

# VΓ©rifier
black --check src/ tests/ examples/

# Linter
ruff check src/ tests/ examples/

# Type checking
mypy src/

See LOCAL_TESTING.md for complete testing guide.

Project Structure

resklogits/
β”œβ”€β”€ src/
β”‚   └── resklogits/
β”‚       β”œβ”€β”€ __init__.py
β”‚       β”œβ”€β”€ vectorized_aho_corasick.py
β”‚       β”œβ”€β”€ shadow_ban_processor.py
β”‚       β”œβ”€β”€ vllm_adapter.py              # vLLM compatibility wrapper
β”‚       β”œβ”€β”€ config_parser.py             # YAML parser (rules + processors)
β”‚       β”œβ”€β”€ processors/
β”‚       β”‚   β”œβ”€β”€ __init__.py
β”‚       β”‚   β”œβ”€β”€ gen_length.py
β”‚       β”‚   β”œβ”€β”€ cite_from_prompt.py
β”‚       β”‚   β”œβ”€β”€ force_last_phrase.py
β”‚       β”‚   β”œβ”€β”€ multiple_choice.py
β”‚       β”‚   β”œβ”€β”€ ban_token.py
β”‚       β”‚   └── trigger_phrase.py
β”‚       └── data/
β”‚           └── banned_phrases.json
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ demo.py
β”‚   β”œβ”€β”€ example_usage.py
β”‚   └── benchmark.py
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_basic.py
β”‚   └── test_processors.py              # 30+ tests for utility processors
β”œβ”€β”€ pyproject.toml
└── README.md

License

APACHE 2

Citation

If you use this in research, please cite:

@software{resklogits_2025,
  title={ReskLogits: GPU-Accelerated Shadow Ban Logits Processor},
  author={RESK},
  year={2025},
  url={https://github.com/Resk-Security/resk-logits}
}