自建 AI 网关 Docker 运维 OpenAI 兼容

自建 LLM API 网关:架构与运维

用 Docker 部署自建 LLM API 网关,配置多供应商通道、作用域密钥、使用日志与 OpenAI 兼容端点。

AveMujica API 2 分钟阅读

自建 LLM API 网关是你在自有网络或云账户中运行的软件:它接受 OpenAI 兼容请求,认证调用方,把流量路由到一个或多个上游模型供应商,并为运维与成本控制记录用量。与纯反向代理不同,它是控制面:密钥、模型别名、通道凭证、配额与请求历史都靠近请求路径。本文说明何时值得自建、可从本仓库这类 Go 网关期望何种架构,以及如何运维它,而不把模型访问变成无人负责的黑盒。

如果仍在薄转发层与控制面之间选择,请先阅读 LLM 代理与 AI 网关。本文假定你已经需要网关职责,并希望获得一个可部署的基线。

何时自建是正确默认

至少满足以下两条时,自建网关:

  • 供应商 API Key 不能分发给每个应用环境
  • 多个产品或团队在不同预算下共享模型访问
  • 需要落在自有留存边界内的请求级日志
  • 数据路径或采购规则更倾向你运维的基础设施
  • 希望在不重写客户端的情况下做多供应商路由
  • SaaS 网关约束(数据驻留、网络出口、变更控制)不合适

当单一原型只用一把密钥、一个模型且无审计要求时,自建是错误默认。那时直接调用供应商或使用薄代理,直到控制面需求出现。

参考架构

Clients (apps, agents, eval jobs)
        |
        |  HTTPS + Bearer gateway key
        v
 Self-hosted AI gateway
   - OpenAI-compatible API (/v1/chat/completions, /v1/responses, ...)
   - Admin API for users, tokens, channels
   - Usage logs, dashboard, pricing context
        |
        +--> Channel: OpenAI
        +--> Channel: Anthropic / Claude (native Messages adaptation)
        +--> Channel: Gemini
        +--> Channel: Azure / Bedrock / others
        |
        v
 Your datastore (SQLite / MySQL / PostgreSQL)
 optional Redis for cache and rate limiting

客户端继续使用 OpenAI SDK 或原始 HTTP。上游多样性是配置,不是每个供应商一个新 SDK。这与 兼容 OpenAI 的 API 网关 的价值主张相同,额外要求是你拥有可用性与备份。

本仓库形态网关通常包含什么

本项目是可自建的 Go 网关与 AI 资产管理式系统。规划时重要的仓库可见能力:

  • 聊天及相关表面的 OpenAI 兼容中继端点
  • 多供应商通道配置
  • 用于作用域访问的用户/令牌管理
  • 使用日志与运维看板
  • 与服务一起嵌入的 Web 管理 UI
  • 简单部署用 SQLite;耐用多用户生产用 MySQL 或 PostgreSQL
  • 使用已发布镜像 calciumion/new-api 的 Docker 部署路径

不要编造合规认证或未声明的 SLA。在向干系人承诺前,对照你运行版本的 UI 与 API 验证确切功能集。

已验证的最小 Docker 路径

仓库提供真实的 docker-compose.yml,使用 PostgreSQL 和 Redis 运行网关。这是多用户预发环境的推荐起点。项目 README 中的快速路径:

docker pull calciumion/new-api:latest
# from a checkout that includes docker-compose.yml
docker compose up -d
# gateway listens on http://localhost:3000 by default

核心服务形态如下,内容从仓库 compose 文件中缩减;Redis/Postgres 服务、健康检查和注释仍应保留完整文件:

