# GuardEx: AI 护栏
GuardEx 是一个 Python SDK,用于筛查 LLM 的输入和输出中是否存在不安全内容、PII、prompt injection 以及可选的 grounding 检查。所有操作均在进程内运行,无需外部 API。只需大约十行代码,即可将其插入到任何 LLM 调用之前。
## 快速开始
```
pip install 'guardex-ai[local]' # adds in-process ML engines
```
或者从源码安装:
```
git clone https://github.com/atliq/guardex-ai.git
cd guardex-ai
pip install -e '.[local]'
```
```
from guardex import Guard
guard = Guard() # zero-config, models download on first use
result = guard.screen("How do I reset my password?", gate="input")
if result.blocked:
print(f"Blocked: {result.classify.category} - {result.classify.description}")
else:
if result.pii.has_pii:
print(f"PII detected ({len(result.pii.entities)} entities), masked text:")
print(result.text)
```
首次调用 `Guard()` 会下载约 250 MB 的模型到 `~/.cache/guardex/` 和 `~/.cache/huggingface/hub/`。随后的调用将直接使用已加载的缓存。
三个适配 Colab 的 [notebooks](docs/notebooks/) 演示了快速入门流程、PII 检测和内容安全。
如需完整的 S1-S14 安全分类,请通过 Ollama 运行 LlamaGuard(参见下方的说明)。如果未安装 Ollama,GuardEx 将使用 ONNX 快速网关。Grounding 为可选功能,需额外下载约 700 MB 的 NLI 模型;请参阅[配置](#configuration)以更改这两项的默认设置。
## 异步
```
import asyncio
from guardex import Guard
async def main():
async with Guard() as guard:
result = await guard.ascreen("What's your refund policy?", gate="input")
print(result.action, result.classify.category)
asyncio.run(main())
```
每个同步方法都有对应的异步版本(`ascreen`、`ascreen_batch`、`acheck_grounding`、`ascreen_grounded`、`astream`)。在本地模式下,它们通过 `asyncio.to_thread` 桥接到同步执行,因此您无需部署服务器。
## PII 保险库(可逆 token 化)
当 LLM 需要将个人数据回显给用户时(例如“向...发送确认信息”),掩码并不是合适的工具。Vault token 可以将占位符映射回原始值:
```
from guardex import Guard, PIIVault
guard = Guard()
vault = PIIVault()
text = "Send a confirmation to alice@example.com"
r = guard.screen(text, gate="input")
# vault_text 原地修改 `vault`
vaulted_text, _ = vault.vault_text(text, r.pii)
# vaulted_text == "Send a confirmation to {{pii:email:a3f9b2...}}"
# 将 vaulted_text 与 LLM 一起使用;模型永远不会看到该 email。
llm_reply = call_my_llm(vaulted_text)
# 在展示给用户之前进行恢复。
final_reply = vault.restore(llm_reply)
```
对于流式响应,请使用 `Guard.astream(..., vault=vault, restore_mode="buffered")` 以便在数据块边界处正确还原 token。流式输出网关默认不会对 PII 进行掩码处理;如有需要,请传入 `mask_output_pii=True`。
## 策略
`GuardExPolicy` 是单一的配置对象。常用的配置项如下:
```
from guardex import Guard, GuardExPolicy, TopicScope
policy = GuardExPolicy(
blocked_categories=["S1", "S3", "S4", "S9", "S11"], # default-blocked set
block_on_unsafe_input=True,
block_on_unsafe_output=True,
pii_enabled=True,
pii_action="mask", # or "block"
pii_threshold=0.85,
topic_scope=TopicScope(
topics=["customer support", "product help"],
scope_width="moderate",
),
audit_logging=True,
)
guard = Guard(policy=policy)
```
从 YAML 加载策略:
```
policy = GuardExPolicy.from_yaml("guardex_policy.yaml")
```
`from_yaml` 会读取一个扁平的策略文件(`pii_action`、`blocked_categories`、
`topic_scope`、`safety_routes` 等)。这是一个**与** `guardex.yaml` **不同的文件**,
后者用于配置本地 ML 引擎(模型仓库、缓存目录),并且会从您的项目根目录自动加载。
`guardex.yaml.example` 是它的模板。有关这两者的说明,请参阅 [configuration.md](docs/guides/configuration.md)。
需要特定领域的 PII 实体(如病历号、员工 ID)?
`GuardExPolicy(pii_custom_regex={...})` 可以添加您自定义的标签 → 正则表达式规则,
这在本地和服务器模式下均可用。请参阅 [PII 检测:自定义正则表达式模式](docs/guides/pii-detection.md#custom-regex-patterns)。
## 功能
| 功能 | 描述 | 延迟(热启动) |
|---|---|---|
| 安全分类 | 二元毒性网关(ONNX,默认开启);通过 LlamaGuard 3 支持完整的 S1-S14 类别(需可选的 Ollama) | ~20 ms / ~500 ms |
| PII 检测与掩码 | 涵盖 5 大类别的 31 种实体类型(GLiNER) | ~15 ms |
| Prompt injection 防御 | 客户端正则表达式(31 种模式) | ~1 ms |
| 幻觉检测 | NLI + embedding 混合模式,支持断言分解(需主动开启) | ~50-200 ms |
| 主题范围限制 | 基于 embedding 的主题过滤 | ~5 ms |
| 流式传输支持 | 缓冲 + 流安全的 Vault 还原 | 按数据块 |
| 多轮对话感知 | `ConversationGuard` 可检测跨轮次的冲突升级 | 按对话轮次 |
| 自定义安全路由 | 通过示例话语定义用户自定义的黑名单类别 | ~5 ms |
默认情况下,ONNX 快速网关会做出二元的安全/有毒判定:它能可靠地捕获有毒语言,但无法识别措辞中性的有害请求(例如“我该如何制作武器”)。若要实现基于 S1-S14 类别的详细判定并覆盖此类请求,需要通过 Ollama 启用可选的 LlamaGuard 层(请参阅“快速开始”下的说明)。延迟数据是在 Apple M2 上测得的;冷启动会增加模型下载时间(未启用 grounding 时约 250 MB,启用时约 950 MB)。
## 集成示例
### Gemini
```
pip install google-genai
```
```
from google import genai
from guardex import Guard, GuardExViolation
guard = Guard()
client = genai.Client() # reads GEMINI_API_KEY
user_msg = "How do I reset my password?"
try:
input_text = guard.screen_or_raise(user_msg, gate="input")
except GuardExViolation as e:
print(f"Refused at input gate: {e.category}")
raise
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=input_text,
)
try:
safe_output = guard.screen_or_raise(response.text, gate="output")
except GuardExViolation as e:
print(f"Refused at output gate: {e.category}")
raise
print(safe_output)
```
这种双层网关模式适用于任何提供商——只需替换模型调用,保留护栏即可。
### 带有幻觉检测的 RAG
Grounding 是可选功能——设置 `GUARDEX_GROUNDING_ENABLED=1` 或将 `grounding_mode=` 传递给 `screen_grounded`。
```
from guardex import Guard
guard = Guard()
screen_result, grounding = guard.screen_grounded(
response_text=llm_response,
sources=retrieved_chunks,
gate="output",
grounding_mode="accuracy",
)
if screen_result.blocked:
return "I can't help with that."
if grounding.hallucinated:
print(f"Faithfulness {grounding.faithfulness_score:.0%}; flagging for human review.")
for s in grounding.hallucinated_sentences:
print(f" - {s.sentence}")
```
### 对话护栏(升级检测)
```
from guardex import Guard
from guardex.conversation import ConversationGuard
guard = Guard()
cg = ConversationGuard(guard, window=6)
result = cg.screen_turn("user", user_message)
if result.blocked:
return guard.policy.refusal_messages.get(
result.classify.category,
"I can't help with that.",
)
llm_reply = call_llm(user_message)
cg.screen_turn("assistant", llm_reply)
```
## 服务器模式
未带 `api_key` 或 `base_url` 的 `Guard()` 会在进程内运行模型(本地
模式)。传入其中任意一个,SDK 就会转而通过 HTTP 与 GuardEx 服务器通信:
```
guard = Guard(base_url="http://your-host:8001") # your self-hosted server
```
SDK 内置了一个参考服务器——与 FastAPI 背后的本地 pipeline 相同:
```
pip install 'guardex-ai[local,server]'
guardex-server --host 0.0.0.0 --port 8001
```
模型在启动时加载;一旦 pipeline 准备就绪,服务器便开始接收流量。
它没有内置身份验证:请在私有网络中运行,或者在前面加上
您自己的身份验证代理。仅当您的部署在 endpoint 前设置了身份验证时,
才需要传入 `api_key=`;目前没有 GuardEx 托管的云服务。
## 架构
```
Guard()
|
| in-process
v
LocalRunner pipeline
|
+-- Input validation (length / repetition / character flood)
+-- Keyword gate (zero-latency hard blocks for passive ideation)
+-- Text normalization (homoglyph + invisible-char removal)
+-- Safety classifier
| +-- Layer 0: ONNX fast gate
| +-- Layer 1: LlamaGuard 3 via Ollama (optional, ~500 ms)
+-- PII detection (GLiNER, 31 entity types)
+-- Topic scope (sentence-transformers embedding)
+-- Custom safety routes (user-defined blocklist categories)
+-- Grounding / hallucination (DeBERTa NLI + embedding hybrid, opt-in)
+-- Prompt injection (client-side regex, 31 patterns)
```
## 安全类别
GuardEx 原样使用了标准的 LlamaGuard 3 / MLCommons 分类体系(`S1`-`S14`),
并增加了由输入验证器发出的 GuardEx 专用 `S0`。默认拦截的集合如下:
| 代码 | 类别 |
|---|---|
| S1 | 暴力犯罪 |
| S3 | 性犯罪 |
| S4 | 儿童性剥削 |
| S9 | 无差别武器 |
| S11 | 自杀与自残 |
有关完整的 S0-S14 对照表以及如何更改被拦截的类别,请
参阅 [safety-categories.md](docs/guides/safety-categories.md)。
## 配置
您可以通过环境变量(`GUARDEX_*`)或项目根目录下的 `guardex.yaml` 来覆盖默认设置。有关其支持的本地引擎设置,请参见 `guardex.yaml.example`。常见的覆盖配置如下:
```
export GUARDEX_CASCADE_MODE=speed # skip LlamaGuard, use ONNX only
export GUARDEX_GROUNDING_ENABLED=1 # enable NLI grounding (~700 MB)
export GUARDEX_CACHE_DIR=/data/guardex # custom model cache
export GUARDEX_ONNX_USE_GPU=1 # CUDA for ONNX classifier
```
## 本 SDK 不涵盖的功能
- 图像、音频或视频审核
- 角色/权限模型(无内置 RBAC)
- 跨语言安全分类(仅限英语模式)
- 托管的云服务(在进程内运行或自行托管参考服务器)
- 从远程存储实时热加载策略(请使用 YAML + 重启的方式)
## 贡献
欢迎提交 Bug 报告、功能请求和 Pull Request。在提交
PR 之前,请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 以了解开发
环境设置、分支策略和代码风格要求。对于安全问题,
请遵循 [SECURITY.md](SECURITY.md) 中的负责任的披露流程。
请勿就安全漏洞发布公开的 issue。
## 许可证
Apache 2.0。详情请参阅 [LICENSE](LICENSE)。