给 vLLM 加一层 LiteLLM:统一入口、按调用方计费与自动故障切换

HN Build in Public AI 2026-09-10T11:50:35.206882

vLLM 只负责把请求算成 token,谁在调用、花了多少钱、后端挂了怎么切换,它一概不管。本文在 vLLM 前面加一层 LiteLLM 代理,对外只暴露一个 OpenAI 兼容接口,把计量、路由、鉴权这些运维工作收拢到一处。数据存进 PostgreSQL,TLS 由 nginx 终止,进程交给 systemd 托管。

上一篇文章讲的是推理引擎本身,这一篇讲引擎前面那扇“门”怎么搭。

引擎前面为什么还要再站一层

推理引擎只做一件事:把请求变成 token,再把 token 送回去。可一旦对外提供服务,就会冒出一堆没人接的活:

这些都不该由推理引擎操心,但少了任何一样,服务都跑不起来。

LiteLLM 就是补在引擎前面的代理层,对外充当唯一入口。它把“谁能进来、花了多少、后端挂了怎么办”集中到一处处理。

放到 AI 编程助手、氛围编程(vibe coding)工具的落地场景里看,这层“门”往往比算力本身更刚需——一套对外服务能不能收钱、能不能稳定跑下去,恰恰取决于这些看起来琐碎的环节。

各组件分别负责什么

角色 由谁承担
统一出口 LiteLLM 对外提供 OpenAI 兼容接口,调用方只需记住一个地址
计量 按调用方发放虚拟密钥,并按密钥维度统计花费
路由 在多个重复部署的后端之间做健康检查与流量分配
存储 PostgreSQL 存放 LiteLLM 管理界面的数据
入口安全 nginx 负责 TLS 终止
进程管理 systemd 托管服务进程

这里说的 TLS 终止,意思是在 nginx 这一层把加密连接的加解密做完,后面的服务只处理明文流量,不必各自维护证书。

安装:先填一个坑

uv tool install prisma
uv tool install 'litellm[proxy]'

有个坑得提前知道。LiteLLM 启动时会调用外部命令 prisma 执行 migrate deploy,也就是把数据库表结构同步到最新版本;但它自带的 schema 生成是坏的,开箱即用必然失败。解决办法是手动为已经装好的包生成一次:

LITELLM=~/.local/share/uv/tools/litellm
PATH="$LITELLM/bin:$PATH" "$LITELLM/bin/python" -m prisma generate \
    --schema="$LITELLM/lib/python3.12/site-packages/litellm_proxy_extras/schema.prisma"

这一步做完,后面启动才不会被卡在数据库初始化上。

数据库与环境变量

先建库、建用户:

sudo -u postgres psql
postgres=# CREATE USER litellm WITH PASSWORD '<secret>';
postgres=# CREATE DATABASE litellm OWNER litellm;

然后是环境变量:

# ~/.config/litellm/litellm.env
export LITELLM_MASTER_KEY=sk-<key>
export LITELLM_PORT=443
export DATABASE_URL="postgresql://litellm:<user>@<host>:5432/litellm"

这里有个安全上的取舍值得说明。主密钥(master key,权限最高的那把钥匙)不写进配置文件,免得跟着配置一起泄漏。真正发给调用方使用的是虚拟密钥——它由主密钥派生而来,只能访问被授权的模型,额度也能单独限制。虚拟密钥统一在 LiteLLM 管理界面里生成,方便随时吊销、随时查看用量。

config.yml:同名后端自动故障切换

核心思路很简单:让两个后端条目共用同一个 model_name。同一个名字下面挂两个后端,路由器就会在它们之间轮转,并定期做健康检查;某个后端出问题后还会被“冷却”一段时间——也就是暂时不再往它上面发请求,等它恢复再放回流量池。

关键要点

路由配置:一份可以直接照抄的 YAML

LiteLLM 最省事的一点,是把「一个模型名背后挂多台后端」这件事从代码里挪进了配置文件。下面这份 YAML 可以直接当骨架用:同一个 model_name 下面挂多个后端,路由器会自动在它们之间分摊请求。

model_list:
  - model_name: glm-5.2
    litellm_params:
      model: openai/glm-5.2
      api_base: http://<backend-1>:8000/v1
      api_key: <secret>
      stream_timeout: 900
    model_info:
      health_check_timeout: 5
      input_cost_per_token: 0.00000035
      output_cost_per_token: 0.00000175
  - model_name: glm-5.2          # same name, second backend
    ...

general_settings:
  background_health_checks: true
  health_check_interval: 30
  enable_health_check_routing: true
  health_check_ignore_transient_errors: true

router_settings:
  routing_strategy: simple-shuffle
  enable_weighted_failover: true
  num_retries: 2
  retry_after: 1
  timeout: 5
  cooldown_time: 60
  allowed_fails_policy:
    AuthenticationErrorAllowedFails: 0
    TimeoutErrorAllowedFails: 2
    RateLimitErrorAllowedFails: 5

对开发者来说,好处很直接:调用方只认一个地址、一个模型名。后端从一台扩到三台,或者某台机器临时下线换新,上层代码一行都不用改。多个 AI 编程工具、Agent 同时打过来时,也不必给每个工具单独配一套后端地址。

这几类参数,各自管什么

模型与后端的绑定(model_list

model_name 是客户端唯一需要知道的名字——背后有几台机器、跑的是什么模型,调用方不用关心,只写这一个名字就行。

计费字段(input_cost_per_token / output_cost_per_token

这两个字段分别记录输入、输出每个 token 的单价。token 是模型处理文本的最小单位,大致可以理解为「一小段字」。单看数字很小,乘上真实 token 用量之后就能直接换算成账单金额,是后面做「按调用方计费」的基础。

健康检查(general_settings

健康检查说白了,就是隔一段时间给每台后端发个探针请求,看它还在不在、能不能正常回话。

路由与故障切换(router_settings

这部分决定请求分给谁、出错之后怎么处理:

查看原文