一个面向内部团队或小规模外部用户的 LLM API 中转站 MVP。项目提供 OpenAI 兼容接口,对接多个上游 provider,隐藏真实上游 API Key,并实现虚拟 Key、模型路由、限流、预算控制、用量审计、流式透传、基础 fallback 与 Prometheus 指标。
核心分层:
cmd/server: 进程入口。internal/config: YAML + 环境变量配置加载。internal/http: Gin 路由、公共接口、管理接口。internal/middleware: request_id、访问日志、虚拟 Key 鉴权、admin token 鉴权。internal/service: 鉴权、路由、网关转发、管理能力、成本计算封装。internal/provider: 上游 provider 抽象与 OpenAI-compatible 实现。internal/repository: PostgreSQL 仓储。internal/ratelimit: Redis RPM/TPM 限流。internal/budget: 日/月预算判断。internal/metrics: Prometheus 指标。pkg/*: 通用工具,如日志、hash、cost、token 估算、request_id。
请求主链路:
- 生成或透传
request_id - Bearer 虚拟 Key 鉴权
- 校验模型白名单
- 估算 tokens / cost
- 校验预算
- 校验 RPM / TPM
- 根据
model_mappings路由到 provider - 调用上游,失败时按顺序 fallback
- 记录
usage_logs - 返回 OpenAI 风格响应或 SSE 流式透传
cmd/server/main.go
config/config.example.yaml
internal/
app/
budget/
config/
http/
metrics/
middleware/
model/
provider/
ratelimit/
repository/
service/
pkg/
cost/
hashutil/
logger/
requestid/
token/
migrations/001_init.sql
seeds/001_seed.sql
Dockerfile
docker-compose.yml
docker compose up --build默认会启动:
- PostgreSQL:
localhost:5432 - Redis:
localhost:6379 - App:
localhost:8080
环境变量:
OPENAI_API_KEYOPENAI_API_KEY_BACKUP可选
- 准备 PostgreSQL 和 Redis。
- 执行迁移和 seed。
- 拷贝配置并填充环境变量。
cp config/config.example.yaml config/config.yaml
export POSTGRES_DSN='postgres://postgres:postgres@localhost:5432/llm_gateway?sslmode=disable'
export REDIS_ADDR='localhost:6379'
export ADMIN_TOKEN='admin-secret-token'
export PROVIDER_OPENAI-MAIN_API_KEY='sk-xxx'
export PROVIDER_OPENAI-BACKUP_API_KEY='sk-yyy'
GOCACHE=$(pwd)/.gocache go run ./cmd/server补充说明:
- 环境变量会覆盖
config/config.yaml中的同名配置。 - 如果之前 shell 中残留了错误的
POSTGRES_DSN、REDIS_ADDR、ADMIN_TOKEN,服务可能会以错误配置启动。 - 建议优先使用项目内脚本:
./scripts/build-linux-amd64.sh
./scripts/run-vps.sh其中:
build-linux-amd64.sh适合在 macOS / Linux 上交叉编译 VPS 可执行文件run-vps.sh会显式设置 VPS 本机常用依赖地址,避免旧环境变量污染
配置文件示例见 config/config.example.yaml。
关键环境变量覆盖:
APP_PORTPOSTGRES_DSNREDIS_ADDRREDIS_PASSWORDADMIN_TOKENPROVIDER_<NAME>_BASE_URLPROVIDER_<NAME>_API_KEYPROVIDER_<NAME>_TIMEOUT_MS
说明:
- provider 的敏感 key 优先从环境变量注入,不建议写入数据库。
- 当前通过 provider 名称匹配配置覆盖,例如
openai-main对应PROVIDER_OPENAI-MAIN_API_KEY。
迁移脚本:
初始化数据:
手动初始化示例:
psql 'postgres://postgres:postgres@localhost:5432/llm_gateway?sslmode=disable' -f migrations/001_init.sql
psql 'postgres://postgres:postgres@localhost:5432/llm_gateway?sslmode=disable' -f seeds/001_seed.sql公共接口:
GET /healthzGET /metricsGET /v1/modelsPOST /v1/chat/completionsPOST /v1/embeddings
管理接口:
POST /admin/api-keysGET /admin/api-keysPATCH /admin/api-keys/:idGET /admin/usageGET /admin/providersPATCH /admin/providers/:idGET /admin/ui
curl -X POST http://localhost:8080/admin/api-keys \
-H 'Authorization: Bearer admin-secret-token' \
-H 'Content-Type: application/json' \
-d '{
"name":"demo-key",
"project_id":"demo",
"allowed_models":["gpt-4o-mini","text-embedding-3-small"],
"rpm_limit":60,
"tpm_limit":120000,
"daily_budget":5,
"monthly_budget":100,
"status":"enabled"
}'响应中会返回一次性明文 raw_key。
curl http://localhost:8080/v1/models \
-H 'Authorization: Bearer lgw_xxx'curl http://localhost:8080/v1/chat/completions \
-H 'Authorization: Bearer lgw_xxx' \
-H 'Content-Type: application/json' \
-d '{
"model":"gpt-4o-mini",
"messages":[
{"role":"system","content":"You are a helpful assistant."},
{"role":"user","content":"Say hello in Chinese."}
]
}'curl http://localhost:8080/v1/chat/completions \
-H 'Authorization: Bearer lgw_xxx' \
-H 'Content-Type: application/json' \
-N \
-d '{
"model":"gpt-4o-mini",
"stream":true,
"messages":[
{"role":"user","content":"Write a short haiku about gateways."}
]
}'curl http://localhost:8080/v1/embeddings \
-H 'Authorization: Bearer lgw_xxx' \
-H 'Content-Type: application/json' \
-d '{
"model":"text-embedding-3-small",
"input":"hello gateway"
}'curl http://localhost:8080/admin/providers \
-H 'Authorization: Bearer admin-secret-token'curl -X PATCH http://localhost:8080/admin/providers/1 \
-H 'Authorization: Bearer admin-secret-token' \
-H 'Content-Type: application/json' \
-d '{"enabled":true,"timeout_ms":45000,"max_retries":2}'curl http://localhost:8080/admin/usage \
-H 'Authorization: Bearer admin-secret-token'
## VPS 打包部署
如果目标是把一整套可运行目录带到 Debian 12 `linux/amd64` 的 VPS,上线前直接在本地执行:
```bash
./scripts/package-vps.sh产物:
dist/nexusai-linux-amd64/dist/nexusai-linux-amd64.tar.gz
目录内已经包含:
bin/nexusai-linux-amd64config/config.yamlmigrations/001_init.sqlseeds/001_seed.sqlscripts/run-vps.shsystemd/nexusai.service
推荐上传和启动:
scp dist/nexusai-linux-amd64.tar.gz root@<VPS_IP>:/opt/
ssh root@<VPS_IP>
cd /opt
tar -xzf nexusai-linux-amd64.tar.gz
mv nexusai-linux-amd64 nexusai
cd /opt/nexusai
vim config/config.yaml
./scripts/run-vps.sh如果要长期运行,复制 systemd/nexusai.service 到 /etc/systemd/system/nexusai.service,然后执行:
systemctl daemon-reload
systemctl enable --now nexusai
systemctl status nexusai
### 8. Web 管理后台
浏览器访问:
```text
http://localhost:8080/admin/ui
首次打开后在页面左侧填入 ADMIN_TOKEN,即可查看并管理:
- API Keys
- Providers
- Usage 汇总
- 服务健康状态
Prometheus 指标由 /metrics 暴露,包含:
- 总请求数
- 成功请求数
- 失败请求数
- 按 provider 统计请求数
- 按 model 统计请求数
- 请求延迟直方图
- 限流次数
- fallback 次数
已覆盖的单测:
- API Key 鉴权
- 模型映射 / fallback 路由
- Redis 限流逻辑
- 预算判断
- provider fallback
- 成本价格注册
运行:
GOCACHE=$(pwd)/.gocache go test ./...- OpenAI 兼容
models/chat/embeddings接口 - OpenAI-compatible provider 抽象实现
- 虚拟 Key 鉴权与模型白名单
- Redis RPM / TPM 限流
- PostgreSQL 用量审计
- 日/月预算控制
- 简单 provider fallback
- SSE 流式透传
- 上游失败/限流/超时的有限重试与回退
- JSON 结构化日志
- request_id 响应头和链路字段
- provider API key 当前建议通过环境变量覆盖,数据库里只保留
api_key_ref/占位字段,不做真实加密存储。 - token 统计在上游未返回 usage 时使用近似估算,而不是 tokenizer 精算。
- 预算按
usage_logs聚合,未额外实现高并发预算计数表。 - fallback 采用简单顺序尝试,不包含复杂策略引擎。
- Anthropic / Gemini 只预留了 provider type 扩展位,未实现具体适配。
model_mappings的管理接口未在本次 MVP 中开放,当前通过 SQL seed 管理。- Web 管理后台为服务内嵌静态页面,不依赖 Node 构建链,也未实现复杂登录态,仅使用 admin token 调用后端管理接口。
- provider secrets 加密存储和 KMS 集成
- 更精确的 tokenizer / cost versioning
- model mappings / pricing 的管理 API
- 多租户项目维度报表和导出
- 异步审计流水和更细粒度告警
- 熔断、健康打分、动态路由策略
- Anthropic / Gemini 原生适配器