1
0
Files
nex/README.md
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

379 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 和 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"}
```
模块命名规范:
- 单一职责包:`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
## 快速开始
### 桌面应用(推荐)
**构建桌面应用**
```bash
# 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 模式(前后端分离)
```bash
make server-run
```
`make server-run` 会并行启动:
- 后端服务:`http://localhost:9826`
- 前端开发服务器:`http://localhost:5173`
前端请求会继续通过 Vite proxy 转发到后端。后端首次启动会自动:
- 创建配置文件 `~/.nex/config.yaml`
- 初始化数据库 `~/.nex/config.db`
- 运行数据库迁移
- 创建日志目录 `~/.nex/log/`
**构建 server 模式产物**
```bash
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`,首次启动自动生成:
```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_` 前缀:
```bash
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 参数
```bash
./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/` - 日志目录
## 测试
```bash
# 全局默认测试(不含 MySQL 和前端 E2E
make test
# 产品级测试
make server-test
make desktop-test
```
backend 分类测试、MySQL 专项测试和前端 E2E 测试请分别查看 `backend/README.md``frontend/README.md`
## 开发
```bash
# 首次克隆后安装 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. 同步镜像文件:
```bash
make version-sync
```
3. 校验版本一致性:
```bash
make version-check
```
4. 提交版本变更后,创建发布 tag
```bash
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin main
git push origin vX.Y.Z
```
### 本地生成发布资产
```bash
# 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
- [后端 README](backend/README.md) - 分层架构、依赖注入、数据库迁移
- [前端 README](frontend/README.md) - TypeScript strict、SCSS Modules、测试策略
## 许可证
Apache License 2.0