内容
哨兵






**适用于 LLM 驱动的编程助手的三阶段防护栏代理。**
哨兵位于 LLM 代理与其执行环境之间,在每个建议的操作运行之前审查它们。它通过模型上下文协议(MCP)与 Claude Code、Cursor 和 CodeX 等工具集成,充当一个始终在线的安全层,可以阻止破坏性命令,标记范围蔓延,并维护每个决策的完整审计跟踪。
支持 **标准输入输出(本地进程)和 SSE(网页端点)** 两种 MCP 传输方式,以实现最大兼容性。
---
## 问题
自主 LLM 编程代理可以执行 shell 命令、修改文件、推送到远程仓库并发出网络请求。这种能力带来真正的风险:一个范围不明确的提示或一个虚构的操作可能会导致数据丢失、暴露凭证或对生产系统进行不可逆转的更改。
现有的解决方案是二元的——要么代理在没有审查的情况下运行所有操作,要么人类必须手动批准每一步。两者都无法扩展。
---
## 解决方案
哨兵实施了一个 **多阶段决策管道**,该管道处理从明显安全到极度风险的操作,使用在每个阶段最快、最合适的工具:
**第一阶段 — 规则引擎**:在可配置的 YAML 规则集上进行模式匹配。处理明确的案例(递归删除、凭证暴露、根级写入)需时微秒,无需网络依赖。
**第二阶段 — 训练分类器**:一个 TF-IDF 矩阵变换器和逻辑回归分类器,训练于带有标签的数据集的代理操作。在毫秒内运行,完全离线,并生成带有置信度界限的可解释风险评分。
**第三阶段 — LLM 审查器**:对于统计模型无法可靠解决的模糊操作,大型语言模型在用户陈述任务的上下文中评估操作。这是唯一一个进行网络调用的阶段,并且仅在前几阶段不确定时激活。支持 Ollama(本地)、OpenAI、Anthropic 和 Google Gemini。
---
## 架构
```
MCP 客户端(Claude Code / Cursor / CodeX)
|
+-- 标准输入输出传输(mcp_server/server.py)
+-- SSE 传输 (mcp_server/sse_server.py)
|
v
| HTTP POST /review
v
api/main.py (FastAPI) <- REST API,审计日志,配置管理
|
v
sentinel_core/orchestrator.py
|
-- 第一阶段:sentinel_core/rules_engine.py (config/rules.yaml)
+阶段:sentinel_core/classifier.py (model_artifacts/model.pkl)
+-- 第三阶段:sentinel_core/llm_reviewer.pysentinel_core/model_manager.py)
|
v
(SQLite) <- 仅追加审计日志
```
---
## 分类器性能
| 指标 | 值 |
|---|---|
| 训练示例 | 828(手动标记 + 综合生成) |
| 类别平衡 | 58% 安全 / 42% 风险 |
| 5 折交叉验证准确率 | 76.3% ± 3.0% |
| CV 宏观 F1 分数 | 75.9% ± 3.1% |
| 保留测试准确率 | 75.2% |
| 风险类别精度 | 70% |
| 安全类别精度 | 79% |
| 自信预测(第二阶段直接处理) | 40% 流量 |
| 第三阶段 LLM 升级率 | 60% 流量 |
分类器的置信度阈值设置为 80%。高于此阈值的预测由第 2 阶段解决,无需调用第 3 阶段 LLM,从而降低了平均延迟并消除了 40% 的所有审查操作的 API 成本。
**与风险操作相关的前 5 个特征:** `bash`、`delete`、`iptables`、`exec`、`secret`
**与安全操作相关的前 5 个特征:** `version`、`list`、`describe`、`test`、`check`
---
## 项目结构
```
sentinel/
├──│ └── main.py FastAPI 应用程序,所有 HTTP 端点
├── sentinel_core/
│ ├── orchestrator.py 三阶段管道协调器
│ ├── rules_engine.py 第一阶段:YAML 规则匹配
│ ├── classifier.py 第二阶段:scikit-learn 推理
│ ├── llm_reviewer.py 第三阶段:LLM 推理
│ ├── model_manager.py 提供程序抽象(Ollama / OpenAI / Anthropic / Gemini)
│ ├── audit_log.py SQLite 决策日志
│ └── model_artifacts/ model.pkl + vectorizer.pkl(gitignored)
├── mcp_server/
│ ├── server.py MCP 标准输入输出服务器
│ └── sse_server.py MCP SSE 服务器(端口 8002)
├── dashboard/
│ ├── index.html 单页控制面板
│ ├── app.js 仪表板逻辑
│ └── style.css 仪表板样式
├── config/
│ ├── rules.yaml 第一阶段允许/阻止模式
│ ├── model_config.yaml 活动提供程序和模型选择
│ └── model_config.local.yaml API 密钥(gitignored,永远不会提交)
├── data/
│ └── training_examples.csv 第二阶段训练的标记数据集
├── train/
│ ├── train_classifier.py 训练脚本(scikit-learn)
│ └── generate_training_data.py 综合训练数据生成
├── docs/
│ └── ARCHITECTURE.md 内部设计笔记和原理
├── start.bat Windows 一键启动器
├── Dockerfile 容器镜像定义
└── requirements.txt
```
---
## 设计决策
### 为什么是三阶段而不是一阶段?
设计目标是尽量减少常见情况下的延迟和成本,同时为模糊情况保留高精度判断。绝大多数代理操作要么明显安全(`git status`、`npm install`),要么明显风险(`rm -rf /`、`git push --force`)。通过 LLM 路由两者将很慢且昂贵。通过规则引擎路由两者将错过大部分中间地带。
三阶段级联解决了这个问题:
- **第一阶段** 确定性地处理明确的案例,微秒级,无需模型参与。已知危险字符串的模式匹配不会产生幻觉。这是灾难性命令的最后一道防线。
- **第二阶段** 在毫秒级内使用可解释的基于系数的模型离线处理统计中间地带。我们故意选择 TF-IDF + 逻辑回归:模型在 CPU 上数秒内训练,生成可检查的系数,适合具有特定关键词和 n-gram 的短动作文本,其中风险集中。神经网络将增加不透明度,而不会显著提高问题。
- **第三阶段** 处理真正的模糊性 —— 上下文(用户陈述,会话范围)比表面级标记更重要的情况。这是 LLM 的推理能力增加实际价值的地方,它是唯一调用延迟和成本的阶段。
### 为什么第三阶段本地?
我们使用 Ollama 作为第三阶段实现,以确保在用户未显式配置云提供商的情况下,不会离开用户的计算机的操作文本。这对于可能有逻辑、内部主机名或敏感文件路径的代码。`model_manager.py` 中的提供商抽象使得在不更改任何第三阶段逻辑的情况下切换到云 LLM简单。
### 为什么要设置置信度阈值?
第二阶段并不将所有预测都传递给第三阶段 —— 只有置信度低于 80%。这在统计信号后面设置了昂贵的网络调用。置信度高于阈值的预测直接由第二阶段解决,占所有流量的约 40%。其余 60% 升级到第三阶段,LLM 的推理在此边际价值。
---
## 安装
**要求Python 3.10 或更高版本,pip,因特网访问(用于 API 提供商),或本地安装 Ollama。
### Docker(生产推荐)
```bash
# 构建镜像
docker build -t sentinel .
容器
docker run -p 80000 -p 8080:808```
仪表http://localhost:8080` 处可用 `http://localhost:8000` 处要持久保存审计日志和配置,请挂载:
```bash run -p 8000:8000 -p 8080:8080 \
-v $(pwd)/config:/app/config \
-v $(pwd)/sentinel.db:/app/sentinel.db \
sentinel
```
### Windows(一键启动)
双击项目根目录中的 `start.bat`。脚本将:
1. 如果不存在,则创建 Python 虚拟环境
2. 从 `requirements.txt` 安装所有依赖项
3. 如果缺少模型工件,则训练第二阶段分类器
4. 在端口 8000 上启动 FastAPI 服务器
5. 在端口 8080 上启动仪表板
6. 在浏览器中打开仪表板
### 手动设置
```bash
# 创建并激活虚拟环境
python -m venv venv
venv\Scripts\activate # Windows
source venv/bin/activate # macOS / Linux
# 安装依赖项
pip install -r requirements.txt
# (仅首次)训练第二阶段分类器
python train/train_classifier.py
# 启动 API 服务器
python -m uvicorn api.main:app --port 8000 --reload
# 在单独的终端中,服务仪表板
cd dashboard
python -m http.server 8080
# 在浏览器中打开
# http://localhost:8080
```
---
## 配置
### 第三阶段商
在 `http://localhost:8080仪表板,并导航到 **模型设置**。
**Ollama)**:选择从本地 Ollama 安装检测到的任何模型。不需要互联网。 使用 `ollama pull <model-name>` 拉取模型,然后选择**API 提供商**:选择 Google Gemini、OpenAI 或 Anthropic,输入您的 API 密钥并保存。密钥存储在磁盘上的 `config/model_config.local.yaml` 中,从不写入审计日志,从不通过 API 完整返回(仅在仪表板中显示最后 4 个字符)。
### 第一阶段规则
在仪表板的 **规则** 选项卡中导航以添加、编辑或匹配规则。规则字符串匹配和正则更改立即生效,无需重启服务器。
---
##集成和工具初始化
Sentinel 通过模型上下文MCP)向编码助手公开其功能。服务器使用 `FastMCP工具并处理传输层(支持 `stdio` 和 `sse`)。
### 工具初始化
当 MCP 服务器启动时,它初始化以下使它们可供连接的客户端使用:
| 工具 | 初始化和参数 | 描述 |
|---|---| `review_action` | `action_text`(user_task`(字符串) | 在执行建议的操作之前审查它。返回 `ALLOW`、`BLOCK` 或 `REVIEW` 的裁决。 |
| `get_recent_decisions` | `limit`(默认为 20) | 从审计日志中返回最近的条目,为代理提供过去裁决的上下文### 传输 1:标准输入输出(本地进程)
适用于在您的机器上本地运行的客户端(例如,Claude Desktop,Claude Code,)。将以下块 MCP 客户端配置文件(例如,`~/.claude/claude_code_config.json`):
```json
{
"mcp {
"sent {
"commandpython",
"args": ["mcp_server"],
"cwd": "/absolute/path/to/s"
}
```
### 传输 2:SSE(网页端点)
适用于基于 IDE(像 Cursor Web)生成本地的平台。`start.bat` 在 API 和旁边自动启动 SSE 服务器。
**Cursor IDE 连接 **类型**SSE`
- **:`http://localhost:8002/sse使用 MCP Inspector 测试:**
```bash
ny @modelcontextprotocol/inspector sse http://localhost:8002/sse
```
### 快速
为了简化,仪表板在右上角具有 **连接** 实用程序:
1. 点击仪表板右上角的 **连接** 按钮。
2. 选择您首选的传输选项卡(标准输入输出或 SSE)。
3. 模态叠加层提供确切的端点、URL 和将 Sentinel 工具注册到助手的时间线说明。
---
## API 参考
FastAPI 后端公开以下端点交互式文档可在服务器运行时在 `localhost:8000/docs` 获取。
| 路径 |
|---|---|---|
| GET | `/health`状况检查,返回暂停状态和项目路径 |
| GET | `/status` | 轻量级暂停验证状态 |
| POST | `/review` |进行审查 |
| POST | `/pause` | 暂停防护栏管道 | `/resume 恢复防护栏管道 |
| GET | `/ | 检索最近的审计日志条目 GET | `/rules` | 获取当前第一阶段规则集 |
| POST | `/rules` | 更新第一阶段规则集 |
| GETmodels/local`出本地可用的 模型 |
| `/models/config` | 获取当前模型提供商配置 |
| POST | `/models/config` | 更新模型提供商配置 |
| `/models/test` | 测试活动模型提供商连接 |
| GET | `/mcp/servers` | 列出已注册的 MCP 服务器 |
| POST | `/mcp/servers` | 注册新的 MCP 服务器 |
| DELETE | `/mcp/servers/{name}` | 删除已注册的 MCP 服务器 |
### 示例:审查操作
```bash
curl -X POST http://localhost:8000/review \
-H "Content-Type: application/json" \
-d '{"action_text": "rm -rf /tmp/build", "user_task": "Clean up build artifacts"}'
```
响应:
```json
{
"action_text": "rm -rf /tmp/build",
"verdict": "ALLOW",
"decided_by_stage": "classifier",
"reason": "Classifier predicted 'safe' with 89% confidence.",
"log_id": 42
}
```
---
## 第二阶段分类器 — 训练
分类器在 `data/training_examples.csv` 上进行训练,这是一个带有标签的数据集,包含 shell 命令、SQL 语句、git 操作和 API 调用,标记为 `safe` 或 `risky`。
要生成额外的综合训练数据:
```bash
python train/generate_training_data.py
```
在修改或扩展数据集后重新训练:
```bash
python train/train_classifier.py
```
脚本打印完整的分类报告和与风险相关的前 15 个特征,允许在不将模型视为黑盒的情况下验证和理解模型的学到的信号。
---
## 安全说明
- API 密钥仅存储在 `config/model_config.local.yaml` 中情况下 gitignored。
- 审计日志 (`sentinel.db`) 记录操作文本和审查决定,但从不存储 API 密钥。
- 如果在启动服务器之前将 `SENTINEL_API_KEY` 设置为环境变量,则所有变更端点(更新规则,更新模型配置,暂停/恢复)都需要通过 `X-Sentinel-Key` 头部提供该密钥。
- 防护栏可以通过仪表板暂停。在暂停模式下,所有操作都返回 `REVIEW`,需要手动签名。这是有意为之,采取保守态度。
---
## 许可证
MIT 许可证。有关详细信息,请参见 `LICENSE`。