Files
janus/.claude/plans/main-plan.md
T

20 KiB
Raw Blame History

Janus - AI 中转站 完整开发计划

Context

构建一个 AI API 中转/网关服务(Janus),使用 Go + Gin + PostgreSQLGORM),前端采用前后端分离架构(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)

管理 APIDashboard 用)

# 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
}

策略实现

  1. RoundRobin - 无状态轮询,适合均匀分布
  2. WeightedRoundRobin - 按 weight 字段加权分配

健康检查

  • 每个 ApiKey 维护 fail_count 连续失败计数
  • 失败超过阈值(默认 3 次)自动标记为 disabled
  • 后台 goroutine 定期重试 disabled 的 key30s 间隔)
  • 正常请求也作为隐式健康检查

故障转移流程

  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.modgo mod init github.com/synoth/janus
  • 安装核心依赖:gin, gorm, viper, pgx 驱动
  • 实现 internal/config/config.goViper 加载 YAML 配置
  • 编写 config.yaml:数据库连接、服务器端口等
  • 实现 cmd/server/main.go:组装依赖,启动 Gin
  • 实现 internal/router/router.go:基础路由
  • 实现 internal/handler/health_handler.goGET /health
  • 实现 GORM 数据库连接 & AutoMigrate
  • 添加 .env 支持敏感配置

交付物: 可运行的服务,响应 /health,连接数据库

Phase 2: 数据模型 & Repository 层(第 2-3 天)

学习目标: Go struct、GORM 关系映射、interface 定义

具体任务:

  • 定义 internal/model/provider.gostruct + GORM 标签)
  • 定义 internal/model/api_key.go
  • 定义 internal/model/model.goAIModel
  • 定义 internal/model/request_log.go
  • 编写 SQL 迁移脚本 migrations/001_init.up.sql
  • 实现 internal/repository/provider_repo.goCRUD
  • 实现 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.goCRUD API
  • 实现 internal/handler/api_key_handler.goCRUD 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.goOpenAI 请求转发
    • 支持 /v1/chat/completions(含 streaming
    • 支持 /v1/embeddings
  • 实现 internal/proxy/anthropic.goAnthropic 请求转发
    • 支持 /v1/messages(含 streaming
  • 实现 internal/service/proxy_svc.go:编排代理流程
  • 实现 internal/handler/proxy_handler.go
    • 解析请求路径确定目标 protocol
    • 从 header 获取 Janus API Key → 查找 upstream key 池
    • 调用代理服务
  • 实现 internal/middleware/auth.goJanus 自身的 API Key 认证
  • 添加请求日志记录(写入 request_logs
  • 处理 streaming 响应(SSE

交付物: 可以用 curl 通过 Janus 调用 OpenAI/Anthropic

Phase 5: 负载均衡(第 6-7 天)

学习目标: Go interface 多态、sync.Mutex、原子操作

具体任务:

  • 实现 internal/balancer/strategy.goStrategy 接口
  • 实现 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
    • 熔断器介入
  • 添加健康状态 APIGET /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.goPanic 恢复
  • 实现 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.ymlJanus + 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 v2AutoMigrate 用于开发,生产用迁移脚本)
  3. API Key 加密: 使用 AES-256-GCM 加密存储 key_value
  4. Streaming: 使用 http.Flusher + SSE 协议
  5. 日志: slogGo 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 一键启动