go-routine-id/bifrost-guardrail-plugin
GitHub: go-routine-id/bifrost-guardrail-plugin
为 Bifrost LLM 网关提供 system prompt 注入和正则输入拦截的内置治理插件,解决静态编译环境下无法动态加载插件的问题。
Stars: 0 | Forks: 0
# bifrost-guardrail-plugin
一个内置的 [Bifrost](https://github.com/maximhq/bifrost) HTTP-transport 插件,它可以:
1. 将**治理 system prompt 注入**到每个推理请求中,并且
2. **拦截**用户输入匹配已配置 regex 模式的请求(返回 HTTP 403)。
它同时支持 Anthropic (`/v1/messages`) 和 OpenAI (`/chat/completions`, `/v1/responses`) 的请求格式。
## 为什么是内置的而不是 `.so` 插件
官方的 `maximhq/bifrost` 镜像是**静态链接**的,因此 Go 的共享对象(shared-object)插件
无法被加载 —— `plugin.Open` 会失败并提示 `"Dynamic loading not supported"`。可行的
方案是将 guardrail 作为内置插件**编译到二进制文件中**,并构建一个
自定义镜像。(`.so` 变体保留在 `legacy-so-plugin/` 下供参考;它仅在
你自行构建动态链接的 Bifrost 时才有效。)
## 目录说明
| 文件 | 用途 |
|------|---------|
| `guardrail.go` | 插件源代码 —— 一个 `schemas.HTTPTransportPlugin`(放入 `transports/bifrost-http/guardrail/`) |
| `wiring.patch` | 两处用于在 Bifrost 的内置 registry 中注册该插件的小修改 |
| `Makefile` | 获取标签,重新应用插件,进行 vet 检查,并构建自定义镜像 |
`wiring.patch` 修改了以下文件:
- `transports/bifrost-http/server/plugins.go` —— 导入 + 在 `loadBuiltinPlugin` 中添加一个 `case` + 在 `loadBuiltinPlugins` 中进行注册
- `transports/bifrost-http/lib/config.go` —— 导入 + 在 `builtinPluginNames` 中添加条目
## 构建
```
# 1. 将 upstream 克隆到此 repo 旁边(或将 FORK_DIR 指向现有的 clone)
git clone https://github.com/maximhq/bifrost.git ./bifrost
# 2. 为给定的 upstream tag 构建自定义 image
make update TAG=transports/v1.6.0 \
FORK_DIR=./bifrost \
SERVER=dev@your-build-host \
IMAGE_REPO=your-org/bifrost
```
`make help` 会列出所有目标。`make smoke` 会启动一个临时容器,并验证
guardrail 是否已注册(`plugin status: guardrail - active`),是否拦截了匹配的请求(403),
以及是否放行了不匹配的请求。
## 与上游保持同步
其足迹仅包含一个新文件和两处微小的接线修改,并保存为 `wiring.patch`。当
上游发布新版本时,`make update TAG=` 会重新应用所有内容。如果
上游插件 registry 改动较大导致 patch 无法应用,请手动重新接线这两个
文件,并运行 `make regen-patch` 来刷新 `wiring.patch` 和 `guardrail.go`。
## CI:构建和自动部署
`.github/workflows/build-deploy.yml` 会在 GitHub runner 上构建镜像,将其推送到
GHCR (`ghcr.io//bifrost:`),并且可以通过
HTTP API 直接将其部署到 Nomad —— 无需 SSH。
- **仅构建**:通过 *Actions → build-and-deploy → Run workflow* 运行工作流,并设置
`deploy = false`,或者直接针对特定的上游标签依赖此流程。
- **构建 + 部署**:在运行时设置 `deploy = true`,或者推送一个 `v*` git 标签(即视为
发布)。部署作业会执行 `nomad job run -var "image=…" deploy/bifrost.nomad.hcl`。
所需的 repository secrets:
| Secret | 值 |
|--------|-------|
| `NOMAD_ADDR` | Nomad API 的 base URL,例如 `https://nomad.example.com` |
| `NOMAD_TOKEN` | 允许提交 `bifrost` 作业的 Nomad ACL token(请缩减其权限范围) |
镜像本身不携带任何密钥(provider 密钥 + `config.json` 存放在 Nomad 宿主机卷中)。
Nomad 节点仍然需要拉取它,因此请选择以下一种方式:
- **Public package** —— 将 GHCR package 可见性设置为公开;节点无需认证即可拉取。
- **Private package** —— 保持其为私有,并让节点进行认证。`deploy/bifrost.nomad.hcl`
会从 Nomad Variable 中读取内容并填充给 Docker driver 的 `auth` 配置块:`ghcr_user`(GitHub
用户名)和 `ghcr_pass`(权限范围仅限 `read:packages` 的 PAT)。只需设置一次:
nomad var put nomad/jobs/bifrost \
ghcr_user='' \
ghcr_pass='' \
kimi_api_key=… kimi_api_key_2=… bifrost_encryption_key=…
`deploy/bifrost.nomad.hcl` 将镜像作为变量接收,并在
部署时从 Nomad Variables 中读取所有的 provider 密钥以及 GHCR 认证信息。
## 启用插件
该插件是**可选开启 (opt-in)** 的。在你的 Bifrost `config.json` 中添加一个条目:
```
{
"plugins": [
{
"name": "guardrail",
"enabled": true,
"config": {
"system_prompt": "You are a governed assistant...",
"system_mode": "prepend",
"block_patterns": ["(?i)some-forbidden-phrase"],
"block_message": "Request blocked by guardrail policy."
}
}
]
}
```
| 字段 | 含义 |
|-------|---------|
| `system_prompt` | 注入到每个请求的 system prompt 中的文本 |
| `system_mode` | `prepend`(默认值 —— 我们的 prompt 置于调用者 prompt 之上)或 `override` |
| `block_patterns` | Regex 列表;如果其中任何一个匹配到拼接后的用户输入,则拦截该请求 |
| `block_message` | 在触发拦截并返回 HTTP 403 时返回的消息 |
如果没有 `plugins` 条目,自定义镜像的行为将与上游 Bifrost 完全一致。
标签:AI网关, DLL 劫持, EVTX分析, Go语言, 人工智能, 大语言模型, 护栏机制, 日志审计, 用户模式Hook绕过, 程序破解, 请求拦截