Clarify product-level server and desktop commands while moving backend-only maintenance tasks into backend/Makefile. This keeps root automation focused on core flows and aligns the main OpenSpec specs with the new command boundaries.
13 KiB
Nex - AI Gateway
一个统一的大模型 API 网关,支持 OpenAI 和 Anthropic 双协议,让应用只需配置一个地址即可透明使用多个供应商的大模型服务。
项目结构
nex/
├── backend/ # Go 后端服务(分层架构)
│ ├── cmd/
│ │ ├── server/ # CLI 主程序入口
│ │ └── desktop/ # 桌面应用入口
│ ├── internal/
│ │ ├── handler/ # HTTP 处理器 + 中间件
│ │ ├── service/ # 业务逻辑层
│ │ ├── repository/ # 数据访问层
│ │ ├── domain/ # 领域模型
│ │ ├── conversion/ # 协议转换引擎(OpenAI/Anthropic 适配器)
│ │ ├── provider/ # 供应商客户端
│ │ └── config/ # 配置管理
│ ├── pkg/ # 公共包(logger/errors/validator)
│ ├── migrations/ # 数据库迁移
│ └── tests/ # 测试(unit/integration)
│
├── frontend/ # React 前端界面
│ ├── src/
│ │ ├── api/ # API 层(统一请求封装 + 字段转换)
│ │ ├── hooks/ # TanStack Query hooks
│ │ ├── components/ # 通用组件(AppLayout)
│ │ ├── pages/ # 页面(Providers, Stats)
│ │ ├── routes/ # React Router 路由配置
│ │ ├── types/ # TypeScript 类型定义
│ │ └── __tests__/ # 单元测试 + 组件测试
│ ├── e2e/ # Playwright E2E 测试
│ └── package.json
│
├── assets/ # 应用资源
│ ├── icon.png # 托盘图标
│ ├── icon.icns # macOS 应用图标
│ └── icon.ico # Windows 应用图标
│
└── README.md # 本文件
功能特性
- 双协议支持:同时支持 OpenAI 和 Anthropic 协议
- 跨协议转换:Hub-and-Spoke 架构实现 OpenAI ↔ Anthropic 双向转换
- 统一模型 ID:
provider_id/model_name格式全局唯一标识模型(如openai/gpt-4) - Smart Passthrough:同协议请求跳过 Canonical 全量转换,仅在 JSON 层改写 model 字段
- 流式响应:完整支持 SSE 流式传输,包括跨协议流式转换
- Function Calling:支持工具调用(Tools)
- Thinking / Reasoning:支持 OpenAI
reasoning_effort和 Anthropicthinking配置 - 扩展接口:支持 Embeddings 和 Rerank 接口
- 多供应商管理:配置和管理多个供应商(供应商 ID 仅限字母、数字、下划线)
- 用量统计:按供应商、模型、日期统计请求数量
- Web 配置界面:提供供应商和模型配置管理
技术栈
后端
- 语言: Go 1.26+
- HTTP 框架: Gin
- ORM: GORM
- 数据库: SQLite / MySQL
- 日志: zap + lumberjack(结构化日志 + 日志轮转 + 模块标识)
- 配置: Viper + pflag(多层配置:CLI > 环境变量 > 配置文件 > 默认值)
- 验证: go-playground/validator/v10
- 迁移: goose
日志模块标识规范
每个模块通过依赖注入获取带模块标识的 logger,日志输出格式为 [module.name]:
Console: INFO [handler.proxy] 处理请求 method=POST path=/v1/chat
JSON: {"level":"info","logger":"handler.proxy","msg":"处理请求","method":"POST"}
模块命名规范:
- 单一职责包:
database、config - 多实体包:
handler.proxy、service.provider - 子包:
handler.middleware
前端
- 运行时: Bun
- 构建工具: Vite
- 语言: TypeScript (strict mode)
- 框架: React
- UI 组件库: TDesign React
- 图表库: Recharts
- 路由: React Router v7
- 数据获取: TanStack Query v5
- 样式: SCSS Modules
- 测试: Vitest + React Testing Library + Playwright
快速开始
桌面应用(推荐)
构建桌面应用:
# macOS (arm64 + amd64,并打包为 .app)
make desktop-build-mac
# Windows
make desktop-build-win
# Linux
make desktop-build-linux
使用桌面应用:
- 双击启动应用(macOS: Nex.app,Windows: nex-win-amd64.exe,Linux: nex-linux-amd64)
- 系统托盘图标出现,浏览器自动打开管理界面
- 点击托盘图标显示菜单,可打开管理界面或退出
- 关闭浏览器后服务继续运行,可通过托盘重新打开
注意事项:
- 桌面应用需要 CGO 支持
- macOS: 自带 Xcode Command Line Tools
- Linux: 自带 gcc,部分桌面环境需要
libappindicator3-dev - Windows: 需要 MinGW-w64 或在 Windows 环境构建
Linux 桌面环境兼容性:
- GNOME: 需要 AppIndicator 扩展
- KDE Plasma: 原生支持
- Xfce: 需要 libappindicator
- 其他支持 StatusNotifierItem 规范的环境
Server 模式(前后端分离)
make server-run
make server-run 会并行启动:
- 后端服务:
http://localhost:9826 - 前端开发服务器:
http://localhost:5173
前端请求会继续通过 Vite proxy 转发到后端。后端首次启动会自动:
- 创建配置文件
~/.nex/config.yaml - 初始化数据库
~/.nex/config.db - 运行数据库迁移
- 创建日志目录
~/.nex/log/
构建 server 模式产物:
make server-build
API 接口
代理接口(对外部应用)
代理接口统一使用 /{protocol}/*path 路由格式,模型 ID 使用 provider_id/model_name 格式(如 openai/gpt-4)。同协议请求走 Smart Passthrough,最小化 JSON 改写并保持未改写字段的 JSON 内容和类型不变;跨协议请求走完整 decode/encode 转换。
OpenAI 协议(protocol=openai):
POST /openai/v1/chat/completions- 对话补全GET /openai/v1/models- 模型列表(本地数据库聚合)GET /openai/v1/models/{provider_id}/{model_name}- 模型详情(本地数据库查询)POST /openai/v1/embeddings- 嵌入POST /openai/v1/rerank- 重排序
Anthropic 协议(protocol=anthropic):
POST /anthropic/v1/messages- 消息对话GET /anthropic/v1/models- 模型列表(本地数据库聚合)GET /anthropic/v1/models/{provider_id}/{model_name}- 模型详情(本地数据库查询)
路径边界:网关只剥离第一段协议前缀,剩余路径保持协议原生形态交给 adapter。OpenAI adapter 接收 /v1/chat/completions、/v1/models、/v1/embeddings、/v1/rerank,并在构建上游 URL 时去掉 /v1;Anthropic adapter 接收 /v1/messages、/v1/models。因此 OpenAI 供应商 base_url 配置到版本路径一级(如 https://api.openai.com/v1),Anthropic 供应商 base_url 配置到域名级(如 https://api.anthropic.com)。
代理错误边界:网关层错误统一返回 {"error":"...","code":"..."},例如 INVALID_JSON、MODEL_NOT_FOUND、CONVERSION_FAILED、UPSTREAM_UNAVAILABLE。只要上游已经返回 HTTP 响应,非 2xx 的 status、过滤 hop-by-hop header 后的 headers 和 body 会直接透传,不包装为应用错误或协议错误。
模型路由边界:只有 adapter 明确适配的接口会解析请求体中的 model 并使用统一模型 ID 路由;未知接口即使包含顶层 model 也按无 model 透传处理。
流式边界:同协议无响应 model 改写时原样透传 SSE frame 和 [DONE];同协议需要响应 model 改写时只解析 SSE frame 的 data JSON 并改写 model;跨协议流式仍走 provider decoder → Canonical stream event → client encoder。
管理接口(对前端)
供应商管理
GET /api/providers- 列出所有供应商POST /api/providers- 创建供应商(id仅限字母、数字、下划线,长度 1-64)GET /api/providers/:id- 获取供应商PUT /api/providers/:id- 更新供应商(id不可修改)DELETE /api/providers/:id- 删除供应商
模型管理
GET /api/models- 列出模型(支持?provider_id=xxx过滤)POST /api/models- 创建模型(id由系统自动生成 UUID,provider_id+model_name联合唯一)GET /api/models/:id- 获取模型(响应含unified_id字段,格式provider_id/model_name)PUT /api/models/:id- 更新模型(不可修改id)DELETE /api/models/:id- 删除模型
统计查询
GET /api/stats- 查询统计GET /api/stats/aggregate- 聚合统计
查询参数支持:provider_id、model_name、start_date、end_date、group_by
配置
配置支持多种方式,优先级为:CLI 参数 > 环境变量 > 配置文件 > 默认值
配置文件
配置文件位于 ~/.nex/config.yaml,首次启动自动生成:
server:
port: 9826
read_timeout: 30s
write_timeout: 30s
database:
driver: sqlite # sqlite 或 mysql
path: ~/.nex/config.db # SQLite 数据库文件路径
# --- MySQL 配置(driver=mysql 时生效)---
# host: localhost
# port: 3306
# user: nex
# password: ""
# dbname: nex
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
# MySQL 模式
export NEX_DATABASE_DRIVER=mysql
export NEX_DATABASE_HOST=db.example.com
export NEX_DATABASE_PORT=3306
export NEX_DATABASE_USER=nex
export NEX_DATABASE_PASSWORD=secret
export NEX_DATABASE_DBNAME=nex
命名规则:配置路径转大写 + 下划线(如 server.port → NEX_SERVER_PORT)。
CLI 参数
./server --server-port 9000 --log-level debug --database-path /tmp/test.db
命名规则:配置路径转 kebab-case(如 server.port → --server-port)。
数据文件
~/.nex/config.yaml- 配置文件~/.nex/config.db- SQLite 数据库(MySQL 模式下不使用本地数据库文件)~/.nex/log/- 日志目录
测试
# 全局默认测试(不含 MySQL 和前端 E2E)
make test
# 产品级测试
make server-test
make desktop-test
backend 分类测试、MySQL 专项测试和前端 E2E 测试请分别查看 backend/README.md 与 frontend/README.md。
开发
# 首次克隆后安装 Git hooks
lefthook install
# 全局命令
make lint # 前后端共享检查
make test # 默认全量测试(不含 MySQL/E2E)
make clean # 清理所有构建产物和测试报告
# server 模式
make server-run # 并行启动后端和前端开发服务
make server-build # 构建 backend/bin/server 和 frontend/dist
make server-lint # server 模式检查
make server-test # server 模式测试
make server-clean # 清理 server 模式产物
# desktop 模式
make desktop-build-mac # 构建 macOS 桌面应用
make desktop-build-win # 构建 Windows 桌面应用
make desktop-build-linux # 构建 Linux 桌面应用
make desktop-lint # desktop 模式检查
make desktop-test # desktop 专属测试
make desktop-clean # 清理 desktop 产物
版本与发布
统一版本源
- 仓库根目录
VERSION是全仓唯一版本源,格式固定为x.y.z frontend/package.json和前端.env.*中的VITE_APP_VERSION由仓库工具同步,不能手工漂移
本地版本演进
- 手工修改根目录
VERSION为新的x.y.z - 同步镜像文件:
make version-sync
- 校验版本一致性:
make version-check
- 提交版本变更后,创建发布 tag:
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin main
git push origin vX.Y.Z
本地生成发布资产
# Linux: server + desktop
make release-assets-linux
# Windows: server + desktop(需在 Windows 环境执行)
make release-assets-windows
# macOS: darwin-amd64 server、darwin-arm64 server、desktop universal
make release-assets-macos
生成的版本化发布资产位于 build/release/。
GitHub Draft Release
- 推送
vX.Y.Ztag 后,.github/workflows/release.yml会自动执行发布流水线 - 流水线会先校验 tag 与
VERSION一致,再构建以下资产并上传到 GitHub Draft Release:- Linux server
- Windows server
- darwin-amd64 server
- darwin-arm64 server
- Linux desktop
- Windows desktop
- macOS desktop universal
- Release 默认以 Draft 形式创建,需人工检查后再公开发布
开发规范
详见各子项目的 README.md:
许可证
Apache License 2.0