services:
  new-api:
    image: calciumion/new-api:latest
    container_name: new-api
    restart: always
    command: --log-dir /app/logs
    ports:
      - "3000:3000"
    volumes:
      - ./data:/data
      - ./logs:/app/logs
    environment:
      # Change passwords before any shared or production use.
      - SQL_DSN=postgresql://root:123456@postgres:5432/new-api
      - REDIS_CONN_STRING=redis://:123456@redis:6379
      - TZ=Asia/Shanghai
      - ERROR_LOG_ENABLED=true
      - BATCH_UPDATE_ENABLED=true
      - NODE_NAME=new-api-node-1
    depends_on:
      - redis
      - postgres

以下运维说明使示例保持诚实:

  • compose 的默认密码(123456)只用于本地启动。进入任何共享环境前必须轮换。
  • 受监管环境应固定镜像 digest,而不是使用文档中的浮动 :latest 标签。
  • 对于单节点 SQLite 实验,README 也记录了挂载 /data 且不设置 SQL_DSN 的容器运行方式;应把它视为小规模路径,而不是多写入者生产环境。
  • 在入口(nginx、Caddy、云负载均衡器、Traefik)终止 TLS。没有额外访问控制时,不要把管理 UI 路径暴露到公网。
  • 首次登录后,供应商 API 密钥应进入通道配置或密钥管理器,不能进入 git。

如果由于隔离网络镜像仓库或自定义编排而无法原样使用 Docker Compose,请把该片段视为需要转换的已验证基线,而不是可选伪代码。上面的镜像名、端口、卷和 SQL_DSN 变量都与本仓库发布的部署文档一致。

第一周配置清单

1. 身份与密钥

  • 用强认证创建管理员用户
  • 为每个服务签发最小模型作用域令牌
  • 分离预发与生产密钥
  • 记录轮换负责人

2. 通道

在管理 UI 的通道配置中:

  • 每个上游凭证边界一个通道
  • 为 Azure/区域端点写明 base URL
  • 凭证变化后运行健康检查或手动冒烟测试
  • 绝不要让互不信任的租户共享一把不受限的上游密钥

3. 目录与价格上下文

  • 发布应用依赖的稳定模型别名(claude-sonnet、gemini-flash、gpt-...)
  • 把别名映射到当前上游 ID,例如切换时供应商列出的 Claude Sonnet 5 / Opus 4.8 与 Gemini 3.5 Flash 类模型
  • 默认别名变化时复核定价上下文

4. 可观测性

  • 为计费路由启用使用日志
  • 确认日志留存和导出路径
  • 对错误率和支出速度告警,而不只是 CPU

5. 备份

  • 自动执行数据库备份(PostgreSQL/MySQL dump 或卷快照)
  • 在第一次真实事故前,在空白主机上测试恢复
  • 将备份加密密钥保存在网关容器之外

自建控制面的安全模型

需要防范的威胁

  • 被盗的网关密钥耗尽供应商预算
  • 管理 UI 暴露在公网
  • 提示与工具日志包含客户机密
  • 当运维人员可把通道指向内部元数据端点时,通道 base URL 引发 SSRF 类风险
  • 集群中的 SESSION_SECRET 保持默认值,导致多节点会话固定风险

真正有效的控制措施

  • 在边缘终止 TLS;通过 VPN、SSO 或 IP 白名单限制管理访问
  • 每个应用使用唯一密钥;批处理密钥设置模型白名单
  • 供应商密钥只保存在网关
  • 对任何可触发工具或长上下文的密钥设置配额
  • 为使用日志导出制定脱敏策略
  • 多节点部署设置 SESSION_SECRET(参见仓库内 compose 注释)

当 agent 能自动调用工具时,请复核 OWASP LLM 应用 Top 10。自建不会消除过度代理风险,只会改变你实施控制的位置。

将路由策略写成配置

把路由策略写成配置:

  1. 每产品默认模型别名
  2. 上游瞬时错误的备份别名
  3. 受监管或评估敏感流的固定别名
  4. 对密钥绝不可触达模型的显式拒绝

把路由与 LLM API 故障转移策略 结合,避免天真地重试中流失败。对于工具型 agent,按照跨供应商可移植工具调用中的方式保持 schema 可移植。

容量、数据库与 Redis

