1
0
lanyuanxiaoyao 2c401f7ae6 chore: streamline workspace make workflows
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.
2026-04-28 17:44:23 +08:00
2026-04-26 21:48:17 +08:00
2026-04-22 19:27:27 +08:00
2026-04-26 12:24:03 +08:00
2026-04-15 16:53:28 +08:00
2026-04-15 16:53:28 +08:00
2026-04-22 19:27:27 +08:00

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 双向转换
  • 统一模型 IDprovider_id/model_name 格式全局唯一标识模型(如 openai/gpt-4
  • Smart Passthrough:同协议请求跳过 Canonical 全量转换,仅在 JSON 层改写 model 字段
  • 流式响应:完整支持 SSE 流式传输,包括跨协议流式转换
  • Function Calling支持工具调用Tools
  • Thinking / Reasoning:支持 OpenAI reasoning_effort 和 Anthropic thinking 配置
  • 扩展接口:支持 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"}

模块命名规范:

  • 单一职责包:databaseconfig
  • 多实体包:handler.proxyservice.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.appWindows: nex-win-amd64.exeLinux: 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 时去掉 /v1Anthropic adapter 接收 /v1/messages/v1/models。因此 OpenAI 供应商 base_url 配置到版本路径一级(如 https://api.openai.com/v1Anthropic 供应商 base_url 配置到域名级(如 https://api.anthropic.com)。

代理错误边界:网关层错误统一返回 {"error":"...","code":"..."},例如 INVALID_JSONMODEL_NOT_FOUNDCONVERSION_FAILEDUPSTREAM_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 由系统自动生成 UUIDprovider_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_idmodel_namestart_dateend_dategroup_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.portNEX_SERVER_PORT)。

CLI 参数

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

命名规则:配置路径转 kebab-caseserver.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.mdfrontend/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 由仓库工具同步,不能手工漂移

本地版本演进

  1. 手工修改根目录 VERSION 为新的 x.y.z
  2. 同步镜像文件:
make version-sync
  1. 校验版本一致性:
make version-check
  1. 提交版本变更后,创建发布 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.Z tag 后,.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

Description
No description provided
Readme 8 MiB
Languages
Go 75.3%
TypeScript 13.4%
Python 9.5%
Makefile 1.2%
JavaScript 0.5%