Model-agnostic LLM output degeneration detector — 4-signal composite scoring in a single pass.
pip install llm-degen-guardfrom degen_guard import DegenGuard
# Batch check
report = DegenGuard.check("Some LLM output text...")
print(report.is_degenerate, report.composite_score)
# Streaming check
guard = DegenGuard()
for chunk in llm_stream:
is_degen, score = guard.feed(chunk)
if is_degen:
print(f"Degeneration detected! score={score:.2f}")
breakFour independent signals are combined into a single composite score (0.0 = normal, 1.0 = degenerate):
| Signal | Weight | What it measures |
|---|---|---|
| N-gram diversity | 0.35 | Distinct 3-gram ratio — low diversity = repetitive |
| Compression ratio | 0.30 | zlib compression ratio — highly compressible = repetitive |
| Substring match | 0.20 | Exact overlap between first/second half of window |
| Line diversity | 0.15 | Unique line ratio — duplicate lines = degenerate |
Structural content (code, lists, tables) gets a discount factor to reduce false positives.
flowchart TD
A["📝 LLM Output"] --> B["N-gram Diversity\nweight: 0.35"]
A --> C["Compression Ratio\nweight: 0.30"]
A --> D["Substring Match\nweight: 0.20"]
A --> E["Line Diversity\nweight: 0.15"]
B --> F["Weighted\nComposite Score"]
C --> F
D --> F
E --> F
F --> G["Structural\nDiscount"]
G --> H["Final Score\n0.0 — 1.0"]
guard = DegenGuard(
window_size=256, # characters to analyze
check_interval=64, # characters between checks
alert_threshold=3, # consecutive alerts before flagging
score_threshold=0.50, # minimum score to trigger alert
)
for chunk in llm_stream:
is_degen, score = guard.feed(chunk)
if is_degen:
break
guard.reset() # reuse for next streamreport = DegenGuard.check(full_text)
report.is_degenerate # bool
report.composite_score # 0.0 ~ 1.0
report.signals # tuple of SignalDetail
report.structural_penalty # < 1.0 if code/tables detected
report.text_length # input length| Alternative | Limitation | llm-degen-guard |
|---|---|---|
| Antislop Sampler | Needs model weight access (no API support) | Works on any output text |
| SpecRA | Paper only, no code available | pip install ready |
| UQLM | Requires N generations (cost × N) | Single pass, real-time streaming |
| repetition_penalty | Penalizes prompt tokens, causes incoherence | Post-generation, no side effects |
- watchdeck — Web page monitoring with visual diffs and safety guards
MIT
Part of the QuartzUnit ecosystem — composable Python libraries for data collection, extraction, search, and AI agent safety.