规模数据库说明
个人 / 小团队SQLite简单,挂载持久卷
多团队生产MySQL ≥ 5.7.8 或 PostgreSQL ≥ 9.6更好并发与运维工具
热点限流/缓存路径可选 Redis进程内限制不够时使用

按并发流而不是空闲管理 UI 用量估算 CPU/内存。流式响应会占用连接;若客户端流式,负载测试应包含 SSE 类流量。

升级与变更管理

  1. 阅读与通道、计费相关的发布说明。
  2. 用类生产通道配置部署到预发。
  3. 对 /v1/chat/completions 与任何 /v1/responses 使用做 curl 冒烟。
  4. 用金丝雀密钥验证日志入库与钱包/配额行为。
  5. 带着已知上一镜像前滚以便回滚。
  6. 升级后对照上游更名复核模型别名。

切勿在同一无人值守窗口同时做数据库迁移、供应商凭证轮换与路由策略变更。

每次部署后的冒烟测试

curl -sS https://gateway.example.com/v1/models \
  -H "Authorization: Bearer $GATEWAY_API_KEY" | head

curl -sS https://gateway.example.com/v1/chat/completions \
  -H "Authorization: Bearer $GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4.1-mini",
    "messages": [{"role": "user", "content": "ping"}],
    "max_tokens": 16
  }'

如果 Claude 和 Gemini 通道在范围内,分别添加一个 Claude 别名(例如 claude-sonnet → 当前 Claude ID)和一个 Gemini 别名(gemini-flash → gemini-3.5-flash 或后继模型)。在宣布部署健康前确认使用日志中有条目。

不放弃自建的前提下控制成本

自建不等于无限。配置:

  • 按密钥与分组的配额
  • 阻止批处理密钥使用旗舰模型的模型白名单
  • 用日志导出或看板检查对花费速度告警
  • 评估任务默认走更便宜模型

默认别名变化时复核公开的价格上下文。无法回答成本问题的自建网关会变成共享负债。

何时改选托管

在以下情况保持托管或混合:

  • 缺乏对 tier-0 依赖的值班能力
  • 无法满足备份/恢复义务
  • 采购更倾向供应商运营的控制面
  • 团队只需要单供应商密钥跳

无论哪种,应用客户端仍可保持 OpenAI 兼容。托管模式不应迫使客户端重写。

官方与项目资料

最近核对:2026-07-15。请对照你实际部署的版本验证镜像标签、环境变量与 UI 路径。

常见问题

自建 LLM 网关等于自己托管模型吗?

不等于。多数自建网关仍调用托管供应商 API。你托管的是控制面——鉴权、路由、日志——不一定是权重。自托管开源权重是额外的 GPU 栈。

可以从 SQLite 起步再迁到 PostgreSQL 吗?

对许多部署可以,但要规划迁移,而不是在事故中才发现锁竞争。小规模用 SQLite,当并发写与备份工具需要时再迁移。

最小可行安全设置是什么?

边缘 TLS、私有管理访问、每应用唯一密钥、供应商密钥只在网关、启用使用日志,以及对任何可触发工具或长上下文的密钥设配额。

如何避免成为单点故障?

可用性重要时在负载均衡后至少跑两个应用实例,使用外部数据库,测试恢复,并文档化通道故障转移。网关应缩小供应商中断的爆炸半径,而不是制造更糟的一个。

新客户端应指向哪个端点?

优先网关的 OpenAI 兼容 /v1 根与 /v1/chat/completions 以获得广泛客户端支持。仅当你的产品有意依赖 /v1/responses 且网关版本支持所需工作流时再采用它。

预发切换

使用仓库 compose 文件(或等效镜像与 SQL_DSN)部署预发网关,向单个非关键服务签发作用域密钥,并在接入第二个供应商或生产流量前验证聊天补全、使用日志与备份恢复。第一个金丝雀验证通过后,把通道配置、模型目录与使用历史作为日常运维循环。