面向读者:刚接触后端、网关、AI API 中转的新手。 阅读目标:看完你应该知道 Sub2API 是什么、怎么跑起来、源码怎么分层、一次请求在系统里经历了什么,以及它为什么能做账号调度、鉴权、计费和限流。
1. 一句话理解这个项目
Sub2API 不是一个普通的"转发接口"。它更像一个面向 AI 服务的 SaaS 网关:管理员把上游 AI 账号或 API Key 接入系统,用户拿到平台生成的 API Key 后调用统一入口,系统在中间完成鉴权、选择账号、转发请求、记录用量、扣费、限流、监控和后台管理。
如果用生活化比喻:
- 上游账号像"批发来的 AI 调用额度"。
- 平台 API Key 像"发给用户的门票"。
- 网关像"检票员 + 调度员 + 记账员"。
- 管理后台像"老板看的控制台"。
官方 README 对它的定位是:AI API Gateway Platform for Subscription Quota Distribution,也就是"用于订阅配额分发管理的 AI API 网关平台"。

2. 技术栈速览
从仓库可以看出,这是一个前后端分离但可打包成单体镜像的项目。
| 层级 | 技术 | 作用 |
|---|---|---|
| 后端 | Go、Gin、Ent、Wire | HTTP 服务、业务逻辑、数据库 ORM、依赖注入 |
| 前端 | Vue 3、Vite、Pinia、Vue Router、TailwindCSS | 管理后台、用户中心、设置向导 |
| 数据库 | PostgreSQL | 保存用户、账号、API Key、订阅、计费、日志等核心数据 |
| 缓存/队列 | Redis | 限流、缓存、会话、异步用量记录等 |
| 部署 | Docker Compose、systemd 安装脚本、多阶段 Dockerfile | 快速部署、打包前端和后端 |
关键文件:
README.md/README_CN.md:项目介绍与部署说明。backend/cmd/server/main.go:后端启动入口。backend/internal/server/router.go:统一注册中间件和路由。backend/internal/server/routes/gateway.go:AI 网关相关路由。backend/internal/handler/openai_gateway_handler.go:OpenAI 网关 HTTP Handler。backend/internal/service/openai_gateway_service.go:OpenAI 请求转发、兼容、重试、流式处理等核心逻辑。backend/internal/service/openai_account_scheduler.go:OpenAI 上游账号调度器。backend/internal/service/api_key_service.go:平台 API Key 管理与校验逻辑。backend/internal/service/billing_service.go:计费缓存、模型价格、余额/订阅用量逻辑。frontend/package.json:前端脚本和依赖。deploy/docker-compose.yml、deploy/.env.example:Docker 部署配置。Dockerfile:前端构建、后端构建、最终镜像三阶段打包。

