Universal LLM Safeguard Layer
Project overview
Universal LLM Safeguard Layer is a modular middleware written in Python that enforces content safety for applications interacting with large language models (LLMs). It implements a canonical filter pipeline designed for the Trinity framework: every decision is explicit, logged and auditable, and there are no silent failure modes. The layer normalises inputs, checks for authorised override phrases, runs a configurable suite of filters, aggregates the results and writes a structured log entry on every invocation. This makes it suitable for AI systems that must meet strict safety and audit requirements while remaining easy to integrate into existing code bases.
The high‑level pipeline is:
- Pre‑processing – sanitise and normalise the incoming text and attach any contextual metadata.
- Override detection – detect exactly one authorised phrase (e.g. from a parent or moderator) and, if present, strip it from the text and permit the message regardless of filter output. Ambiguous or missing overrides are rejected and logged.
- Filtering – run the configured filters on the cleaned text. The built‑in filters include:
- Keyword/regex filter – checks for banned keywords and regular expressions.
- Classifier filter – optionally uses a HuggingFace model to score toxicity/abuse categories and compares them against configurable warn/block thresholds.
- Perspective API filter – optionally calls the Google Perspective API for additional scoring.
Each filter returns (allowed, flags, reasons) where:
-
allowedis a boolean, -
flagsis a list of machine‑readable identifiers, -
reasonsis a list of human‑readable explanations. -
Aggregation – merge and deduplicate flags and reasons across all filters.
-
Logging – write a JSON‑lines entry with the timestamp, status, flags, reasons, override metadata, user/session identifiers, anonymised text and any additional context.
-
Post‑processing – allow downstream hooks to augment the result before returning a canonical dictionary.
The return value from the pipeline always includes the keys:
status–"allowed"or"blocked"flags– list of flag identifiers (e.g."keyword","classifier_toxic")reasons– corresponding human‑readable explanationsoverride–Trueif an override phrase was usedrole–"parent","moderator"orNone
This strict schema promotes type‑safety, cognitive alignment and ease of integration. Unexpected errors are never swallowed; instead they are logged with status="error" and the exception is re‑raised.
Installation
The package is distributed on PyPI under the name safeguard. A minimal installation installs only the core filtering logic; optional extras install framework adapters.
pip install safeguard
# Framework extras (optional)
pip install "safeguard[flask]" # Flask integration
pip install "safeguard[fastapi]" # FastAPI integration
pip install "safeguard[django]" # Django integration
To work from source:
git clone <repository_url>
cd safeguard
python3 -m venv .venv
source .venv/bin/activate # Use .venv\Scripts\activate on Windows
pip install -U pip setuptools
pip install .
pip install ".[dev]" # Installs test and lint dependencies
Configuration
Configuration is provided via a JSON file or Python dictionary. The default file lives in safeguarding/config/safeguard_config.json and is merged onto sensible defaults by load_config().
Important configuration sections:
rules.banned_keywords– list of lower‑cased substrings. If any appear, the message is blocked with the"keyword"flag.rules.banned_regex– list of regex patterns. Matches add a"regex"flag and block the message.classifier.enabled– enables HuggingFace classifier. Scores are compared to warn/block thresholds.perspective_api.enabled– enables Google Perspective API. Thresholds mirror classifier logic.logging.log_path– file path for audit logs.logging.anonymize– whether to redact text in logs (default: true).override.parent_phrases,override.moderator_phrases– lists of allowed override phrases.
Example safeguard_config.json
{
"rules": {
"banned_keywords": ["sex", "drugs", "violence", "suicide"],
"banned_regex": [".*naked.*", ".*let's keep this secret.*"]
},
"classifier": {
"enabled": false,
"model": "unitary/toxic-bert",
"thresholds": {
"toxic": { "warn": 0.5, "block": 0.7 },
"insult": { "warn": 0.5, "block": 0.7 }
}
},
"perspective_api": {
"enabled": false
},
"logging": {
"log_path": "safeguard_flags.log",
"anonymize": true
},
"override": {
"parent_phrases": ["override123"],
"moderator_phrases": ["modunlock!"]
}
}
Load with:
from safeguarding.utils.config_loader import load_config
config = load_config()
Programmatic usage
The core entry point is run_all_filters() from safeguarding.core.orchestrator.
from safeguarding.core.orchestrator import run_all_filters
from safeguarding.utils.config_loader import load_config
config = load_config()
config["classifier"]["enabled"] = False
config["perspective_api"]["enabled"] = False
result = run_all_filters(
text="Let's talk about drugs override123",
source="input",
user_id="user42",
session_id="sessionA",
config=config
)
if result["status"] == "blocked":
print("Content blocked:", result["reasons"])
else:
print("Allowed:", result)
Return schema:
| Key | Type | Description |
|---|---|---|
| status | str | "allowed" or "blocked" |
| flags | List[str|dict] | Identifiers for filter hits (e.g. "regex") |
| reasons | List[str] | Human-readable explanations |
| override | bool | True if override used |
| role | str or None | "parent", "moderator", or None |
Logging and override behaviour
Every run creates a JSON audit log containing:
timestampsource– e.g."input"or"output"status–"allowed","blocked","override"or"error"flags,reasonsoverride_used,override_roletext–[REDACTED]or full contentuser_id,session_idaction_type– e.g."block"or"allow"context– any additional metadata
Override phrases must match exactly. Zero or multiple matches = reject. All override attempts are logged.
Framework integration
Adapters are provided for Flask and FastAPI.
Flask
from flask import Flask, request, jsonify
from safeguarding.middleware.flask_adapter import safeguard_filter, safeguard_endpoint
from safeguarding.utils.config_loader import load_config
app = Flask(__name__)
config = load_config()
@app.route("/filter", methods=["POST"])
def filter_text():
data = request.get_json() or {}
text = data.get("text", "")
result = safeguard_filter(text, config=config)
if result["status"] != "allowed":
return jsonify(result), 403
return jsonify(result)
@app.route("/chat", methods=["POST"])
@safeguard_endpoint(config)
def chat():
return jsonify({"message": "Hello!"})
FastAPI
from fastapi import FastAPI
from safeguarding.middleware.fastapi_adapter import FastAPISafeguardMiddleware
from safeguarding.utils.config_loader import load_config
app = FastAPI()
config = load_config()
app.add_middleware(FastAPISafeguardMiddleware, config=config)
@app.post("/messages")
async def receive(data: dict):
return {"echo": data.get("text")}
Both return 403 with flags/reasons on block. All overrides are logged.
Version and licence
Current version: 0.1.0
Licence: MIT
See LICENSE for terms.
Contributing
Contributions welcome! Please open issues or PRs. Follow the design principles:
- No hidden behaviour
- No silent failures
- Full auditability
- Include tests for new logic
Release files for LLM-safeguard 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| llm_safeguard-0.1.0.tar.gz | 20.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_safeguard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.3 kB
Release files / llm_safeguard-0.1.0.tar.gz
| Download URL | llm_safeguard-0.1.0.tar.gz |
|---|---|
| Size | 20.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
75fa80587d3505847530f9086e5347bee08b32b4277e81137cd60da46aea178b
|
|
BLAKE2b-256 checksum How to use checksums |
f5c82d78869a06b00441f42103725fc5af25a653a187d12fb2f075f2908d9d42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Release files / llm_safeguard-0.1.0-py3-none-any.whl
| Download URL | llm_safeguard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 27.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39cf9d2bc0819cf960e09ab699105620eed5c8694c181b4766c85e9de2c86932
|
|
BLAKE2b-256 checksum How to use checksums |
d8e3f7908dd5d7b1d6121032bb9131bb46ee48287f9f03abc27017dd00d6ec8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|