Files
zzrouter/docs/superpowers/specs/2026-03-11-model-proxy-design.md

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');
```