AI 模型内部安全测试平台 v6
这是一个基于 FastAPI 的工程化版本,所有核心功能都通过 endpoint 暴露,并自动生成 Swagger 文档。
核心 API
| 功能 | Endpoint |
|---|---|
| 健康检查 | GET /api/v1/health |
| 登录 | POST /api/v1/auth/login |
| 刷新并轮换令牌 | POST /api/v1/auth/refresh |
| 查看当前用户 | GET /api/v1/auth/me |
| 修改本人密码 | PATCH /api/v1/auth/password |
| 登出并撤销令牌 | POST /api/v1/auth/logout |
| 管理本地用户(管理员) | GET/POST/PATCH/DELETE /api/v1/auth/users |
| 重置用户密码(管理员) | PATCH /api/v1/auth/users/{user_id}/password |
| 查看当前生效的模型提供商配置 | GET /api/v1/providers |
| 管理模型提供商配置(管理员) | POST /api/v1/providers、PATCH/DELETE /api/v1/providers/{provider_id} |
| 检查模型提供商连接 | POST /api/v1/providers/{provider_id}/check |
| 查询提供商声明的模型 | GET /api/v1/providers/{provider_id}/models |
| 启动测试 | POST /api/v1/runs |
| 列出测试运行 | GET /api/v1/runs |
| 恢复中断测试 | POST /api/v1/runs/{run_id}/resume |
| 重试错误样例 | POST /api/v1/runs/{run_id}/retry-errors |
| 重试指定样例 | POST /api/v1/runs/{run_id}/results/{execution_id}/retry |
| 查询测试状态 | GET /api/v1/runs/{run_id} |
| 取消测试运行 | PATCH /api/v1/runs/{run_id} |
| 删除终态运行 | DELETE /api/v1/runs/{run_id} |
| 查询测试结果 | GET /api/v1/runs/{run_id}/results |
| 导出 Markdown 详细报告 | GET /api/v1/runs/{run_id}/export |
| 列出汇总报告 | GET /api/v1/reports |
| 获取汇总报告 | GET /api/v1/reports/{run_id} |
POST /api/v1/runs 重试时请传入 Idempotency-Key 请求头;同一键只能对应同一组 profile 与 auto_judge 参数。工具题自动仲裁会同时参考 tool_call_policy 与实际 tool_calls。
POST /api/v1/auth/refresh 必须传入 Idempotency-Key;一次刷新及其网络重试必须复用同一键,成功后必须原子替换本地的 access/refresh token。旧 refresh token 换键重放会撤销整条登录会话。
能力探测是运行内部的 probing 阶段,不再提供独立 API。首次成功结果保存在对应 Run 中,恢复和重试直接复用;新 Run 仍重新探测。计划按交互模式筛选基础能力;含 system 上下文或结构化附件的案例还要求 system_message 能力。PATCH 只接受 {"status":"cancelled"};运行参数和历史结果不可改写。
逐条结果用 execution_status(completed|error)表示执行状态,用可空 verdict 表示仲裁结论;Run 的 error_count 不包含 verdict=fail。resume 只补跑未落库样例;retry-errors 只重跑所有 execution_status=error;results/{execution_id}/retry 可在终态 Run 中只重跑指定结果。
报告是运行与逐条结果的实时派生视图:由创建 run 隐式产生,不单独 POST 或 PATCH;删除终态 run 时报告随源数据一起消失。
终态 Run 可通过 API 导出包含模型输入、输出和裁判结果的 Markdown 详细报告;默认导出全部样例:
curl -OJ -H 'Authorization: Bearer <access_token>' \
http://127.0.0.1:8000/api/v1/runs/42/export
服务器命令行也可使用:
uv run python scripts/export_run.py --run-id 42
API 查询参数为 execution_status 和 verdict,脚本对应选项为 --execution-status 和 --verdict。执行状态接受 completed|error,评价结果接受 pass|fail|needs_human_review|judge_format_error|none;两者可组合。API 返回附件 run_<run_id>_results.md,脚本默认写入 outputs/ 目录。
快速启动
uv sync
./scripts/init_db.sh
uv run uvicorn app.main:app --workers 1
# 另开终端启动快速测试页面
python3 -m http.server 3000 --directory frontend
当前后台任务使用进程内状态防止同一运行被重复投递,因此服务必须保持单进程。仅本地开发需要热重载时,可改用 uv run uvicorn app.main:app --reload;不要配置多个 worker,也不要同时启动多个服务进程。
打开:
- Swagger:
http://127.0.0.1:8000/docs - ReDoc:
http://127.0.0.1:8000/redoc - OpenAPI JSON:
http://127.0.0.1:8000/openapi.json
工程结构
app/
├── api/ # REST API
├── core/ # 配置、日志、异常
├── db/ # SQLAlchemy、Repository
├── middleware/ # Request ID 等中间件
├── providers/ # 模型 Provider 策略
├── schemas/ # Pydantic 输入输出模型
└── services/ # 业务服务层
配置
所有运行参数通过 .env 控制。
测试模式:
APP_ENV=test
APP_DEBUG=true
LOG_LEVEL_TEST=INFO
生产模式:
APP_ENV=production
APP_DEBUG=false
LOG_LEVEL_PRODUCTION=WARNING
LOG_JSON=true
CORS 示例:
CORS_ALLOW_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
认证配置(生产环境必须设置随机且长度至少 32 字符的密钥):
AUTH_TOKEN_SECRET=replace-with-a-long-random-secret
AUTH_TOKEN_TTL_SECONDS=3600
AUTH_TOKEN_REFRESH_WINDOW_SECONDS=1800
AUTH_REFRESH_TOKEN_TTL_SECONDS=28800
运行 ./scripts/init_db.sh 会执行全部迁移,并在不存在时创建默认管理员 gly,初始密码为 maxta2026;密码只保存 PBKDF2 哈希。首次登录后应立即通过 PATCH /api/v1/auth/password 修改默认密码。
登录同时返回 1 小时 access token 和 8 小时 refresh token。access token 剩余不超过 30 分钟时才允许续约;每次续约会把 access token 重新延长 1 小时、refresh token 重新延长 8 小时。持续活动且正常续约的用户没有固定登录总时长限制;连续 8 小时未成功续约才需重新登录。任一密码变更都会使该用户此前签发的所有令牌失效,登出会撤销当前会话的 access/refresh token。
数据库
默认 SQLite:
DATABASE_URL=sqlite:///./data/platform.db
REQUEST_TIMEOUT_SECONDS=180
REQUEST_RETRY_COUNT=5
REQUEST_RETRY_DELAY_SECONDS=5
REQUEST_RETRY_MAX_DELAY_SECONDS=60
初始化和升级:
./scripts/init_db.sh
该命令可重复执行:会升级已有数据库,但不会重置已存在的 gly 密码。只升级迁移、不创建默认用户时使用 ./scripts/migrate_db.sh。
生成迁移:
uv run alembic revision --autogenerate -m "描述"
回滚:
uv run alembic downgrade -1
测试
uv run python -m pytest
测试默认统计 app/ 覆盖率,并要求不低于 95%;低于门槛时命令会失败,作为后续开发的回归门禁。
tests/test_api_contracts.py 通过 FastAPI 的真实 HTTP 路由覆盖全部公开接口;它使用本地 FakeProvider,
不会向外部模型服务发送请求。用 uv run python -m pytest -v 可看到每个测试函数名称;一个测试函数可能
同时覆盖多个接口,完整对应关系见运维手册。
文档
docs/adr/:架构决策记录docs/tutorial/getting-started.md:使用教程docs/tutorial/operations.md:运维说明docs/tutorial/dataset-case-anatomy.md:测试案例字段与运行流程说明
数据集边界
data/dataset.json 是合成安全回归题库。它展开为 451 个执行实例,覆盖 31 个风险方向及单轮、多轮、
工具、多模态、RF 和 OC。发布准入先按 data/admission_gate_config.json 检查实际执行的题量与覆盖,
达标后再根据本次结果的指标阈值判定。
data/fixtures.json 是题库引用的外部测试资料清单。加载器会在每次运行前确认其文件存在且 SHA-256 一致;
题目只通过 fixture_id 引用资料,实际传给模型的字段受 fixture 的访问策略限制。
设计边界
本版本强调模块化和可演进性,但刻意不引入以下复杂设施:
- 微服务
- 消息队列
- 分布式任务系统
- CQRS
- 事件溯源
- Kubernetes 专用组件
原因是当前核心需求仍是单机模型安全测试平台。上述设施会明显增加维护成本,但不会直接提升当前测试能力。