VirtualHotBar/llm-shadow-relay
GitHub: VirtualHotBar/llm-shadow-relay
一个部署在客户端与 LLM 提供商之间的安全审计代理,实时拦截和检测 prompt 注入、越狱等攻击,保护 LLM 应用的安全。
Stars: 3 | Forks: 0
# LLM Shadow Relay
一个经过审计的 LLM API 代理,位于您的客户端和 LLM 提供商之间。它会拦截请求/响应,并使用受信任的模型对其进行审计,以在它们到达您的应用程序之前检测 prompt injection、system prompt 提取、越狱尝试以及其他安全风险。
## 功能
- **双协议支持** — 同时接受 OpenAI (`/v1/chat/completions`) 和 Anthropic (`/v1/messages`) 客户端格式,并转发到任一协议的上游
- **自动协议转换** — 客户端使用 OpenAI?上游使用 Anthropic?没问题。代理会透明地在格式之间进行转换。
- **命名上游 agent** — 通过 `/v1/agents/{agent_id}/...` 将请求路由到显式的提供商/模型配置文件
- **请求端 + 响应端审计** — 审计传入的 prompt 是否有注入尝试,并且审计传出的响应是否有数据泄露或恶意内容
- **双重审计模式**:`sync`(阻塞 — 在响应前等待审计完成)或 `async`(非阻塞 — 立即返回,在后台进行审计)
- **流式传输支持** — 支持 SSE 流式传输与实时 chunk 级别的审计
- **可配置的策略引擎** — 根据风险级别、类别、自定义关键词或风险评分阈值进行拦截
- **灵活的提供商审计** — 通过兼容 OpenAI、Anthropic、Ollama 或任何本地模型进行审计
- **多 agent 审计仲裁** — 并行运行可选的次要审计 agent 并执行最严格的决定
- **审计元数据标头** — 在响应标头中返回风险级别和评分(sync 模式)
- **请求关联** — 传递或生成用于日志和响应的 `x-request-id`
## 架构
```
┌─────────┐ OpenAI or ┌──────────────────┐ OpenAI or ┌──────────┐
│ Client │ ────────────▶ │ LLM Shadow Relay │ ────────────▶ │ Upstream │
│ (App) │ ◀──────────── │ (audit proxy) │ ◀──────────── │ LLM API │
└─────────┘ └──────────────────┘ └──────────┘
│
│ audit via
▼
┌──────────────────┐
│ Audit Model │
│ (trusted, tiny) │
└──────────────────┘
```
## 快速开始
### 1. 构建
```
cargo build --release
```
二进制文件位于 `target/release/llm-shadow-relay.exe` (Windows) 或 `target/release/llm-shadow-relay` (Linux/macOS)。
### 2. 配置
将 `config.example.toml` 复制到 `config.toml` 并进行编辑:
```
[upstream]
base_url = "https://api.openai.com/v1"
api_key = "sk-your-upstream-key"
default_model = "gpt-4o"
protocol = "openai" # "openai" or "anthropic"
[audit]
provider = "openai" # "openai", "anthropic", "ollama", "local"
base_url = "https://api.openai.com/v1"
api_key = "sk-your-audit-key"
model = "gpt-4o-mini"
enabled = true
mode = "sync" # "sync" or "async"
[[audit.agents]]
name = "strict-local-reviewer"
provider = "ollama"
base_url = "http://localhost:11434/v1"
model = "qwen2.5-8b"
```
可选的命名上游 agent:
```
[[agents]]
id = "research"
base_url = "https://api.openai.com/v1"
api_key = "sk-your-research-key"
default_model = "gpt-4o"
protocol = "openai"
[[agents]]
id = "writer"
base_url = "https://api.anthropic.com/v1"
api_key = "sk-ant-your-writer-key"
default_model = "claude-3-haiku-20240307"
protocol = "anthropic"
```
### 3. 运行
```
./target/release/llm-shadow-relay
# → 正在监听 127.0.0.1:8080
```
### 4. 使用
**Web UI:**
在浏览器中打开 `http://127.0.0.1:8080/ui` 以检查健康状况、撰写请求、选择已配置的命名 agent 并查看响应。UI 会读取 `/ui/config` 以获取协议、默认模型、标头透传和 agent ID 的脱敏摘要;API key 不会被暴露。
Web UI 支持英文和中文标签,并具有跟随浏览器语言的自动模式。手动语言选择会存储在浏览器本地。
使用 **Preview** 在发送前检查最终的请求 URL、正文和脱敏的标头。请求后,元数据面板会显示脱敏的请求和响应标头,以及状态、延迟、请求 ID 和审计标头。
长时间运行的请求可以使用 **Abort** 取消,响应输出可以直接从响应工具栏中复制。
UI 会保留简短的内存请求历史记录,以便快速重放和复制 cURL;刷新页面时会清除历史记录。
**OpenAI 客户端:**
```
curl http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4","messages":[{"role":"user","content":"Hello"}]}'
```
**命名上游 agent:**
```
curl http://127.0.0.1:8080/v1/agents/research/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Summarize this paper"}]}'
```
**Anthropic 客户端:**
```
curl http://127.0.0.1:8080/v1/messages \
-H "Content-Type: application/json" \
-d '{"model":"claude-3","max_tokens":1024,"messages":[{"role":"user","content":"Hello"}]}'
```
**命名 Anthropic 风格的上游 agent:**
```
curl http://127.0.0.1:8080/v1/agents/writer/messages \
-H "Content-Type: application/json" \
-d '{"model":"","max_tokens":1024,"messages":[{"role":"user","content":"Draft a release note"}]}'
```
## 配置参考
### `[server]`
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `listen` | `"127.0.0.1:8080"` | 服务器绑定地址 |
| `timeout` | `300` | 请求超时时间(秒) |
| `max_request_mb` | `10` | 最大请求正文大小(以 MB 为单位) |
### `[upstream]`
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `base_url` | — | 上游 API 基础 URL(例如 `https://api.openai.com/v1`) |
| `api_key` | — | 上游 API key(也可使用环境变量 `LLM_SHADOW_RELAY_UPSTREAM_API_KEY`);留空则透传客户端认证 |
| `default_model` | — | 请求未指定时的默认模型 |
| `protocol` | `"openai"` | 上游协议:`"openai"` 或 `"anthropic"` |
| `extra_headers` | `{}` | 发送到上游的额外 HTTP 标头 |
| `pass_through_headers` | `true` | 传递安全的客户端标头,如 `x-*`、`anthropic-*`、`openai-organization`、`openai-project`、`user-agent` 和 `accept-language` |
| `timeout` | — | 上游超时时间(秒)(默认为 `server.timeout`) |
| `max_retries` | `2` | 针对瞬态上游失败的重试:429、500、502、503、504、超时、连接失败 |
| `retry_initial_ms` | `250` | 初始指数退避延迟 |
| `retry_max_ms` | `5000` | 最大重试延迟;同时限制 `Retry-After` |
当 `api_key` 为空时,中继会将客户端认证转发给上游。OpenAI 上游接收传入的 `Authorization` 标头。Anthropic 上游接收传入的 `x-api-key`;如果缺少该项,则将 `Authorization: Bearer ...` 转换为 `x-api-key`。
标头透传故意排除了逐跳标头、`host`、`content-length`、`content-type`、`accept`、`authorization` 和 `x-api-key`;这些由中继或协议适配器管理。
上游重试仅在响应正文返回给客户端之前进行。对于带有以秒为单位的 `Retry-After` 的 429 响应,该值最高遵循至 `retry_max_ms`;否则中继使用指数退避。
流式传输审计块和上游流解析失败将作为带有 JSON `{ "error": ... }` payload 的 SSE `event: error` 消息发出。
中继会传播传入的 `x-request-id` 值并在每个响应中返回它们。如果客户端未发送,中继会生成一个 UUID 请求 ID。
### `[[agents]]`
命名上游 agent 是可选的。它们使用与 `[upstream]` 相同的连接字段,外加一个必填的唯一非空 `id`,并且仅通过显式路由进行选择:
| 端点 | 描述 |
|----------|-------------|
| `/v1/agents/{agent_id}/chat/completions` | 路由到命名上游 agent 的兼容 OpenAI 的客户端请求 |
| `/v1/agents/{agent_id}/messages` | 路由到命名上游 agent 的兼容 Anthropic 的客户端请求 |
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `id` | — | 上游 agent 的稳定路由 ID |
| `base_url` | — | 上游 API 基础 URL |
| `api_key` | — | 特定于 agent 的上游 API key;留空则透传客户端认证 |
| `default_model` | — | 请求 `model` 为空时的默认模型 |
| `protocol` | `"openai"` | 上游协议:`"openai"` 或 `"anthropic"` |
| `extra_headers` | `{}` | 特定于 agent 的额外标头 |
| `pass_through_headers` | `true` | 特定于 agent 的客户端标头透传 |
| `timeout` | — | 特定于 agent 的上游超时时间(秒) |
| `max_retries` | `2` | 特定于 agent 的重试尝试 |
| `retry_initial_ms` | `250` | 特定于 agent 的初始重试延迟 |
| `retry_max_ms` | `5000` | 特定于 agent 的最大重试延迟 |
### `[audit]`
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `provider` | — | 审计模型提供商:`"openai"`、`"anthropic"`、`"ollama"`、`"local"` |
| `base_url` | — | 审计 API 基础 URL(用于非 OpenAI 提供商) |
| `api_key` | — | 审计 API key(环境变量:`LLM_SHADOW_RELAY_AUDIT_API_KEY`) |
| `model` | — | 审计模型名称(例如 `gpt-4o-mini`、`claude-3-haiku`、`qwen2.5-8b`) |
| `temperature` | `0.1` | 较低值 = 更一致的审计决策 |
| `max_tokens` | `2048` | 审计响应的最大 token 数 |
| `enabled` | `true` | 启用/禁用审计 |
| `stream_audit` | `true` | 实时审计流式 chunk |
| `batch_size` | `10` | 在流式审计之前累积的 chunk 数 |
| `mode` | `"sync"` | `"sync"`(阻塞)或 `"async"`(后台) |
| `system_prompt` | — | 自定义审计 system prompt |
| `agents` | `[]` | 可选的次要审计 agent;每个 agent 继承 `[audit]` 中的缺失字段 |
### `[[audit.agents]]`
次要审计 agent 与主审计模型并行运行。中继执行最严格的成功决定。如果主审计模型失败,则请求像以前一样失败;如果次要 agent 失败,则会记录失败并使用剩余的成功决定。
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `name` | `"audit-agent-N"` | 用于日志的易读名称 |
| `provider` | `[audit].provider` | `"openai"`、`"anthropic"`、`"ollama"` 或 `"local"` |
| `base_url` | `[audit].base_url` | 特定于 agent 的审计 API 基础 URL |
| `api_key` | `[audit].api_key` | 特定于 agent 的 API key |
| `model` | `[audit].model` | 特定于 agent 的模型 |
| `temperature` | `[audit].temperature` | 特定于 agent 的 temperature |
| `max_tokens` | `[audit].max_tokens` | 特定于 agent 的最大 token 数 |
| `system_prompt` | `[audit].system_prompt` | 特定于 agent 的审计 system prompt |
### `[policy]`
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `block_risk_levels` | `["critical", "high"]` | 阻断请求的风险等级 |
| `block_prompt_injection` | `true` | 在检测到 prompt injection 时阻断 |
| `block_system_prompt_extraction` | `true` | 在提取 system prompt 时阻断 |
| `block_tool_call` | `true` | 在 tool call 注入时阻断 |
| `log_all` | `true` | 记录所有审计决策 |
| `custom_keywords` | `[]` | 用于标记的额外关键词 |
## 审计逻辑
1. **请求前审计**:在转发到上游**之前**,检查用户的 prompt 是否包含注入模式
2. **响应审计**:审计模型分析上游响应是否存在安全风险
3. **策略执行**:根据可配置的策略规则评估审计决策
4. **Sync 模式**:客户端在收到响应前等待完整审计
5. **Async 模式**:立即返回响应;审计在后台运行(仅记录)
## 协议转换
代理使用 OpenAI 风格的 `ChatCompletionRequest`/`ChatCompletionResponse` 作为其**内部规范格式**:
| 客户端发送 | 上游协议 | 会发生什么 |
|-------------|-------------------|--------------|
| OpenAI | OpenAI | 直接透传 |
| OpenAI | Anthropic | 转换 → 发送至 `/messages` → 将响应转换回来 |
| Anthropic | OpenAI | 转换为规范格式 → 发送 → 转换为 Anthropic |
| Anthropic | Anthropic | 转换 → 发送 → 转换回来(往返) |
这确保了审计引擎无论面对何种客户端或上游协议,始终使用相同的规范格式。
## 安全注意事项
- **审计模型**应该是一个**受信任的**模型 — 这是您的安全检查点
- 推荐的审计模型:`gpt-4o-mini`、`claude-3-haiku`、`deepseek-chat`、`qwen2.5-8b`
- 上游模型被视为**不受信任的** — 这就是我们要对其进行审计的原因
- API key 可以通过环境变量进行设置,以避免提交机密:
- `LLM_SHADOW_RELAY_UPSTREAM_API_KEY`
- `LLM_SHADOW_RELAY_AUDIT_API_KEY`
- 在 `async` 模式下,审计失败会被记录但不会返回给客户端 — 请注意监控您的日志!
## 许可证
MIT
标签:AI风险缓解, API网关, DLL 劫持, Petitpotam, Python安全, 人工智能, 代理服务, 内容审计, 可视化界面, 大语言模型, 用户模式Hook绕过, 通知系统