diff --git a/backend/README.md b/backend/README.md index c09fbef..b2fcc00 100644 --- a/backend/README.md +++ b/backend/README.md @@ -26,7 +26,7 @@ AI 网关后端服务,提供统一的大模型 API 代理接口。 - **ORM**: GORM - **数据库**: SQLite - **日志**: zap + lumberjack -- **配置**: gopkg.in/yaml.v3 +- **配置**: Viper + pflag(多层配置:CLI > 环境变量 > 配置文件 > 默认值) - **验证**: go-playground/validator/v10 - **迁移**: goose @@ -39,7 +39,7 @@ backend/ │ └── main.go # 主程序入口(依赖注入) ├── internal/ │ ├── config/ # 配置管理 -│ │ ├── config.go # 配置加载/保存/验证 +│ │ ├── config.go # Viper 多层配置加载/验证 │ │ └── models.go # GORM 数据模型 │ ├── domain/ # 领域模型 │ │ ├── provider.go @@ -47,17 +47,17 @@ backend/ │ │ ├── stats.go │ │ └── route.go │ ├── handler/ # HTTP 处理器 -│ │ ├── middleware/ # 中间件 +│ │ ├── middleware/ # 中间件 │ │ │ ├── request_id.go │ │ │ ├── logging.go │ │ │ ├── recovery.go │ │ │ └── cors.go -│ │ ├── proxy_handler.go # 统一代理处理器 +│ │ ├── proxy_handler.go # 统一代理处理器 │ │ ├── provider_handler.go │ │ ├── model_handler.go │ │ └── stats_handler.go -│ ├── conversion/ # 协议转换引擎 -│ │ ├── canonical/ # Canonical Model +│ ├── conversion/ # 协议转换引擎 +│ │ ├── canonical/ # Canonical Model │ │ │ ├── types.go # 核心请求/响应类型 │ │ │ ├── stream.go # 流式事件类型 │ │ │ └── extended.go # 扩展层 Models @@ -111,13 +111,12 @@ backend/ │ └── validator/ # 验证器 │ └── validator.go ├── migrations/ # 数据库迁移 -│ ├── 001_initial_schema.sql -│ └── 002_add_indexes.sql -├── tests/ # 测试 +│ ├── 20260401000001_initial_schema.sql +│ ├── 20260401000002_add_indexes.sql +│ └── 20260419000001_add_provider_protocol.sql +├── tests/ # 集成测试 │ ├── helpers.go -│ ├── integration/ -│ ├── unit/ -│ └── testdata/ +│ └── integration/ ├── Makefile ├── go.mod └── README.md @@ -133,6 +132,19 @@ handler(HTTP 请求处理) → repository(数据访问) ``` +代理请求通过 ConversionEngine 进行协议转换: + +``` +Client Request (clientProtocol) + → ProxyHandler 路由到上游 provider + → ConversionEngine 请求转换 (clientProtocol → providerProtocol) + → ProviderClient 发送请求 + → ConversionEngine 响应转换 (providerProtocol → clientProtocol) + → Client Response +``` + +同协议时自动透传,跳过序列化开销。 + ## 运行方式 ### 安装依赖 @@ -186,78 +198,44 @@ log: export NEX_SERVER_PORT=9000 export NEX_DATABASE_PATH=/data/nex.db export NEX_LOG_LEVEL=debug -./server ``` -环境变量命名规则:将配置路径转换为大写,用下划线连接,加 `NEX_` 前缀: -- `server.port` → `NEX_SERVER_PORT` -- `database.path` → `NEX_DATABASE_PATH` -- `log.level` → `NEX_LOG_LEVEL` +命名规则:配置路径转大写 + 下划线 + `NEX_` 前缀(如 `server.port` → `NEX_SERVER_PORT`)。 ### 命令行参数 -所有配置项都支持命令行参数: - ```bash ./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` +命名规则:配置路径转 kebab-case + `--` 前缀(如 `server.port` → `--server-port`)。 完整参数列表: ``` -服务器配置: - --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) +服务器: --server-port, --server-read-timeout, --server-write-timeout +数据库: --database-path, --database-max-idle-conns, --database-max-open-conns, --database-conn-max-lifetime +日志: --log-level, --log-path, --log-max-size, --log-max-backups, --log-max-age, --log-compress +通用: --config (指定配置文件路径) ``` ### 使用示例 ```bash -# 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 +# Docker 部署 +docker run -d -e NEX_SERVER_PORT=9000 -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 用 CLI,log.level 用 ENV ``` 数据文件: @@ -283,6 +261,9 @@ make migrate-up DB_PATH=~/.nex/config.db make migrate-down DB_PATH=~/.nex/config.db make migrate-status DB_PATH=~/.nex/config.db +# 创建新迁移 +make migrate-create + # 或直接使用 goose goose -dir migrations sqlite3 ~/.nex/config.db up ``` @@ -293,7 +274,7 @@ goose -dir migrations sqlite3 ~/.nex/config.db up 使用 `/{protocol}/v1/{path}` URL 前缀路由: -#### OpenAI 协议代理 +#### OpenAI 协议 ``` POST /openai/v1/chat/completions @@ -302,37 +283,13 @@ POST /openai/v1/embeddings POST /openai/v1/rerank ``` -请求示例: - -```json -{ - "model": "gpt-4", - "messages": [ - {"role": "user", "content": "Hello"} - ], - "stream": false -} -``` - -#### Anthropic 协议代理 +#### Anthropic 协议 ``` POST /anthropic/v1/messages GET /anthropic/v1/models ``` -请求示例: - -```json -{ - "model": "claude-3-opus", - "max_tokens": 1024, - "messages": [ - {"role": "user", "content": [{"type": "text", "text": "Hello"}]} - ] -} -``` - **协议转换**:网关支持任意协议间的双向转换。客户端使用 OpenAI 协议请求,上游供应商可以是 Anthropic 协议(反之亦然)。同协议时自动透传,零序列化开销。 ### 管理接口 @@ -345,8 +302,6 @@ GET /anthropic/v1/models - `PUT /api/providers/:id` - 更新供应商 - `DELETE /api/providers/:id` - 删除供应商 -创建供应商示例: - ```json { "id": "openai", @@ -357,15 +312,9 @@ GET /anthropic/v1/models } ``` -**Protocol 字段说明:** -- `protocol` 标识上游供应商使用的协议类型,可选值:`"openai"`(默认)、`"anthropic"` -- 同协议透传时,请求体和响应体原样转发,零序列化开销 +**Protocol 字段**:标识上游供应商使用的协议类型,可选值 `"openai"`(默认)、`"anthropic"`。 -**重要说明:** -- `base_url` 应配置到 API 版本路径,不包含具体端点 -- OpenAI: `https://api.openai.com/v1` -- GLM: `https://open.bigmodel.cn/api/paas/v4` -- 其他 OpenAI 兼容供应商根据其文档配置版本路径 +**base_url 说明**:应配置到 API 版本路径,不包含具体端点(如 OpenAI: `https://api.openai.com/v1`,GLM: `https://open.bigmodel.cn/api/paas/v4`)。 #### 模型管理 @@ -375,8 +324,6 @@ GET /anthropic/v1/models - `PUT /api/models/:id` - 更新模型 - `DELETE /api/models/:id` - 删除模型 -创建模型示例: - ```json { "id": "gpt-4", @@ -390,61 +337,43 @@ GET /anthropic/v1/models - `GET /api/stats` - 查询统计 - `GET /api/stats/aggregate` - 聚合统计 -查询参数: +查询参数:`provider_id`、`model_name`、`start_date`(YYYY-MM-DD)、`end_date`、`group_by`(provider/model/date) -- `provider_id` - 供应商 ID -- `model_name` - 模型名称 -- `start_date` - 开始日期(YYYY-MM-DD) -- `end_date` - 结束日期(YYYY-MM-DD) -- `group_by` - 聚合维度(provider/model/date) +#### 健康检查 + +- `GET /health` - 返回 `{"status": "ok"}` ## 开发 -### 构建 - ```bash -make build +make build # 构建 +make lint # 代码检查 +make deps # 整理依赖 ``` -### 代码检查 - -```bash -make lint -``` - -### 环境要求 - -- Go 1.26 或更高版本 +环境要求:Go 1.26 或更高版本 ## 公共库使用指南 ### pkg/errors — 结构化错误 -使用预定义的错误类型,配合 `errors.Is` / `errors.As` 判断错误: - ```go 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 } ``` -可用函数:`NewAppError`、`Wrap`、`WithContext`、`WithMessage`、`AsAppError` - -预定义错误:`ErrModelNotFound`、`ErrProviderNotFound`、`ErrInvalidRequest`、`ErrRequestCreate`、`ErrRequestSend`、`ErrResponseRead` 等 - ### pkg/logger — 日志系统 -使用依赖注入模式,构造函数接受 `*zap.Logger` 参数,nil 时回退到 `zap.L()`: +构造函数接受 `*zap.Logger` 参数,nil 时回退到 `zap.L()`: ```go func NewMyService(repo Repository, logger *zap.Logger) *MyService { @@ -455,8 +384,6 @@ func NewMyService(repo Repository, logger *zap.Logger) *MyService { } ``` -禁止直接在业务代码中使用 `zap.L()` 全局 logger,应通过构造函数注入。 - ### pkg/validator — 请求验证 ```go @@ -468,8 +395,8 @@ err := v.Validate(myStruct) ## 编码规范 -- **JSON 解析**:使用 `encoding/json` 标准库(`json.Unmarshal` / `json.Marshal`),不手动扫描字节 +- **JSON 解析**:使用 `encoding/json` 标准库,不手动扫描字节 - **字符串拼接**:使用 `strings.Join`,不手写循环拼接 -- **错误判断**:使用 `errors.Is` / `errors.As`,不使用字符串匹配(`strings.Contains(err.Error(), ...)`) +- **错误判断**:使用 `errors.Is` / `errors.As`,不使用字符串匹配 - **日志使用**:通过依赖注入 `*zap.Logger`,不直接调用 `zap.L()` -- **字符串分割**:使用 `strings.SplitN(key, "/", 2)` 等精确分割,不使用索引切片 +- **字符串分割**:使用 `strings.SplitN` 等精确分割,不使用索引切片