# aig_api_checker

AI 模型指纹识别 + 中转站检测工具

## 功能

### 1. 随机数指纹识别（统计方法）
通过让 AI 模型"随机选数字 1-355"，收集大量样本的分布指纹来区分不同模型。

### 2. 中转站一致性检测
结合接口、响应和协议行为等多类信号，辅助判断中转服务是否按预期转发模型请求。

## 检测能力

### A. 随机数指纹（统计方法）
让 AI 模型"随机选数字 1-355"，通过分布指纹区分不同模型。

### D. PAMELA 单 token 分布指纹（集成自 pamela-publish-py）
用 PAMELA 研究的 10 个 study-A 探针任务（随机数字/字母/单词/颜色/动物/城市/抛硬币）
在 en/ru/zh/ar 多语言下采样单 token 回答分布，与已发布参考指纹库
（内置 `pamela/reference/distributions.json`，167 个模型）逐单元计算
Jensen–Shannon 散度，排名最前即指纹最接近的模型。候选分布输出到
`pamela/results/candidate-distributions.json`，格式与 pamela-publish-py 完全兼容。

### E. Ventor QTest 供应商一致性量化检验

内置 [Ventor QTest](https://github.com/kexinoh/ventor_qtest)，同时提供两个互补
方法：长序列 EFL 通过可信参考逐位置重评分并观察运行级偏离的上尾；重复请求 AFL
只读取目标接口返回的文本，通过类别计数重建输出分布并计算有限样本偏差校正的
coarsened-KL。两种方法都只要求可信参考接口提供 `logprobs`。该模块使用独立配置
与结果目录，不改变已有 A/B/C/D 算法、基准文件或 HTTP SSE 接口。

### B. 协议一致性辅助校验

对支持相关能力的模型协议执行额外一致性校验，并将结果作为中转站检测的辅助信号。

### C. 中转站黑盒审计（8 探针，源自朱雀实验室 A.I.G）

适用于 OpenAI 兼容中转站（`/v1/models`、`/v1/chat/completions` 或
`/v1/responses`）：

| # | 探针 | 检测什么 | 关键风险信号 |
|---|------|----------|--------------|
| 1 | models | GET /v1/models 列表一致性 | 目标模型缺失；模型数异常 |
| 2 | liveness | 基础聊天可用性（精确 echo） | 返回被改写（中）；不可用（高） |
| 3 | identity | 模型身份弱信号 | 自报家族与所购模型不符 |
| 4 | glitch_fingerprint | Glitch Token 模型家族弱指纹 | 15 项复述错误编号命中已知家族签名 |
| 5 | token_delta | 隐藏 prompt / token 注入 | 短 prompt 的 prompt_tokens 异常偏高 |
| 6 | echo_rewrite | 输出改写 / 工具命令篡改 | pip install 被改成换源/curl/eval |
| 7 | stream_integrity | SSE 流式完整性 | 无 [DONE]、JSON 损坏、流内 model 不一致 |
| 8 | context_canary | 上下文截断 | 尾部 canary 丢失 |

- 纯 Python 标准库，无第三方依赖
- API key 全程脱敏，不回显
- 随机化探针 prompt，避免被识别规避
- 执行 8 个黑盒探针

## 安装

```bash
cd services/api_checker
pip install -r requirements.txt
```

在 AIG 仓库根目录可用以下命令创建隔离虚拟环境：

```bash
python3 -m venv services/api_checker/.venv
services/api_checker/.venv/bin/pip install -r services/api_checker/requirements.txt
```

## 使用

### 交互式菜单

```bash
python main.py
```

AIG 统一命令入口为 `ai-infra-guard api-checker ...`（别名
`relay-checker`）；它会自动查找本目录并调用配置的 Python 解释器。

### 命令行直接调用

```bash
python main.py calibrate   # 标定官方模型基准（随机数指纹）
python main.py test        # 测试第三方 API（随机数指纹匹配）
python main.py detect      # 中转站协议一致性辅助校验
python main.py audit       # 中转站黑盒审计（8 探针）
python main.py pamela      # PAMELA 单token分布指纹匹配（JSD）
python main.py qtest run   # Ventor QTest（使用内置默认配置）
python main.py qtest run --config path/to/config.yaml
python main.py qtest afl-run --config path/to/afl.yaml
python main.py qtest openrouter-providers --model moonshotai/kimi-k2.5
python main.py list        # 查看已保存基准
```

### 中转站检测示例

```bash
python main.py detect
# 输入中转站的 Base URL / API Key / 模型名
# 输出中转站检测结果
```

### HTTP SSE 接口

```bash
python server.py
# 独立运行时的 OpenAPI 文档：http://127.0.0.1:8000/docs
# 通过 AIG 统一接入时的 OpenAPI 文档：http://127.0.0.1:8088/api-checker/docs
curl http://127.0.0.1:8088/api/v1/relay/models
curl -N -X POST http://127.0.0.1:8088/api/v1/relay/check/stream \
  -H "Content-Type: application/json" \
  -d '{"algorithm":"quick","base_url":"https://relay.example.com/v1","api_key":"sk-...","model":"gpt-4o","language":"en"}'
```

本服务不内置检测前端；独立部署的前端直接调用上述 API。跨域直连 Checker 时通过
`AIG_API_CHECKER_CORS_ORIGINS` 配置允许的前端来源；经 AIG 或其他网关访问时在对应
网关配置跨域策略。

可通过 `/api/v1/relay/models` 查询 quick/full 检测支持的 29 个参考指纹模型。检测入口为
`/api/v1/relay/check/stream`，详见
[`docs/API.md`](docs/API.md)。常见风险、检测原理、结果解释和使用建议参见
[`docs/FAQ.md`](docs/FAQ.md)。
`language` 可选 `zh` 或 `en`，省略时默认中文；该参数控制结果中的 `summary`
和 `detail.findings[].title`。`detail.findings[].severity` 统一使用英文二值
状态；字段名以及 `overall_verdict`、`risk_level` 的机器可读枚举保持不变。
`risk_level` 在确认风险时按顶层安全分标记为 `high`（低于 30）、`medium`
（30～69.9）或 `low`（70 及以上）；检测通过时为 `none`，证据不足时为 `unknown`。
`summary` 由当前被测大模型根据评分、组件评分和未通过检查项生成：中文约
20～30 字，英文保持同等简洁；低于 100 分时说明一个主要降分原因。该步骤会新增
一次上游请求；若生成失败则自动使用同语言的本地兜底文本，不影响检测评分和判定。
`base_url` 可填写版本根路径，也可直接填写完整的 `/chat/completions` 或
`/responses` 地址；服务会自动选择对应协议且不会重复拼接路径。
模型 ID 会优先原样请求；如果 `/models` 中不存在 `provider/model`、但存在去掉
首段后的 `model`，后续审计、专项校验和指纹请求会自动使用该规范 ID。对于未提供
完整模型列表的服务，原始 ID 的 Chat 请求返回 400/404/422 时也会执行同样的回退。

## 日志

HTTP 检测主流程输出单行 JSON 结构化日志到 stdout，Docker 可通过
`docker logs -f ai-infra-guard-agent` 查看合并容器日志。日志覆盖任务接收、开始、组件错误、
完成、取消、拒绝和客户端断开，并记录请求 ID、模式、模型、目标地址、耗时、分数、
判定和 finding 数量。默认级别为 `INFO`，可通过
`AIG_API_CHECKER_LOG_LEVEL=DEBUG|INFO|WARNING|ERROR` 调整；`DEBUG` 额外记录进度。

API Key 原文不会进入日志，仅写入 `api_key_suffix`（最后 3 位）和
`api_key_sha256`（完整 SHA-256），用于安全地关联同一个 Key 的多次检测。客户端可
通过 `X-Request-ID` 请求头传入关联 ID，服务端也会在响应头返回最终请求 ID。

## 隐私

- **本地执行**：检测逻辑在本地运行；被测模型 API 仍可能按调用量收费
- **API Key 原文不留存**：HTTP 检测只在任务内存中使用原文；结构化日志仅保留
  最后 3 位和 SHA-256。QTest `--dump-config` 只写环境变量占位符，导出文件权限为
  `0600`
- **代码开源**：完整源码可审计

HTTP 服务默认只允许公网 HTTPS 目标。可信内网或本机测试可显式设置
`AIG_API_CHECKER_ALLOW_HTTP=1`、`AIG_API_CHECKER_ALLOW_PRIVATE_TARGETS=1`。
同时运行的检测任务默认上限为 20，可通过 `AIG_API_CHECKER_MAX_JOBS` 调整；超过
上限且没有空闲执行槽时返回 HTTP 429。

## 项目结构

```
services/api_checker/
├── main.py              # CLI 入口
├── server.py            # HTTP SSE 服务入口
├── Dockerfile           # 本地独立运行使用；Compose 生产部署已合并到 Agent 镜像
├── algorithms/
│   ├── common.py        # 公共 API 客户端、统计与基准存储
│   ├── fingerprint.py   # 随机数指纹
│   ├── bayes_score.py   # 贝叶斯评分
│   ├── signature.py     # 协议一致性辅助校验
│   ├── relay_audit.py   # 中转站黑盒审计
│   └── pamela.py        # PAMELA 单 token 分布指纹
├── ventor_qtest/         # 隔离内置的 Ventor QTest
│   ├── check.py          # logprobs、信息熵与 Z 检验
│   ├── summary.py        # 结果聚合与排名
│   ├── config/           # 独立默认配置
│   └── runner/           # CLI、编排及 OpenRouter 支持
├── docs/
│   ├── API.md           # HTTP API 文档
│   └── PARAMETERS.md    # 参数与数据结构说明
├── assets/charts/       # 分析图表
├── pamela/
│   ├── config/          # PAMELA 探针配置
│   └── reference/       # 随服务提供的参考指纹库
├── tests/               # 不访问真实模型的离线测试
├── requirements.txt
└── baselines.json       # 内置只读种子基准
```

可写基准和 PAMELA 结果默认进入 `runtime/`，可通过
`AIG_API_CHECKER_DATA_DIR` 指向持久化目录。

## 免责声明

测试结果仅供参考。由于大模型本身存在随机性及网络波动，本工具的测试结果不能作为任何商业纠纷、退款索赔的绝对法律/事实依据。

## 致谢

- 随机数指纹算法基于 [hlwy-ai-checker](https://github.com/hanlinwenyuan/hlwy-ai-checker)
- PAMELA 单 token 分布指纹实现参考 Tomas Bruckner 的论文
  [One Token Is Enough: Fingerprinting and Verifying Large Language Models from Single-Token Output Distributions](https://arxiv.org/abs/2607.10252)
