# 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 ``` ## 数据库设计 ```sql -- 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 # 请求明细 ``` ## 负载均衡 & 故障转移设计 ### 负载策略接口 ```go type Strategy interface { Next(keys []*model.ApiKey) *model.ApiKey Name() string } ``` ### 策略实现 1. **RoundRobin** - 无状态轮询,适合均匀分布 2. **WeightedRoundRobin** - 按 weight 字段加权分配 ### 健康检查 - 每个 ApiKey 维护 `fail_count` 连续失败计数 - 失败超过阈值(默认 3 次)自动标记为 `disabled` - 后台 goroutine 定期重试 disabled 的 key(30s 间隔) - 正常请求也作为隐式健康检查 ### 故障转移流程 1. Balancer 选取一个 ApiKey 2. 代理请求到上游 3. 如果失败(5xx / 超时 / 网络错误): - 递增 `fail_count` - 达到阈值标记 `disabled` - 立即从剩余 key 中选择重试(最多 3 次) 4. 如果成功:重置 `fail_count` 为 0 ### 熔断器(单例 per ApiKey) ``` 状态机: CLOSED → (连续失败) → OPEN → (冷却时间) → HALF_OPEN → (成功) → CLOSED → (失败) → OPEN ``` ## 分阶段实施计划 ### Phase 1: 项目骨架 & 基础设施(第 1-2 天) **学习目标**: Go 项目组织、package 管理、Gin 基础 具体任务: - [-] 初始化 `go.mod`(go mod init github.com/synoth/janus) - [ ] 安装核心依赖:gin, gorm, viper, pgx 驱动 - [ ] 实现 `internal/config/config.go`:Viper 加载 YAML 配置 - [ ] 编写 `config.yaml`:数据库连接、服务器端口等 - [ ] 实现 `cmd/server/main.go`:组装依赖,启动 Gin - [ ] 实现 `internal/router/router.go`:基础路由 - [ ] 实现 `internal/handler/health_handler.go`:GET /health - [ ] 实现 GORM 数据库连接 & AutoMigrate - [ ] 添加 `.env` 支持敏感配置 **交付物**: 可运行的服务,响应 `/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`:协议适配器接口 ```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 | 通用技能 | ## 关键技术决策 1. **配置管理**: Viper(支持 YAML + 环境变量覆盖) 2. **ORM**: GORM v2(AutoMigrate 用于开发,生产用迁移脚本) 3. **API Key 加密**: 使用 AES-256-GCM 加密存储 key_value 4. **Streaming**: 使用 `http.Flusher` + SSE 协议 5. **日志**: slog(Go 1.21+ 内置结构化日志) 6. **前端**: Vue 3 + Vite + Element Plus(轻量、国内文档丰富) 7. **容器化**: 多阶段 Docker 构建,docker-compose 一键部署 ## 验证方式 每个 Phase 完成后的验证方法: 1. `go build ./...` 编译通过 2. `go vet ./...` 静态分析通过 3. `go test ./...` 单元测试通过 4. curl / Postman 手动测试关键 API 5. Phase 4+ 可用 OpenAI SDK 指向 Janus 实际调用 6. Phase 6 手动停用一个 key 验证故障转移 7. Phase 8 `docker-compose up` 一键启动