3. 新手最快搭建方式:Docker Compose
如果你只是想先跑起来,推荐 Docker Compose。它会同时拉起 Sub2API、PostgreSQL 和 Redis。
3.1 环境要求
- Linux 服务器或本地 Docker 环境
- Docker 20.10+
- Docker Compose v2+
- 推荐开放端口:
8080
3.2 一键准备部署目录
官方 README 提供的快速方式:
mkdir -p sub2api-deploy && cd sub2api-deploy
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/docker-deploy.sh | bash
docker compose up -d
docker compose logs -f sub2api
这个脚本会做几件对新手很友好的事:
- 下载 Docker Compose 配置和
.env.example。 - 自动生成
JWT_SECRET、TOTP_ENCRYPTION_KEY、POSTGRES_PASSWORD等密钥。 - 创建数据目录,方便以后备份和迁移。
- 启动后访问
http://服务器IP:8080。
3.3 手动部署方式
如果你想理解每一步,可以手动来:
git clone https://github.com/Wei-Shaw/sub2api.git
cd sub2api/deploy
cp .env.example .env
nano .env
.env 里最关键的是:
POSTGRES_PASSWORD=your_secure_password_here
JWT_SECRET=your_jwt_secret_here
TOTP_ENCRYPTION_KEY=your_totp_key_here
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your_admin_password
SERVER_PORT=8080
生成密钥可以用:
openssl rand -hex 32
然后启动:
docker compose up -d
docker compose logs -f sub2api
如果使用本地目录版配置:
docker compose -f docker-compose.local.yml up -d
docker compose -f docker-compose.local.yml logs -f sub2api
3.4 首次启动发生了什么?
backend/cmd/server/main.go 里可以看到启动逻辑:
- 解析
-setup和-version参数。 - 检查是否需要初始化配置。
- 如果设置了
AUTO_SETUP=true,就从环境变量自动初始化。 - 如果没有自动初始化,就启动 Web Setup Wizard。
- 初始化完成后进入正常服务模式。
Docker Compose 中的 deploy/docker-compose.yml 明确设置了:
AUTO_SETUP=true
SERVER_HOST=0.0.0.0
SERVER_PORT=8080
DATABASE_HOST=postgres
REDIS_HOST=redis
所以容器部署时不需要你手动创建配置文件,系统会根据环境变量完成第一次初始化。
4. 本地开发搭建
如果你想读源码、改代码、参与开发,可以按开发模式来。
4.1 后端
后端位于 backend/,使用 Go modules。
cd backend
go mod download
go build -o bin/server ./cmd/server
项目自己的后端 Makefile 提供了:
make build
make test
make test-unit
make test-integration
根目录 Makefile 也封装了:
make build-backend
make test-backend
注意:backend/go.mod 当前声明的是 go 1.26.3,README 徽章和开发文档中也出现过 Go 1.25.x 的描述。实际开发时建议以当前源码 go.mod 和 CI 配置为准。
4.2 前端
前端位于 frontend/,包管理器是 pnpm,不建议混用 npm。
cd frontend
pnpm install
pnpm run dev
常用脚本来自 frontend/package.json:
pnpm run dev # Vite 开发服务器
pnpm run build # vue-tsc 类型检查 + Vite 构建
pnpm run typecheck # 类型检查
pnpm run lint:check # ESLint 检查
pnpm run test:run # Vitest 测试
开发文档 DEV_GUIDE.md 特别提醒:前端必须使用 pnpm,pnpm-lock.yaml 要同步提交,否则 CI 的 frozen lockfile 会失败。
5. 源码分层:这个项目怎么组织?
从目录上看,Sub2API 后端采用比较典型的 Go 分层架构。
backend/
cmd/server/ # 程序入口
ent/ # Ent ORM 生成代码和 schema
internal/config/ # 配置加载、默认值、校验
internal/server/ # HTTP server、router、routes、中间件组装
internal/handler/ # HTTP Handler,负责解析请求和返回响应
internal/service/ # 业务逻辑:账号、调度、计费、网关转发
internal/repository/ # 数据访问、缓存、迁移、上游 HTTP 辅助
migrations/ # 数据库迁移
resources/ # 模型价格等资源
前端则是 Vue 项目常见结构:
frontend/src/
api/ # 调后端接口的封装
stores/ # Pinia 状态管理
router/ # Vue Router 路由与导航守卫
views/ # 页面级组件
components/ # 可复用组件
frontend/src/router/index.ts 里可以看到:路由按页面懒加载,包含 /setup、/login、/register、用户页面和管理后台页面,并通过 meta 字段控制是否需要登录。
6. 请求从用户到上游:一次 AI 调用的完整链路
最值得分析的是网关链路。以用户调用 OpenAI/Claude/Gemini 兼容接口为例,可以拆成 7 步。
第 1 步:请求进入 Gin 路由
backend/internal/server/router.go 中的 SetupRouter 会挂载通用中间件:
- 请求日志
- CORS
- Security Headers / CSP
- 嵌入式前端资源服务
- API v1 路由
- 网关路由
核心注册点:
routes.RegisterGatewayRoutes(r, h, apiKeyAuth, apiKeyService, subscriptionService, opsService, settingService, cfg)
第 2 步:网关路由判断协议
backend/internal/server/routes/gateway.go 定义了 AI 网关入口:
/v1/messages:Claude Messages 兼容入口,也会根据分组平台转到 OpenAI 逻辑。/v1/responses:Responses API。/v1/chat/completions:OpenAI Chat Completions。/v1/images/generations、/v1/images/edits:OpenAI 图片接口。/v1beta/models/...:Gemini 原生 API 兼容层。/backend-api/codex/responses:Codex 相关直连路径。
这说明 Sub2API 的目标不是只支持一种 API,而是把多个 AI 生态的入口统一到一个平台里。
第 3 步:API Key 鉴权
网关路由会使用 API Key 中间件。平台发给用户的 API Key 不是上游官方 Key,而是 Sub2API 自己生成和管理的 Key。
backend/internal/service/api_key_service.go 负责 API Key 的创建、查询、删除、额度检查、过期检查、失败限速等。源码里能看到这些错误类型:
API_KEY_NOT_FOUNDAPI_KEY_EXPIREDAPI_KEY_QUOTA_EXHAUSTEDAPI_KEY_RATE_5H_EXCEEDEDAPI_KEY_RATE_1D_EXCEEDEDAPI_KEY_RATE_7D_EXCEEDED
这就是"平台 Key"和"上游 Key"解耦的关键:用户只接触平台 Key,系统内部再决定用哪个上游账号。
第 4 步:检查分组、订阅和余额
网关中还有 RequireGroupAssignment、订阅校验、计费缓存等逻辑。billing_service.go 中定义了余额、订阅、API Key 时间窗口用量缓存接口。
它关心三类数据:
- 用户余额。
- 用户某个分组下的订阅。
- 某个 API Key 在 5 小时、1 天、7 天窗口内的用量。
因此系统可以支持更细的商业规则:某个用户能用哪些模型、多少额度、是否超限、是否需要扣余额。
第 5 步:选择上游账号
这是 Sub2API 比普通反代更有技术含量的部分。
backend/internal/service/openai_account_scheduler.go 定义了 OpenAI 账号调度接口:
Select(ctx, req) (*AccountSelectionResult, OpenAIAccountScheduleDecision, error)
ReportResult(accountID, success, firstTokenMs)
ReportSwitch()
SnapshotMetrics()
调度器会综合考虑:
- 分组 ID
- 会话 Hash
- 粘性账号 ID
previous_response_id- 请求模型
- 上游传输方式
- 图片能力
- 是否需要 compact 模式
- 排除账号列表
源码里的调度层名称很直观:
previous_response_id:优先保持同一个上下文响应链。session_hash:同一个会话尽量打到同一个账号。load_balance:无法命中粘性时再负载均衡。
它还维护运行时统计,例如错误率 EWMA、首 Token 延迟 TTFT EWMA,用来辅助选择更健康的账号。
新手可以这样理解:普通轮询是"排队轮流上",Sub2API 的调度更像"先看你是不是老客户,再看哪个窗口空、哪个服务员状态好"。
第 6 步:构造并转发上游请求
backend/internal/service/openai_gateway_service.go 是 OpenAI 网关的核心大文件。它处理的事情很多:
- OpenAI Responses / Chat Completions / Images 等接口兼容。
- OAuth 账号与 API Key 账号的不同上游地址。
- Codex CLI 相关请求头、会话和 WebSocket 行为。
- 请求头白名单,避免把不安全或无意义的客户端头透传给上游。
- 流式响应、重试、错误恢复。
- 上游响应头和用量信息解析。
源码中可以看到一些关键常量:
chatgptCodexURL = "https://chatgpt.com/backend-api/codex/responses"
openaiPlatformAPIURL = "https://api.openai.com/v1/responses"
openaiStickySessionTTL = time.Hour
这说明它不是简单把 URL 换一下,而是根据账号类型、客户端类型、模型能力和接口形态走不同路径。
第 7 步:记录用量、扣费、返回结果
请求成功后,系统需要把调用量转成成本,写入用量记录,再更新余额或订阅额度。billing_service.go 里有模型价格结构 ModelPricing,包含输入 token、输出 token、缓存 token、长上下文倍率、图片输出 token 等字段。
这解释了为什么它可以做到"Token 级别的用量追踪和成本计算"。对平台运营者来说,这比只统计请求次数精细得多。
7. 几个值得学习的技术点
7.1 Setup Wizard 与 Auto Setup
main.go 的启动逻辑把首次运行分成两种:
- 没有配置且没开自动初始化:启动 Setup Wizard。
- Docker 环境设置
AUTO_SETUP=true:直接从环境变量生成配置。
这对开源项目很友好:小白可以走网页向导,生产部署可以走环境变量自动化。
7.2 前端嵌入后端二进制
Dockerfile 是三阶段构建:
- Node 镜像构建前端。
- Go 镜像编译后端,并带上前端 dist。
- Alpine 运行最终二进制。
后端启动时 web.HasEmbeddedFrontend() 会判断是否有嵌入前端资源。如果有,就由后端同时服务 API 和前端页面。
这样部署时只需要一个应用容器,不必单独部署 Nginx + 前端静态站点。
7.3 Redis Lua 原子限流
backend/internal/middleware/rate_limiter.go 使用 Redis Lua 脚本做限流:
local current = redis.call('INCR', KEYS[1])
local ttl = redis.call('PTTL', KEYS[1])
if current == 1 then
redis.call('PEXPIRE', KEYS[1], ARGV[1])
elseif ttl == -1 then
redis.call('PEXPIRE', KEYS[1], ARGV[1])
end
return {current, repaired}
好处是计数和设置过期时间在 Redis 内部原子完成,避免高并发下出现计数错乱。
7.4 粘性会话
AI 对话不是一次性请求。很多客户端会带 session_id、conversation_id 或 previous_response_id。如果同一个上下文被分配到不同上游账号,可能出现上下文丢失或响应异常。
所以调度器先尝试 previous response 和 session hash,再进入负载均衡。这是 AI 网关区别于普通 HTTP 网关的重要点。
7.5 网关不是"裸透传"
OpenAI 网关里有 allowed headers 白名单。这样做可以减少两个风险:
- 客户端乱七八糟的头传到上游,触发风控或兼容问题。
- 敏感头、代理头、环境头被意外泄露。
这也是成熟网关常见设计:该透传的透传,不该透传的坚决过滤。
7.6 h2c 与 Nginx 注意事项
项目支持 HTTP/2 Cleartext,即 h2c。README 还特别提醒:如果前面接 Nginx,并且 Codex CLI 依赖带下划线的请求头,需要在 Nginx http 块里开启:
underscores_in_headers on;
否则像 session_id 这样的头可能被 Nginx 丢掉,进而破坏粘性会话。
8. 管理后台能做什么?
从 Handler 聚合结构 backend/internal/handler/handler.go 可以看到后台能力很丰富:
- 用户管理
- 分组管理
- 上游账号管理
- 公告管理
- 数据管理与备份
- OAuth 管理
- 代理管理
- 兑换码/促销码
- 系统设置
- 运维监控
- 订阅管理
- 用量统计
- API Key 管理
- 渠道监控
- 内容审核
- 支付与分销
这说明 Sub2API 不只是一个给开发者自用的小工具,而是带有 SaaS 运营后台的完整平台。
9. 新手读源码路线
如果你刚开始读,不建议直接打开 openai_gateway_service.go 从头硬啃。推荐路线:
第一阶段:先看启动和路由
backend/cmd/server/main.gobackend/internal/server/http.gobackend/internal/server/router.gobackend/internal/server/routes/gateway.go
目标:知道服务如何启动,请求如何进来。
第二阶段:看用户与 API Key
backend/internal/handler/api_key_handler.gobackend/internal/service/api_key_service.gobackend/internal/service/api_key_auth_cache.go
目标:理解平台 API Key 如何生成、校验和缓存。
第三阶段:看网关主链路
backend/internal/handler/openai_gateway_handler.gobackend/internal/service/openai_gateway_service.gobackend/internal/service/openai_account_scheduler.go
目标:理解请求如何被选择账号、转发上游、处理响应。
第四阶段:看计费和用量
backend/internal/service/billing_service.gobackend/internal/service/account_usage_service.gobackend/internal/handler/usage_handler.gobackend/internal/repository/ops_repo*.go
目标:理解 Token、成本、余额、订阅额度如何串起来。
第五阶段:看前端后台
frontend/src/router/index.tsfrontend/src/api/frontend/src/stores/frontend/src/views/admin/
目标:理解后端能力如何被管理后台组织成页面。
10. 常见问题
Q1:我没有上游账号,可以跑起来吗?
可以。项目本身可以部署和进入后台,但真正转发 AI 请求需要配置上游账号、API Key 或 OAuth 账号。
Q2:用户调用的是谁的 Key?
用户调用的是 Sub2API 生成的平台 Key。上游官方 Key 或 OAuth 凭据保存在平台侧,由调度器选择使用哪个上游账号。
Q3:为什么需要 PostgreSQL 和 Redis?
PostgreSQL 保存长期数据,比如用户、账号、配置、订阅、用量记录。Redis 处理高频、短期、并发相关数据,比如限流计数、缓存、会话粘性和队列状态。
Q4:为什么不直接 Nginx 反代?
Nginx 只能做比较基础的转发和负载均衡。Sub2API 还要做 API Key 鉴权、账号调度、Token 计费、订阅额度、用户后台、支付、监控、粘性会话和模型兼容,这些已经是应用层网关能力。
Q5:simple 和 standard 模式有什么区别?
配置示例中说明:standard 是完整 SaaS 模式,包含计费和余额检查;simple 会隐藏 SaaS 功能,并跳过计费/余额检查,更适合内部使用。
11. 总结:这个项目最值得学什么?
Sub2API 的价值不在于"把请求转发到 OpenAI/Claude/Gemini"这么简单,而在于它把一个 AI API 平台需要的核心能力组合起来:
- 用 Gin 承接多协议 API。
- 用平台 API Key 解耦用户和上游账号。
- 用调度器管理多账号、多模型、多会话。
- 用 Redis 做高并发缓存、限流和粘性会话。
- 用 PostgreSQL 保存长期业务数据。
- 用计费系统把 Token 用量变成余额和订阅额度。
- 用 Vue 管理后台把复杂运营能力可视化。
- 用 Docker 和 Setup Wizard 降低部署门槛。
对小白来说,这个项目是学习"真实世界后端系统"的好样本:它既有 Web 后台,也有网关高并发;既有业务系统,也有工程化部署;既要考虑用户体验,也要考虑上游 API 的兼容和风控。
如果你想练手,可以从三个小目标开始:
- 先用 Docker Compose 跑起来。
- 在后台创建一个用户和 API Key。
- 顺着
/v1/chat/completions或/v1/responses的路由,把一次请求从 route、handler、service、scheduler 到 billing 画成流程图。
当你能画出这张图,你就已经从"会部署"进阶到了"读懂一个真实 AI 网关系统"。