# 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 ) 路由结构: ├── /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 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'); ```