262c8377b9
- 实现全局配置结构体,包含服务、数据库和日志配置 - 添加 Viper 配置加载功能,支持 YAML 文件和环境变量 - 创建 config.yaml 配置文件,包含服务器和数据库连接信息 - 集成 GORM 数据库连接功能,支持 PostgreSQL 驱动 - 更新依赖包,添加 postgres 驱动和相关工具库 - 实现 main 入口函数,加载配置并初始化服务 - 创建详细的 Phase 1 基础设施实施计划文档
20 KiB
20 KiB
Janus - AI 中转站 完整开发计划
Context
构建一个 AI API 中转/网关服务(Janus),使用 Go + Gin + PostgreSQL(GORM),前端采用前后端分离架构(Vue 3)。
用户背景:Java 转 Go,项目兼顾学习目的。计划按阶段递增复杂度,每个阶段引入新的 Go 语言特性:
- 早期:struct、interface、error handling、package 组织
- 中期:goroutine、channel、sync 包(并发安全)
- 后期:middleware 模式、context、observability
架构总览
┌─────────────────────────────────────────────────┐
│ Clients │
│ (OpenAI SDK / Anthropic SDK / curl) │
└─────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Janus Gateway │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Gin │ │ Proxy │ │ Management │ │
│ │ Router │ │ Engine │ │ API (CRUD) │ │
│ └────┬─────┘ └────┬─────┘ └───────┬───────┘ │
│ │ │ │ │
│ ┌────┴─────────────┴───────────────┴───────┐ │
│ │ Service Layer │ │
│ │ ┌──────────┐ ┌────────┐ ┌────────────┐ │ │
│ │ │ Balancer │ │ Health │ │ Rate Limiter│ │ │
│ │ │ Service │ │Checker │ │ Service │ │ │
│ │ └──────────┘ └────────┘ └────────────┘ │ │
│ └────────────────┬──────────────────────────┘ │
│ │ │
│ ┌────────────────┴──────────────────────────┐ │
│ │ Repository Layer (GORM) │ │
│ └────────────────┬──────────────────────────┘ │
│ │ │
│ ┌────────────────┴──────────────────────────┐ │
│ │ PostgreSQL │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Vue 3 Dashboard (SPA) │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Upstream AI Providers │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ OpenAI │ │Anthropic │ │ Compatible │ │
│ │ API │ │ API │ │ (DS, QWen) │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
项目目录结构
janus/
├── cmd/
│ └── server/
│ └── main.go # 应用入口,依赖组装
├── internal/
│ ├── config/
│ │ └── config.go # YAML 配置加载(viper)
│ ├── model/
│ │ ├── provider.go # Provider 模型
│ │ ├── api_key.go # ApiKey 模型
│ │ ├── model.go # AIModel 模型
│ │ └── request_log.go # RequestLog 模型
│ ├── repository/
│ │ ├── provider_repo.go # Provider CRUD
│ │ ├── api_key_repo.go # ApiKey CRUD
│ │ ├── model_repo.go # AIModel CRUD
│ │ └── request_log_repo.go # Log 查询
│ ├── service/
│ │ ├── provider_svc.go # Provider 业务逻辑
│ │ ├── api_key_svc.go # ApiKey 管理
│ │ ├── balancer_svc.go # 负载均衡核心
│ │ ├── proxy_svc.go # 请求代理引擎
│ │ ├── health_svc.go # 健康检查 & 故障转移
│ │ └── rate_limit_svc.go # 速率限制
│ ├── handler/
│ │ ├── proxy_handler.go # /v1/* 代理端点
│ │ ├── provider_handler.go # Provider 管理 API
│ │ ├── api_key_handler.go # ApiKey 管理 API
│ │ ├── model_handler.go # Model 管理 API
│ │ ├── stats_handler.go # 统计 API
│ │ └── health_handler.go # 健康检查
│ ├── middleware/
│ │ ├── auth.go # API Key 认证
│ │ ├── ratelimit.go # 速率限制中间件
│ │ ├── logging.go # 请求日志中间件
│ │ ├── cors.go # CORS
│ │ └── recovery.go # Panic 恢复
│ ├── proxy/
│ │ ├── openai.go # OpenAI 协议适配器
│ │ ├── anthropic.go # Anthropic 协议适配器
│ │ └── adapter.go # 适配器接口定义
│ ├── balancer/
│ │ ├── strategy.go # 策略接口
│ │ ├── round_robin.go # 轮询实现
│ │ └── weighted.go # 加权实现
│ ├── health/
│ │ ├── checker.go # 健康检查 Worker
│ │ └── circuit_breaker.go # 熔断器
│ └── router/
│ └── router.go # 路由注册
├── pkg/
│ ├── response/
│ │ └── response.go # 统一响应格式
│ ├── errors/
│ │ └── errors.go # 自定义错误类型
│ └── utils/
│ └── utils.go # 工具函数
├── web/ # Vue 3 前端项目
│ ├── src/
│ │ ├── views/
│ │ ├── components/
│ │ ├── api/
│ │ └── router/
│ ├── package.json
│ └── vite.config.ts
├── migrations/ # 数据库迁移 SQL
│ ├── 001_init.up.sql
│ └── 001_init.down.sql
├── config.yaml # 默认配置
└── go.mod
数据库设计
-- providers: AI 服务提供商
CREATE TABLE providers (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE, -- openai / anthropic / deepseek
base_url VARCHAR(255) NOT NULL, -- https://api.openai.com
protocol VARCHAR(20) NOT NULL DEFAULT 'openai', -- openai / anthropic
status VARCHAR(20) NOT NULL DEFAULT 'active', -- active / disabled
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- api_keys: API 密钥池
CREATE TABLE api_keys (
id BIGSERIAL PRIMARY KEY,
provider_id BIGINT NOT NULL REFERENCES providers(id),
key_value TEXT NOT NULL, -- 加密存储
name VARCHAR(100), -- 别名/备注
weight INT NOT NULL DEFAULT 1, -- 负载权重
status VARCHAR(20) NOT NULL DEFAULT 'active', -- active/disabled/depleted
fail_count INT NOT NULL DEFAULT 0, -- 连续失败计数
last_used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- models: 可用模型列表
CREATE TABLE models (
id BIGSERIAL PRIMARY KEY,
provider_id BIGINT NOT NULL REFERENCES providers(id),
name VARCHAR(100) NOT NULL, -- gpt-4o / claude-sonnet-4-5
input_price DECIMAL(10,8) DEFAULT 0, -- 每 1K token 价格
output_price DECIMAL(10,8) DEFAULT 0,
status VARCHAR(20) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(provider_id, name)
);
-- request_logs: 请求日志
CREATE TABLE request_logs (
id BIGSERIAL PRIMARY KEY,
api_key_id BIGINT,
model_id BIGINT,
provider_id BIGINT,
request_method VARCHAR(10),
request_path VARCHAR(500),
request_body TEXT,
response_body TEXT,
status_code INT,
latency_ms INT,
tokens_in INT DEFAULT 0,
tokens_out INT DEFAULT 0,
cost DECIMAL(10,6) DEFAULT 0,
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 索引
CREATE INDEX idx_api_keys_provider_id ON api_keys(provider_id);
CREATE INDEX idx_api_keys_status ON api_keys(status);
CREATE INDEX idx_models_provider_id ON models(provider_id);
CREATE INDEX idx_request_logs_created_at ON request_logs(created_at DESC);
CREATE INDEX idx_request_logs_provider_id ON request_logs(provider_id);
API 设计
代理端点(OpenAI 兼容 & Anthropic 兼容)
POST /v1/chat/completions # OpenAI 聊天补全
POST /v1/embeddings # OpenAI 嵌入
POST /v1/messages # Anthropic Messages API
GET /v1/models # 列出可用模型(聚合所有 provider)
管理 API(Dashboard 用)
# Providers
GET /api/admin/providers
POST /api/admin/providers
GET /api/admin/providers/:id
PUT /api/admin/providers/:id
DELETE /api/admin/providers/:id
# API Keys
GET /api/admin/api-keys?provider_id=
POST /api/admin/api-keys
PUT /api/admin/api-keys/:id
DELETE /api/admin/api-keys/:id
POST /api/admin/api-keys/:id/toggle # 启用/禁用
# Models
GET /api/admin/models?provider_id=
POST /api/admin/models
PUT /api/admin/models/:id
DELETE /api/admin/models/:id
# Stats
GET /api/admin/stats/overview # 总览统计
GET /api/admin/stats/requests # 请求明细
负载均衡 & 故障转移设计
负载策略接口
type Strategy interface {
Next(keys []*model.ApiKey) *model.ApiKey
Name() string
}
策略实现
- RoundRobin - 无状态轮询,适合均匀分布
- WeightedRoundRobin - 按 weight 字段加权分配
健康检查
- 每个 ApiKey 维护
fail_count连续失败计数 - 失败超过阈值(默认 3 次)自动标记为
disabled - 后台 goroutine 定期重试 disabled 的 key(30s 间隔)
- 正常请求也作为隐式健康检查
故障转移流程
- Balancer 选取一个 ApiKey
- 代理请求到上游
- 如果失败(5xx / 超时 / 网络错误):
- 递增
fail_count - 达到阈值标记
disabled - 立即从剩余 key 中选择重试(最多 3 次)
- 递增
- 如果成功:重置
fail_count为 0
熔断器(单例 per ApiKey)
状态机: CLOSED → (连续失败) → OPEN → (冷却时间) → HALF_OPEN → (成功) → CLOSED
→ (失败) → OPEN
分阶段实施计划
Phase 1: 项目骨架 & 基础设施(第 1-2 天)
📋 详细计划: phase-1-infrastructure.md
学习目标: Go 项目组织、package 管理、Gin 基础
核心任务:
- 初始化
go.mod,安装 gin / gorm / viper / pgx 依赖 - 实现配置加载(Viper + YAML + 环境变量)
- 实现 GORM 数据库连接和连接池配置
- 实现
/health端点,组装 Gin 启动流程 - 添加
.env支持和.gitignore
交付物: 可运行的服务,响应 /health,连接数据库
Phase 2: 数据模型 & Repository 层(第 2-3 天)
学习目标: Go struct、GORM 关系映射、interface 定义
具体任务:
- 定义
internal/model/provider.go(struct + GORM 标签) - 定义
internal/model/api_key.go - 定义
internal/model/model.go(AIModel) - 定义
internal/model/request_log.go - 编写 SQL 迁移脚本
migrations/001_init.up.sql - 实现
internal/repository/provider_repo.go(CRUD) - 实现
internal/repository/api_key_repo.go - 实现
internal/repository/model_repo.go - 编写 Repository 层的单元测试
交付物: 完整的数据访问层,可通过测试验证
Phase 3: Provider & API Key 管理 API(第 3-4 天)
学习目标: Gin handler、请求验证、JSON 序列化、统一错误处理
具体任务:
- 实现
pkg/response/response.go:统一 JSON 响应格式 - 实现
pkg/errors/errors.go:业务错误码定义 - 实现
internal/service/provider_svc.go - 实现
internal/service/api_key_svc.go - 实现
internal/handler/provider_handler.go:CRUD API - 实现
internal/handler/api_key_handler.go:CRUD API - 实现
internal/handler/model_handler.go:模型管理 API - 添加请求验证(binding tags + validator)
- Postman/curl 可测试的完整管理 API
交付物: 可通过 REST API 管理 Provider、ApiKey、Model
Phase 4: 代理引擎(第 4-6 天)
学习目标: HTTP 反向代理、streaming、context、Go http.Client
具体任务:
- 实现
internal/proxy/adapter.go:协议适配器接口type Adapter interface { Forward(ctx context.Context, key *model.ApiKey, body []byte) (*ProxyResult, error) Protocol() string } - 实现
internal/proxy/openai.go:OpenAI 请求转发- 支持
/v1/chat/completions(含 streaming) - 支持
/v1/embeddings
- 支持
- 实现
internal/proxy/anthropic.go:Anthropic 请求转发- 支持
/v1/messages(含 streaming)
- 支持
- 实现
internal/service/proxy_svc.go:编排代理流程 - 实现
internal/handler/proxy_handler.go:- 解析请求路径确定目标 protocol
- 从 header 获取 Janus API Key → 查找 upstream key 池
- 调用代理服务
- 实现
internal/middleware/auth.go:Janus 自身的 API Key 认证 - 添加请求日志记录(写入 request_logs)
- 处理 streaming 响应(SSE)
交付物: 可以用 curl 通过 Janus 调用 OpenAI/Anthropic
Phase 5: 负载均衡(第 6-7 天)
学习目标: Go interface 多态、sync.Mutex、原子操作
具体任务:
- 实现
internal/balancer/strategy.go:Strategy 接口 - 实现
internal/balancer/round_robin.go:- 线程安全的轮询计数器(sync.Mutex 或 atomic)
- 跳过 disabled key
- 实现
internal/balancer/weighted.go:- 加权轮询算法
- 平滑加权轮询(Nginx 算法)
- 实现
internal/service/balancer_svc.go:- 集成策略选择(可通过 API 或配置切换)
- 从 DB 加载可用 key 列表(带缓存)
- 修改 ProxyService 集成 BalancerService
- 编写负载均衡的单元测试(验证分布均匀性)
交付物: 请求自动在多个 ApiKey 间负载均衡
Phase 6: 健康检查 & 故障转移(第 7-9 天)
学习目标: Goroutine、Channel、context 取消、并发模式
具体任务:
- 实现
internal/health/circuit_breaker.go:- 三态状态机(Closed/Open/HalfOpen)
- 可配置阈值和冷却时间
- 实现
internal/health/checker.go:- 后台 goroutine 定期检查 disabled key
- 向每个 provider 发送轻量健康检查请求
- 通过 channel 接收检查结果
- 实现
internal/service/health_svc.go:- 管理所有 key 的健康状态
- 优雅关闭(context 取消 → 停止所有 goroutine)
- 修改 ProxyService 添加故障转移逻辑:
- 请求失败 → 标记 key → 从剩余池中重试
- 最大重试次数 3
- 熔断器介入
- 添加健康状态 API:GET /api/admin/keys/:id/health
交付物: 单个 key 故障时自动切换,故障 key 自动恢复
Phase 7: 速率限制 & 可观测性(第 9-10 天)
学习目标: Middleware 模式、token bucket 算法、结构化日志
具体任务:
- 实现
internal/service/rate_limit_svc.go:- Token bucket 算法(golang.org/x/time/rate)
- 支持按 Janus API Key 限流
- 支持按上游模型限流
- 实现
internal/middleware/ratelimit.go:- 从 Gin context 提取 key
- 返回 429 Too Many Requests
- 添加 Retry-After header
- 实现
internal/middleware/logging.go:- 结构化日志(使用 slog 或 zerolog)
- 记录 latency、status、path、tokens
- 实现
internal/middleware/recovery.go:Panic 恢复 - 实现
internal/handler/stats_handler.go:- 总请求数、成功率、平均延迟
- 按 Provider/Model 分组统计
- 费用汇总
- 添加
internal/middleware/cors.go
交付物: 完整的中间件链,可观测的统计数据
Phase 8: Dashboard 前端 & 容器化(第 10-14 天)
学习目标: 前后端集成、Docker、项目收尾
具体任务:
- 初始化 Vue 3 + Vite 项目(
web/) - 安装 UI 组件库(Element Plus 或 Naive UI)
- 实现 Providers 管理页面
- 实现 API Keys 管理页面
- 实现 Models 管理页面
- 实现统计仪表盘页面(图表)
- 前端构建产物由 Gin 静态文件服务托管
- 编写 Dockerfile(多阶段构建)
- 编写 docker-compose.yml(Janus + PostgreSQL)
- 编写 README.md(中英文)
交付物: 完整的可部署项目
Go 学习路径映射
| Phase | Go 特性 | Java 对比 |
|---|---|---|
| 1 | package, import, func, defer | package ≈ package, defer ≈ finally |
| 2 | struct, interface, 指针 | struct ≈ class(无继承), interface 隐式满足 |
| 3 | error handling, type assertion | error 返回值 ≠ exception |
| 4 | context, http.Client, io.Reader | context ≈ 请求上下文传递 |
| 5 | sync.Mutex, atomic, slice | 无内置锁语法,需显式使用 |
| 6 | goroutine, channel, select | ≈ ThreadPool + BlockingQueue |
| 7 | middleware 闭包, functional options | ≈ Filter chain / Builder pattern |
| 8 | 前后端集成, Docker | 通用技能 |
关键技术决策
- 配置管理: Viper(支持 YAML + 环境变量覆盖)
- ORM: GORM v2(AutoMigrate 用于开发,生产用迁移脚本)
- API Key 加密: 使用 AES-256-GCM 加密存储 key_value
- Streaming: 使用
http.Flusher+ SSE 协议 - 日志: slog(Go 1.21+ 内置结构化日志)
- 前端: Vue 3 + Vite + Element Plus(轻量、国内文档丰富)
- 容器化: 多阶段 Docker 构建,docker-compose 一键部署
验证方式
每个 Phase 完成后的验证方法:
go build ./...编译通过go vet ./...静态分析通过go test ./...单元测试通过- curl / Postman 手动测试关键 API
- Phase 4+ 可用 OpenAI SDK 指向 Janus 实际调用
- Phase 6 手动停用一个 key 验证故障转移
- Phase 8
docker-compose up一键启动