# llm-gateway **Repository Path**: gitcrazy/llm-gateway ## Basic Information - **Project Name**: llm-gateway - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-19 - **Last Updated**: 2026-10-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # LLM Gateway 企业内统一 LLM 网关。对外**只暴露 OpenAI 兼容协议**,业务方把 `base_url` 换掉即可接入; 对内统一管理上游渠道、模型路由、API Key 鉴权、限流配额与计费。 ## 技术栈 | 层 | 选型 | |---|---| | 后端 | JDK 21 / Spring Boot 3.5.16 / Spring Cloud 2025.0 / WebFlux | | 前端 | Vue 2.7 / ant-design-vue 1.7.8 / webpack 5 | | 存储 | MySQL 8(Flyway 迁移)/ Redis 单实例(database 6) | | 部署 | Docker Compose + Nginx | ## 模块 ``` gateway-core 协议模型、错误码体系、token 估算、API Key 工具(无框架依赖) gateway-admin JPA 实体与仓储、Flyway 迁移、JWT 鉴权、管理 REST API gateway-server /v1 函数式端点、上游适配转发、限流配额、计费落库 gateway-web 管理后台前端 deploy Dockerfile / compose / nginx / mock 上游 / redis 哨兵配置 docs 设计文档与接口契约 scripts 接入验证脚本 ``` ## 快速开始 ```bash # 1. 起依赖(MySQL + Redis + 网关 + Nginx) cd deploy docker compose up -d # 2. 网关 # http://localhost:8090 网关本体(/v1、/api/admin、/healthz) # http://localhost:8080 经 Nginx(前端 + 反向代理,用于验证生产链路) # 3. 前端开发 cd gateway-web npm install # postinstall 会自动打 vue-loader 补丁 npm run dev # http://localhost:8081 npm run build # 产物在 dist/ ``` 管理后台默认账号 `admin / admin123`,首次登录后请立即修改。 ## 构建与环境配置 配置拆为三份:`application.yml`(公共)+ `application-dev.yml` / `application-prod.yml` (环境差异),由 `spring.profiles.active` 决定加载哪个环境文件并与公共配置合并: - **默认构建(dev)**:`mvn package`,jar 内默认激活 `dev`; - **prod 构建**:`mvn clean package -Pprod`,jar 内默认激活 `prod` (Dockerfile 构建时已自动带 `-Pprod`,可直接 `docker compose up -d --build`); - **运行时覆盖**:环境变量 `SPRING_PROFILES_ACTIVE` 优先级最高,可用 dev 包连生产配置做诊断。 ```bash # 注意:命令行编译请用 JDK 21(若 shell 的 JAVA_HOME 指向 JDK 8 会报一堆假错) JAVA_HOME="C:\Program Files\Java\jdk-21.0.11" mvn clean package -Pprod -DskipTests ``` > **本地一定要用 `docker compose` 起网关,不要手敲 `docker run`。** > 漏掉 `GW_AES_KEY` 会让上游调用报 `Tag mismatch`;漏掉 `REDIS_PASSWORD` 会让限流 > **静默失效**(走降级放行,只在日志留一条 warn)——后者不报错,极难发现。 > 详见 `docs/01-总体设计方案.md` 第 14.4 节。 > > **Redis 为单实例模式**(应用默认使用 database 6)。compose 里的 `redis` 服务开箱即用; > 宿主机 IDE 直跑网关时默认连 `localhost:6379`,全部变量:`REDIS_HOST` / `REDIS_PORT` / > `REDIS_PASSWORD` / `REDIS_DATABASE`。 ## 调用方式 网关对外就是 OpenAI 协议,SDK 无需改动,只换 `base_url`: ```python from openai import OpenAI client = OpenAI(base_url="http://localhost:8090/v1", api_key="sk-gw-xxxx") resp = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}], ) ``` 或直接用 curl: ```bash curl -s http://localhost:8090/v1/chat/completions \ -H "Authorization: Bearer sk-gw-xxxx" \ -H 'Content-Type: application/json' \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"你好"}]}' ``` 完整的接入验证(模型列表 / 非流式 / 流式 / 错误分支): ```bash LLM_GW_KEY=sk-gw-xxxx python scripts/test_api_key.py ``` ## 流式协议的约定 流式响应末尾会比 OpenAI 多**一帧**用量帧,因为原生协议不回传流式 usage, 而计费必须拿到 token 数: ``` data:{"choices":[{"finish_reason":"stop"}...]} data:{"choices":[],"usage":{"prompt_tokens":42,"completion_tokens":28}} ← 网关补的 data:[DONE] ``` SDK 里必须判空,否则 `choices[0]` 会抛 `IndexError`: ```python for chunk in stream: if not chunk.choices: # 用量帧或心跳,跳过 continue print(chunk.choices[0].delta.content or "", end="") ``` ## 错误码 | HTTP | `error.code` | 含义 | |---|---|---| | 401 | `invalid_api_key` | Key 不存在或已禁用 | | 403 | `model_not_allowed` | 该 Key 无权访问此模型 | | 404 | `model_not_found` | 模型不存在 | | 429 | `rate_limit_exceeded` | 超过 RPM/TPM | | 429 | `quota_exhausted` | 日/月配额用尽 | | 502 | `upstream_error` | 上游调用失败 | | 503 | `no_available_channel` | 无可用渠道 | `499 client_closed` 不返回给客户端,只落 `llm_gateway_usage_record.status`,用于标记客户端提前断开; 这类请求**仍按已生成部分计费**。 ## 文档 - [`docs/01-总体设计方案.md`](docs/01-总体设计方案.md) — 架构、关键决策、数据模型、 流式与路由的实现细节,以及 14 节**实测踩坑记录**(含每条的根因与修复) - [`docs/02-接口与数据模型.md`](docs/02-接口与数据模型.md) — 管理 API 契约与 DDL ## 生产部署前必改 以下默认值仅用于本地开发,上线前必须通过环境变量覆盖: | 变量 | 说明 | |---|---| | `GW_AES_KEY` | 加密上游渠道 apiKey,32 字节。**换值后必须重建所有渠道 apiKey**,否则旧密文解不开 | | `DB_HOST` / `DB_USER` / `DB_PASSWORD` | MySQL 地址与凭证(prod 配置**无默认值**,漏配启动即失败) | | `REDIS_HOST` / `REDIS_PASSWORD` | Redis 地址与密码(prod 配置无默认值;`REDIS_PORT` 默认 6379) | | `REDIS_DATABASE` | Redis 逻辑库编号(默认 6,与其他应用共用实例时做隔离) | | `CLICKHOUSE_HOST` / `CLICKHOUSE_PASSWORD` | ClickHouse 地址与密码(prod 配置无默认值) | `application-prod.yml` 里所有主机与凭证均不提供 localhost / 开发密码兜底(fail-fast): 漏配环境变量会在启动时报占位符解析错误,而不是运行后才出现连接异常或静默故障。 `docker compose` 已为 gateway 注入全部所需变量。