1
0
Files
nex/backend/README.md
lanyuanxiaoyao cfb0edf802 feat: 引入 Viper 实现多层配置管理
引入 Viper 配置管理框架,支持 CLI 参数、环境变量、配置文件和默认值四种配置方式。

主要变更:
- 引入 Viper、pflag、validator、mapstructure 依赖
- 实现配置优先级:CLI > ENV > File > Default
- 所有 13 个配置项支持 CLI 参数和环境变量
- 规范化命名:server.port → NEX_SERVER_PORT → --server-port
- 使用结构体验证器进行配置验证
- 添加配置摘要输出功能

新增能力:
- cli-config: 命令行参数配置支持
- env-config: 环境变量配置支持(符合 12-Factor App)
- config-priority: 配置优先级管理

修改能力:
- config-management: 扩展为多层配置源支持

使用示例:
  ./server --server-port 9000 --log-level debug
  export NEX_SERVER_PORT=9000 && ./server
  ./server --config /path/to/custom.yaml
2026-04-20 18:04:42 +08:00

13 KiB
Raw Permalink Blame History

AI Gateway Backend

AI 网关后端服务,提供统一的大模型 API 代理接口。

功能特性

  • 支持 OpenAI 协议(/openai/v1/...
  • 支持 Anthropic 协议(/anthropic/v1/...
  • 支持 Hub-and-Spoke 跨协议双向转换OpenAI ↔ Anthropic
  • 同协议透传(零语义损失、零序列化开销)
  • 支持流式响应SSE
  • 支持 Function Calling / Tools
  • 支持 Thinking / Reasoning
  • 支持扩展层接口Models、Embeddings、Rerank
  • 多供应商配置和路由
  • 用量统计
  • 结构化日志zap + lumberjack
  • YAML 配置管理
  • 请求验证
  • 中间件支持(请求 ID、日志、恢复、CORS

技术栈

  • 语言: Go 1.26+
  • HTTP 框架: Gin
  • ORM: GORM
  • 数据库: SQLite
  • 日志: zap + lumberjack
  • 配置: gopkg.in/yaml.v3
  • 验证: go-playground/validator/v10
  • 迁移: goose

项目结构

backend/
├── cmd/
│   └── server/
│       └── main.go              # 主程序入口(依赖注入)
├── internal/
│   ├── config/                  # 配置管理
│   │   ├── config.go            # 配置加载/保存/验证
│   │   └── models.go            # GORM 数据模型
│   ├── domain/                  # 领域模型
│   │   ├── provider.go
│   │   ├── model.go
│   │   ├── stats.go
│   │   └── route.go
│   ├── handler/                 # HTTP 处理器
│   │   ├── middleware/          # 中间件
│   │   │   ├── request_id.go
│   │   │   ├── logging.go
│   │   │   ├── recovery.go
│   │   │   └── cors.go
│   │   ├── proxy_handler.go    # 统一代理处理器
│   │   ├── provider_handler.go
│   │   ├── model_handler.go
│   │   └── stats_handler.go
│   ├── conversion/               # 协议转换引擎
│   │   ├── canonical/            # Canonical Model
│   │   │   ├── types.go         # 核心请求/响应类型
│   │   │   ├── stream.go        # 流式事件类型
│   │   │   └── extended.go      # 扩展层 Models
│   │   ├── openai/              # OpenAI 协议适配器
│   │   │   ├── types.go
│   │   │   ├── adapter.go
│   │   │   ├── decoder.go
│   │   │   ├── encoder.go
│   │   │   ├── stream_decoder.go
│   │   │   └── stream_encoder.go
│   │   ├── anthropic/           # Anthropic 协议适配器
│   │   │   ├── types.go
│   │   │   ├── adapter.go
│   │   │   ├── decoder.go
│   │   │   ├── encoder.go
│   │   │   ├── stream_decoder.go
│   │   │   └── stream_encoder.go
│   │   ├── adapter.go           # ProtocolAdapter 接口 + Registry
│   │   ├── stream.go            # StreamDecoder/Encoder/Converter
│   │   ├── middleware.go        # Middleware 接口和 Chain
│   │   ├── engine.go            # ConversionEngine 门面
│   │   ├── errors.go            # ConversionError
│   │   ├── interface.go         # InterfaceType 枚举
│   │   └── provider.go          # TargetProvider
│   ├── provider/                # 供应商客户端
│   │   └── client.go
│   ├── repository/              # 数据访问层
│   │   ├── provider_repo.go     # 接口定义
│   │   ├── provider_repo_impl.go
│   │   ├── model_repo.go
│   │   ├── model_repo_impl.go
│   │   ├── stats_repo.go
│   │   └── stats_repo_impl.go
│   └── service/                 # 业务逻辑层
│       ├── provider_service.go       # 接口定义
│       ├── provider_service_impl.go
│       ├── model_service.go
│       ├── model_service_impl.go
│       ├── routing_service.go
│       ├── routing_service_impl.go
│       ├── stats_service.go
│       └── stats_service_impl.go
├── pkg/                         # 公共包
│   ├── errors/                  # 结构化错误
│   │   ├── errors.go
│   │   └── wrap.go
│   ├── logger/                  # 日志系统
│   │   ├── logger.go
│   │   ├── rotate.go
│   │   └── context.go
│   └── validator/               # 验证器
│       └── validator.go
├── migrations/                  # 数据库迁移
│   ├── 001_initial_schema.sql
│   └── 002_add_indexes.sql
├── tests/                       # 测试
│   ├── helpers.go
│   ├── integration/
│   ├── unit/
│   └── testdata/
├── Makefile
├── go.mod
└── README.md

架构

采用三层架构handler → service → repository通过依赖注入连接

handlerHTTP 请求处理)
  → service业务逻辑
    → repository数据访问

运行方式

安装依赖

go mod download

启动服务

go run cmd/server/main.go

服务将在端口 9826 启动。首次启动会自动创建配置文件和运行数据库迁移。

配置

配置支持多种方式:配置文件、环境变量、命令行参数,优先级为:CLI 参数 > 环境变量 > 配置文件 > 默认值

配置文件

配置文件位于 ~/.nex/config.yaml,首次启动自动生成。

server:
  port: 9826
  read_timeout: 30s
  write_timeout: 30s

database:
  path: ~/.nex/config.db
  max_idle_conns: 10
  max_open_conns: 100
  conn_max_lifetime: 1h

log:
  level: info
  path: ~/.nex/log
  max_size: 100        # MB
  max_backups: 10
  max_age: 30          # 天
  compress: true

环境变量

所有配置项都支持环境变量,使用 NEX_ 前缀:

export NEX_SERVER_PORT=9000
export NEX_DATABASE_PATH=/data/nex.db
export NEX_LOG_LEVEL=debug
./server

环境变量命名规则:将配置路径转换为大写,用下划线连接,加 NEX_ 前缀:

  • server.portNEX_SERVER_PORT
  • database.pathNEX_DATABASE_PATH
  • log.levelNEX_LOG_LEVEL

命令行参数

所有配置项都支持命令行参数:

./server --server-port 9000 --log-level debug --database-path /tmp/test.db

CLI 参数命名规则:将配置路径转换为 kebab-case用连字符连接

  • server.port--server-port
  • database.path--database-path
  • log.level--log-level

完整参数列表:

服务器配置:
  --server-port int                   服务器端口(默认 9826
  --server-read-timeout duration      读超时(默认 30s
  --server-write-timeout duration     写超时(默认 30s

数据库配置:
  --database-path string              数据库文件路径(默认 ~/.nex/config.db
  --database-max-idle-conns int       最大空闲连接数(默认 10
  --database-max-open-conns int       最大打开连接数(默认 100
  --database-conn-max-lifetime duration 连接最大生命周期(默认 1h

日志配置:
  --log-level string           日志级别debug/info/warn/error默认 info
  --log-path string            日志文件目录(默认 ~/.nex/log
  --log-max-size int           单个日志文件最大大小 MB默认 100
  --log-max-backups int        保留的旧日志文件最大数量(默认 10
  --log-max-age int            保留旧日志文件的最大天数(默认 30
  --log-compress               是否压缩旧日志文件(默认 true

通用选项:
  --config string              配置文件路径(默认 ~/.nex/config.yaml

使用示例

# 1. 使用默认配置
./server

# 2. 临时修改端口(不修改配置文件)
./server --server-port 9000

# 3. 测试场景(临时数据库)
./server --database-path /tmp/test.db --log-level debug

# 4. Docker 部署(环境变量)
docker run -d \
  -e NEX_SERVER_PORT=9000 \
  -e NEX_DATABASE_PATH=/data/nex.db \
  -e NEX_LOG_LEVEL=info \
  nex-server

# 5. 使用自定义配置文件
./server --config /path/to/custom.yaml

# 6. 混合使用优先级CLI > ENV > File
export NEX_LOG_LEVEL=debug
./server --server-port 9000  # port 用 CLIlog.level 用 ENV

数据文件:

  • ~/.nex/config.yaml - 配置文件
  • ~/.nex/config.db - SQLite 数据库
  • ~/.nex/log/ - 日志目录

测试

# 运行所有测试
make test

# 生成覆盖率报告
make test-coverage

数据库迁移

# 使用 Makefile
make migrate-up DB_PATH=~/.nex/config.db
make migrate-down DB_PATH=~/.nex/config.db
make migrate-status DB_PATH=~/.nex/config.db

# 或直接使用 goose
goose -dir migrations sqlite3 ~/.nex/config.db up

API 文档

代理接口

使用 /{protocol}/v1/{path} URL 前缀路由:

OpenAI 协议代理

POST /openai/v1/chat/completions
GET  /openai/v1/models
POST /openai/v1/embeddings
POST /openai/v1/rerank

请求示例:

{
  "model": "gpt-4",
  "messages": [
    {"role": "user", "content": "Hello"}
  ],
  "stream": false
}

Anthropic 协议代理

POST /anthropic/v1/messages
GET  /anthropic/v1/models

请求示例:

{
  "model": "claude-3-opus",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": [{"type": "text", "text": "Hello"}]}
  ]
}

协议转换:网关支持任意协议间的双向转换。客户端使用 OpenAI 协议请求,上游供应商可以是 Anthropic 协议(反之亦然)。同协议时自动透传,零序列化开销。

管理接口

供应商管理

  • GET /api/providers - 列出所有供应商
  • POST /api/providers - 创建供应商
  • GET /api/providers/:id - 获取供应商
  • PUT /api/providers/:id - 更新供应商
  • DELETE /api/providers/:id - 删除供应商

创建供应商示例:

{
  "id": "openai",
  "name": "OpenAI",
  "api_key": "sk-...",
  "base_url": "https://api.openai.com/v1",
  "protocol": "openai"
}

Protocol 字段说明:

  • protocol 标识上游供应商使用的协议类型,可选值:"openai"(默认)、"anthropic"
  • 同协议透传时,请求体和响应体原样转发,零序列化开销

重要说明:

  • base_url 应配置到 API 版本路径,不包含具体端点
  • OpenAI: https://api.openai.com/v1
  • GLM: https://open.bigmodel.cn/api/paas/v4
  • 其他 OpenAI 兼容供应商根据其文档配置版本路径

模型管理

  • GET /api/models - 列出模型(支持 ?provider_id=xxx 过滤)
  • POST /api/models - 创建模型
  • GET /api/models/:id - 获取模型
  • PUT /api/models/:id - 更新模型
  • DELETE /api/models/:id - 删除模型

创建模型示例:

{
  "id": "gpt-4",
  "provider_id": "openai",
  "model_name": "gpt-4"
}

统计查询

  • GET /api/stats - 查询统计
  • GET /api/stats/aggregate - 聚合统计

查询参数:

  • provider_id - 供应商 ID
  • model_name - 模型名称
  • start_date - 开始日期YYYY-MM-DD
  • end_date - 结束日期YYYY-MM-DD
  • group_by - 聚合维度provider/model/date

开发

构建

make build

代码检查

make lint

环境要求

  • Go 1.26 或更高版本

公共库使用指南

pkg/errors — 结构化错误

使用预定义的错误类型,配合 errors.Is / errors.As 判断错误:

import (
    "errors"
    pkgErrors "nex/backend/pkg/errors"
)

// 使用预定义错误
return pkgErrors.ErrRequestSend.WithCause(err)

// 判断错误类型
var appErr *pkgErrors.AppError
if errors.As(err, &appErr) {
    // appErr.Code, appErr.HTTPStatus, appErr.Message
}

可用函数:NewAppErrorWrapWithContextWithMessageAsAppError

预定义错误:ErrModelNotFoundErrProviderNotFoundErrInvalidRequestErrRequestCreateErrRequestSendErrResponseRead

pkg/logger — 日志系统

使用依赖注入模式,构造函数接受 *zap.Logger 参数nil 时回退到 zap.L()

func NewMyService(repo Repository, logger *zap.Logger) *MyService {
    if logger == nil {
        logger = zap.L()
    }
    return &MyService{repo: repo, logger: logger}
}

禁止直接在业务代码中使用 zap.L() 全局 logger应通过构造函数注入。

pkg/validator — 请求验证

import "nex/backend/pkg/validator"

v := validator.Get()
err := v.Validate(myStruct)

编码规范

  • JSON 解析:使用 encoding/json 标准库(json.Unmarshal / json.Marshal),不手动扫描字节
  • 字符串拼接:使用 strings.Join,不手写循环拼接
  • 错误判断:使用 errors.Is / errors.As,不使用字符串匹配(strings.Contains(err.Error(), ...)
  • 日志使用:通过依赖注入 *zap.Logger,不直接调用 zap.L()
  • 字符串分割:使用 strings.SplitN(key, "/", 2) 等精确分割,不使用索引切片