litellm/ui
Ishaan Jaff 5246e64b98
Add topic blocker guardrail with keyword and embedding implementations (#21713)
* Add keyword-based topic blocker implementation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add embedding-based topic blocker using MiniLM

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add topic blocker package init with exports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add synthetic engine eval set (34 cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment questions eval set (207 cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add engine eval synthetic policy config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add engine keyword blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment keyword blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding MiniLM eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding MPNet eval results (historical)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment TF-IDF eval results (historical)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add unified eval runner with confusion matrix reporting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add benchmarks comparison table in markdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Clean up topic blocker: remove unused blockers, add phrase_patterns to content filter

- Remove embedding_blocker.py, api_embedding_blocker.py, nli_blocker.py,
  tfidf_blocker.py, onnx_blocker.py (heavy deps not in Docker, inferior accuracy)
- Remove airline_off_topic_restriction policy template and its test
- Fix __init__.py to only export DeniedTopic and TopicBlocker (no eager import crash)
- Add phrase_patterns support to ContentFilterGuardrail for regex-based paraphrase detection
- Rewrite denied_financial_advice.yaml with conditional matching (identifier + block word),
  always-block keywords, phrase patterns, and exception phrases
- Clean up test_eval.py: only keyword blocker + content filter tests remain (no network calls)
- All 207 eval cases pass at 100% F1, 0 FP, 0 FN, <0.1ms latency

Addresses all Greptile review comments:
- Eager import crash (embedding deps) → fixed
- Undeclared dependencies → fixed (files deleted)
- lru_cache memory leak → fixed (file deleted)
- Real network calls in tests → fixed (embedding tests removed)
- Unused Dict import → already fixed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add LLM-as-judge eval and update BENCHMARKS.md

- Add TestInvestmentLlmJudgeGpt4oMini and TestInvestmentLlmJudgeClaude
  test classes that use litellm.completion() to classify messages
- System prompt instructs LLM to act as airline chatbot content moderator
- Tests skip gracefully when API keys aren't set
- Update BENCHMARKS.md with production results table, historical comparison,
  and instructions for running LLM judge evals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move evals and benchmarks to guardrail_benchmarks folder

Move eval runner, eval data (JSONL), and results from
tests/test_litellm/.../topic_blocker/ into the guardrail implementation
folder at litellm/.../litellm_content_filter/guardrail_benchmarks/.

This keeps benchmarks co-located with the guardrail code they test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove standalone topic_blocker package, consolidate into content_filter

The standalone keyword_blocker.py was redundant with content_filter.py +
denied_financial_advice.yaml. Removed the entire topic_blocker/ package,
engine eval files, and old keyword blocker results. Simplified test_eval.py
to only test ContentFilter + LLM judge baselines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix compliance playground batch scoring bug, add display_name support

The compliance playground was sending all texts in a single batch API call,
but the content filter raises HTTPException on the first blocked text. This
caused a single blocked/allowed result to be applied to all rows, producing
incorrect scores (e.g. 41% instead of 100%). Fix by sending each text
individually to get per-text results with progressive UI updates.

Also add display_name field support for category YAML files so
denied_financial_advice shows as "Denied Financial / Investment Advice"
in the UI dropdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add block_investment CSV eval set and update benchmark result JSON

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* address greptile review feedback (greploop iteration 1)

Fix stale test path in denied_financial_advice.yaml comment.
Other comments were on files already deleted in prior commits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:02:04 -08:00
..
litellm-dashboard Add topic blocker guardrail with keyword and embedding implementations (#21713) 2026-02-20 18:02:04 -08:00