241 lines
7.2 KiB
Markdown
241 lines
7.2 KiB
Markdown
# zzrouter - 模型 API 代理服务设计文档
|
|
|
|
## 概述
|
|
|
|
zzrouter 是一个 AI 模型 API 代理服务,支持多个模型提供商的统一访问,并提供 API Key 轮换、请求日志等功能。
|
|
|
|
## 核心需求
|
|
|
|
| 项目 | 决策 |
|
|
|------|------|
|
|
| 模型提供商 | OpenAI 兼容格式 + Anthropic |
|
|
| API Key 轮换策略 | 轮询 (Round-robin) |
|
|
| 客户端 Key 存储 | SQLite 数据库 |
|
|
| 提供商 Key 存储 | SQLite 数据库 |
|
|
| 对外 API 格式 | OpenAI 兼容 + 原生格式双支持 |
|
|
| 流式响应 | 支持 (SSE) |
|
|
| 管理方式 | 直接操作数据库 |
|
|
| 日志统计 | 完整版 (token、延迟、错误) |
|
|
|
|
## 架构
|
|
|
|
```
|
|
┌─────────────┐
|
|
│ Client │
|
|
└──────┬──────┘
|
|
│ API Key 认证
|
|
▼
|
|
┌─────────────────────────────────┐
|
|
│ FastAPI 服务 │
|
|
│ ┌─────────────────────────┐ │
|
|
│ │ 认证中间件 │ │
|
|
│ └───────────┬─────────────┘ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────┐ │
|
|
│ │ 路由层 │ │
|
|
│ │ /v1/chat/* (OpenAI) │ │
|
|
│ │ /v1/anthropic/* │ │
|
|
│ └───────────┬─────────────┘ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────┐ │
|
|
│ │ LiteLLM + Key 轮询 │ │
|
|
│ └───────────┬─────────────┘ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────┐ │
|
|
│ │ 日志记录 (异步批量) │ │
|
|
│ └─────────────────────────┘ │
|
|
└─────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────┐
|
|
│ SQLite │
|
|
└─────────────┘
|
|
```
|
|
|
|
## 数据库结构
|
|
|
|
```sql
|
|
-- 客户端 API Key
|
|
CREATE TABLE client_keys (
|
|
id INTEGER PRIMARY KEY,
|
|
key TEXT UNIQUE NOT NULL,
|
|
name TEXT,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
-- 模型提供商
|
|
CREATE TABLE providers (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
base_url TEXT NOT NULL,
|
|
api_type TEXT NOT NULL, -- 'openai' 或 'anthropic'
|
|
is_active BOOLEAN DEFAULT TRUE
|
|
);
|
|
|
|
-- 提供商 API Key (一对多)
|
|
CREATE TABLE provider_keys (
|
|
id INTEGER PRIMARY KEY,
|
|
provider_id INTEGER REFERENCES providers(id),
|
|
key TEXT NOT NULL,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
-- 请求日志
|
|
CREATE TABLE request_logs (
|
|
id INTEGER PRIMARY KEY,
|
|
client_key_id INTEGER REFERENCES client_keys(id),
|
|
provider_id INTEGER REFERENCES providers(id),
|
|
model TEXT,
|
|
prompt_tokens INTEGER,
|
|
completion_tokens INTEGER,
|
|
latency_ms INTEGER,
|
|
success BOOLEAN,
|
|
error_message TEXT,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
## API 路由
|
|
|
|
```
|
|
认证方式: Bearer Token (Authorization: Bearer <client_key>)
|
|
|
|
路由结构:
|
|
├── /v1/chat/completions # OpenAI 兼容格式 (自动路由)
|
|
├── /v1/models # 列出可用模型
|
|
│
|
|
├── /v1/openai/chat/completations # OpenAI 原生格式 (透传)
|
|
├── /v1/openai/models
|
|
│
|
|
├── /v1/anthropic/messages # Anthropic 原生格式 (透传)
|
|
├── /v1/anthropic/models
|
|
│
|
|
└── /health # 健康检查
|
|
```
|
|
|
|
### 模型映射逻辑
|
|
|
|
用于 `/v1/chat/completions` 根据模型名自动路由:
|
|
- `gpt-*`, `o1-*` → OpenAI
|
|
- `claude-*` → Anthropic
|
|
- 其他可配置映射
|
|
|
|
## 项目结构
|
|
|
|
```
|
|
backend/
|
|
├── main.py # 入口
|
|
├── pyproject.toml
|
|
├── app/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # FastAPI 应用
|
|
│ ├── config.py # 配置
|
|
│ ├── database.py # 数据库连接
|
|
│ │
|
|
│ ├── models/ # 数据库模型
|
|
│ │ ├── __init__.py
|
|
│ │ ├── client_key.py
|
|
│ │ ├── provider.py
|
|
│ │ ├── provider_key.py
|
|
│ │ └── request_log.py
|
|
│ │
|
|
│ ├── services/ # 业务逻辑
|
|
│ │ ├── __init__.py
|
|
│ │ ├── auth.py # 客户端 Key 验证
|
|
│ │ ├── key_selector.py # Key 轮询选择
|
|
│ │ ├── logger.py # 异步日志写入
|
|
│ │ └── router.py # 模型路由逻辑
|
|
│ │
|
|
│ ├── providers/ # 提供商适配器
|
|
│ │ ├── __init__.py
|
|
│ │ └── litellm_wrapper.py # LiteLLM 封装
|
|
│ │
|
|
│ └── routes/ # API 路由
|
|
│ ├── __init__.py
|
|
│ ├── chat.py
|
|
│ ├── openai.py
|
|
│ ├── anthropic.py
|
|
│ └── health.py
|
|
│
|
|
frontend/ # 暂时空置
|
|
```
|
|
|
|
## 请求流程
|
|
|
|
```
|
|
Client Request: POST /v1/chat/completions
|
|
Headers: Authorization: Bearer <client_key>
|
|
Body: { "model": "claude-3-opus", "messages": [...], "stream": true }
|
|
│
|
|
▼
|
|
1. Auth Middleware - 验证 client_key
|
|
│
|
|
▼
|
|
2. Router Service - model → provider 映射
|
|
│
|
|
▼
|
|
3. Key Selector - 轮询选择 provider_key
|
|
│
|
|
▼
|
|
4. LiteLLM Wrapper - 执行请求
|
|
│
|
|
▼
|
|
5. Response Handler - 流式/非流式响应
|
|
│
|
|
▼
|
|
6. Async Logger - 批量写入日志
|
|
```
|
|
|
|
## 错误处理
|
|
|
|
### 认证错误
|
|
| 场景 | 响应 |
|
|
|------|------|
|
|
| 缺少 Authorization | 401 `{"error": "Missing API key"}` |
|
|
| 无效的 client_key | 401 `{"error": "Invalid API key"}` |
|
|
| client_key 已禁用 | 403 `{"error": "API key disabled"}` |
|
|
|
|
### 提供商错误
|
|
| 场景 | 响应 |
|
|
|------|------|
|
|
| 模型不存在/不支持 | 400 `{"error": "Unsupported model: xxx"}` |
|
|
| 提供商无可用 Key | 503 `{"error": "No available API key for provider"}` |
|
|
| 上游 API 限流 | 429 转发上游错误 |
|
|
| 上游 API 错误 | 500 转发上游错误 |
|
|
|
|
### 流式响应错误
|
|
- 中途失败 → SSE `data: {"error": "..."}\n\n` 后关闭连接
|
|
- 记录部分成功的 token 使用量
|
|
|
|
## 依赖
|
|
|
|
```toml
|
|
dependencies = [
|
|
"fastapi>=0.135.1",
|
|
"uvicorn[standard]>=0.41.0",
|
|
"litellm>=1.50.0",
|
|
"aiosqlite>=0.20.0",
|
|
]
|
|
```
|
|
|
|
## 初始化示例
|
|
|
|
```sql
|
|
-- 预置提供商
|
|
INSERT INTO providers (name, base_url, api_type) VALUES
|
|
('openai', 'https://api.openai.com/v1', 'openai'),
|
|
('anthropic', 'https://api.anthropic.com/v1', 'anthropic');
|
|
|
|
-- 添加提供商 API Key
|
|
INSERT INTO provider_keys (provider_id, key) VALUES
|
|
(1, 'sk-xxx...'), -- OpenAI key 1
|
|
(1, 'sk-yyy...'), -- OpenAI key 2
|
|
(2, 'sk-ant-xxx...'); -- Anthropic key
|
|
|
|
-- 添加客户端 Key
|
|
INSERT INTO client_keys (key, name) VALUES
|
|
('zzrouter-client-xxx', 'my-laptop');
|
|
```
|