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

7.2 KiB

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    │
└─────────────┘

数据库结构

-- 客户端 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 使用量

依赖

dependencies = [
    "fastapi>=0.135.1",
    "uvicorn[standard]>=0.41.0",
    "litellm>=1.50.0",
    "aiosqlite>=0.20.0",
]

初始化示例

-- 预置提供商
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');