如果你手上同时要接好几个大模型服务,或者只是想让团队内部调 Gemini 的方式统一起来,LiteLLM 算是我试下来最省心的网关方案之一。你可以把它理解成一个专门做 API 转发和治理的中间层:业务方不管底层是 Gemini 还是别的模型,都统一往这个代理服务发请求,由它把请求转换成对应厂商的格式、补上密钥、再把结果原样返回。这篇文章不绕概念,直接讲我怎么把 LiteLLM 代理服务从零跑起来,并且稳定用了一段时间的过程。适合正在集成 Gemini API、又不想在每个业务里重复写厂商 SDK 的开发者,也适合需要统一管理模型 Key、统一记账和限流的团队。
先说清楚一点:这里的“代理”指的是 API 网关层的反向代理,跟网络出口代理没有任何关系。它代理的是“接口调用”,不是“网络流量”,这一点先对齐,后面所有内容都建立在这个基础上。
1. 为什么要给 Gemini API 套一层网关
1.1 直接调 Gemini 时会遇到的一堆破事
如果你只是写个脚本自己玩,直接用 Gemini 官方 SDK 是最快的,填个 Key 就能跑。但一旦涉及多个服务、多个模型、多个人协作,问题马上冒出来:
- 每个语言都得装对应的官方 SDK,接口风格还不一样。Python 一套写法,Node.js 另一套写法,前端要调还得自己做一层封装。
- 响应格式不同。Gemini 返回的
candidates和 OpenAI 的choices结构完全两样,prompt 里contents和messages的字段名也不同。你要在代码里写一堆兼容层。 - Key 管理失控。密钥散落在各服务的环境变量里,换一个 Key 要登好几台机器改。团队里有新人加入,直接把 Key 发群里,后面发现账单涨了都不知道谁调的。
- 想加 fallback 很难。Gemini 限流了怎么办?换一个模型试试?直接调原生接口时,这套逻辑全得自己写。
这些问题单拎出来都不大,但叠在一起就很不舒服。我见过的项目里,很多人最后写出来的“调用封装”比自己业务代码还复杂,而且只适用于某一个模型,换模型等于重写。
1.2 LiteLLM 在这套架构里的位置
LiteLLM 是一个开源的大模型网关,同时提供 Python SDK 和 HTTP 代理服务两种用法。这篇文章说的“代理服务”指的是第二种:跑一个独立进程,对外提供标准接口,对内连接各种上游模型厂商。它支持一百多个模型提供商,Gemini 只是其中之一。
它的核心思路很直白:客户端请求统一走 OpenAI 兼容的 /v1/chat/completions 格式,LiteLLM 把这个请求翻译成目标厂商的 API 请求。对 Gemini 来说,就是把 OpenAI 风格的 messages、tools、system 指令转换成 Gemini 的 contents、parts、system_instruction 格式,再把返回结果翻译回 OpenAI 风格。你的业务代码永远只认一种格式,底层换哪家的模型,对业务透明。
这个“翻译”看起来简单,实际坑不少。Gemini 的 tool calling 结构、流式返回的 chunk 格式、system prompt 的放置位置,都跟 OpenAI 不一样。LiteLLM 把这些转换封装好了,你不需要关心细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心能力拆解:一个代理服务到底替你干了什么
2.1 统一出参格式:所有模型一个样子
LiteLLM 对外暴露的接口是业界事实标准的格式,请求体长这样:
json复制{
"model": "gemini-flash",
"messages": [
{"role": "system", "content": "你是一个乐于助人的助手"},
{"role": "user", "content": "用一句话介绍你自己"}
],
"temperature": 0.7
}
返回也长成标准样子:
json复制{
"id": "chatcmpl-xxx",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "你好,我是你的助手"},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 18, "completion_tokens": 15, "total_tokens": 33}
}
这意味着你项目里只需要依赖一个 OpenAI 兼容的 SDK,或者干脆自己用 HTTP 客户端拼 JSON。以后不管接 Gemini、接本地模型、还是接别的厂商,业务代码一行都不用改。
Gemini 在参数上与 OpenAI 有差异。比如 OpenAI 的 logprobs 这类参数 Gemini 根本不支持,LiteLLM 会在配置里开了 drop_params 之后自动把不支持的参数丢掉,而不是让请求直接报错。这个细节对生产环境很重要,后面配置部分会细说。
2.2 密钥与虚拟 Key:不再把上游 Key 到处发
代理服务支持三层密钥体系:
| 层级 | 用途 | 谁来用 |
|---|---|---|
| 上游 Key | Gemini 官方签发的真实密钥 | 只存在于网关进程/配置里 |
| 管理 Key | 网关的管理员凭证,用来创建虚拟 Key、查看账单 | 运维/管理员 |
| 虚拟 Key | 下发给业务方和团队成员的凭证,可以独立撤销、记账 | 各业务服务、团队成员 |
创建虚拟 Key 只需要一个请求:
bash复制curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-你的管理Key" \
-H "Content-Type: application/json" \
-d '{"models": ["gemini-flash"], "max_budget": 10}'
返回的 key 字段就是虚拟 Key。每个虚拟 Key 可以设置可用的模型范围、预算上限、每分钟请求数上限。哪个 Key 超额了,单独撤销它,完全不影响其他业务。上游 Key 本身从头到尾只躺在网关配置里,业务方永远接触不到。
这套机制在有多个合作方、多个内部项目的场景下特别实用。之前一个虚拟 Key 只能对应一个模型组,现在按项目分 Key、按 Key 设预算,月底看调用统计就知道每个项目花了多少。
2.3 负载均衡与故障转移:不用自己写重试逻辑
单个 Gemini Key 有速率限制和额度限制。LiteLLM 允许在配置里给同一个 model_name 配多个上游条目,它会在请求时自动分配流量。一个 Key 被限流了,自动换另一个 Key 重试。这个在多账号分摊限额的时候尤其好用。
再进一步,可以在路由层配置 fallback:某个模型连续失败几次之后,自动切换到备选模型。这对于线上服务来说几乎是刚需。Gemini 偶尔会抖动或者限流,与其让用户看到报错,不如自动降级到另一个模型。配置方法后面会写。
2.4 用量统计与限流:月底不用再猜账单
网关每处理一个请求,都会记录 token 消耗和费用估算。它内置了 /spend/logs、/spend/keys、/spend/tags 等接口,可以直接查每个虚拟 Key 的花费。数据默认存在本地的 SQLite 文件里,也可以接 Postgres 存更久、查更快。
它还对外暴露 Prometheus 指标端口 /metrics,接上 Grafana 就能画出请求量、延迟、错误率、Token 消耗趋势。生产环境部署时,我强烈建议至少把错误率和 Key 花费这两个指标接进去,Gemini 一限流告警就能拉起来,而不是等用户来投诉了才发现。
另外,网关层可以做并发限制。max_parallel_requests 可以控制同一个模型同时处理的请求数量,防止一个突发流量把整个上游额度打爆,也可以防止自己服务被下游刷爆。
3. 从零搭建:本地部署一个可用的网关
3.1 环境准备与安装
建议用虚拟环境装,避免污染系统 Python:
bash复制python -m venv .venv
source .venv/bin/activate
pip install 'litellm[proxy]'
litellm --version
litellm[proxy] 这个 extra 会带上跑代理服务需要的额外依赖。版本确认没问题后,先准备好 Gemini 的 API Key,通过环境变量注入,不要直接写进配置文件里提交到仓库。
3.2 写一个最小可用的 config.yaml
LiteLLM 的所有行为都通过一个 YAML 配置文件来声明。先写一个最简版本:
yaml复制model_list:
- model_name: gemini-flash
litellm_params:
model: gemini/gemini-2.0-flash
api_key: os.environ/GEMINI_API_KEY
litellm_settings:
drop_params: true
num_retries: 3
request_timeout: 60
general_settings:
master_key: sk-换成一个足够复杂的管理密钥
database_url: sqlite:///litellm.db
这里稍微解释一下:
model_name是暴露给业务方的名字,可以叫任何你喜欢的名字,相当于菜单上的菜名。model是真实的上游模型标识,gemini/前缀表示走 Google AI Studio,后面跟具体模型名。api_key从环境变量取,避免 Key 写死在文件里。drop_params丢弃上游模型不支持的参数,建议直接打开。num_retries是请求失败后的自动重试次数。master_key用来管理网关,生产环境务必设一个强随机值。database_url存调用记录和账单数据,默认 SQLite 即可,量大了再迁 Postgres。
3.3 启动服务并验证
bash复制export GEMINI_API_KEY=你的密钥
litellm --config config.yaml --port 4000
看到提示服务已在 http://0.0.0.0:4000 监听,就说明起来了。先验证网关本身:
bash复制curl http://localhost:4000/health/liveliness
然后发一个真正的对话请求:
bash复制curl http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-你的管理Key" \
-d '{
"model": "gemini-flash",
"messages": [{"role": "user", "content": "你好,请回复一句话"}],
"stream": false
}'
拿到标准格式的返回就说明链路通了。更常见的做法是用 OpenAI 的 SDK 来连:
python复制from openai import OpenAI
client = OpenAI(
api_key="sk-你的管理Key",
base_url="http://localhost:4000/v1",
)
resp = client.chat.completions.create(
model="gemini-flash",
messages=[{"role": "user", "content": "用一句话介绍 Gemini"}],
)
print(resp.choices[0].message.content)
base_url 指向网关,模型名填 model_name 的别名,其他一切都跟调 OpenAI 时一模一样。也可以先 curl http://localhost:4000/v1/models 看看网关暴露了哪些模型。
3.4 Docker 部署方式
本地验证没问题后,部署到服务器上我一般用 Docker。不依赖宿主机 Python 环境,升级也方便。这里给一个自建镜像的方式,避免到处找现成镜像:
dockerfile复制FROM python:3.11-slim
RUN pip install --no-cache-dir 'litellm[proxy]'
COPY config.yaml /app/config.yaml
EXPOSE 4000
CMD ["litellm", "--config", "/app/config.yaml", "--port", "4000"]
然后:
bash复制docker build -t litellm-proxy .
docker run -d --name litellm \
-p 4000:4000 \
-e GEMINI_API_KEY=你的密钥 \
-v $(pwd)/litellm.db:/app/litellm.db \
litellm-proxy
注意把 SQLite 数据库文件挂载出来,否则容器重建后账单数据就没了。量比较大的场景建议直接换 Postgres,把 database_url 指过去。
4. 关键配置项与参数解读
4.1 model_name 和 model 的区别
这是新手最容易混淆的一组概念。model_name 是网关内部用的别名,业务方请求时填的是它;model 才是真正发给上游的模型标识。
yaml复制model_list:
- model_name: gemini-flash
litellm_params:
model: gemini/gemini-2.0-flash
- model_name: gemini-15-pro
litellm_params:
model: gemini/gemini-1.5-pro
这么设计的目的有两个:一是业务方不需要关心上游模型版本,网关升级模型时业务侧不用改;二是同一个别名可以对应多个上游条目,为负载均衡和 fallback 打基础。
我个人的习惯是给模型起一个语义化的名字,比如 chat-fast 对应 Gemini 快速模型,chat-smart 对应更强的模型。这样业务方看到的是能力等级,而不是某个具体模型名。以后底层从 Gemini 切到别家,只要改配置,业务完全无感。
4.2 认证链路与虚拟 Key 配置
管理 Key 设好之后,给业务方创建虚拟 Key 是标准操作:
bash复制curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-管理Key" \
-H "Content-Type: application/json" \
-d '{
"models": ["gemini-flash"],
"max_budget": 10,
"budget_duration": "30d",
"max_parallel_requests": 20
}'
这段配置的意思是:这个虚拟 Key 只能用 gemini-flash 这个模型,30 天内预算上限 10 美元,同时最多 20 个并发请求。返回里的 key 字段就是业务方要用的。还需要把虚拟 Key 和上游 Key 分开放:业务方只拿虚拟 Key,上游 Key 永远只存在于网关配置里。出事的时候追溯、撤销都很快。
4.3 流式输出与超时设置
对话类应用基本都要流式输出,网关支持把 Gemini 的流式响应转成 OpenAI 风格的 SSE 流。客户端只需要在请求里加 "stream": true,或者用 OpenAI SDK 时传 stream=True,就能一直接收增量内容。
这里有一个容易被低估的参数:request_timeout。Gemini 某些深度思考模型第一次响应可能需要比较长的时间,如果超时设得太短,客户端那边会先断开,实际请求还在后台消耗额度。我建议结合具体模型把超时设到 60 秒以上,线上环境再做一层客户端超时保护。
4.4 日志、数据库与监控
网关默认会在控制台打印调用日志。调试时可以加 --detailed_debug 看更详细的内部转换过程,但生产环境不要开,日志会非常多,而且可能把完整请求内容打进去,有隐私风险。
生产环境我建议至少做这几件事:
- 把
database_url指向 Postgres,持久化保存调用记录。 - 定期查看
/spend/keys,核对每个 Key 的花费。 - 用
/metrics接监控,重点盯错误率和 429 限流次数。 - 日志轮转,避免磁盘被日志占满。
5. 常见问题与排查实录
5.1 401 认证失败
网关日志里出现 401,排查顺序一般是:
- 上游 Key 是否有效。直接拿 Key 调 Gemini 原生接口试试,确认 Key 本身没问题。
- 环境变量是否注入成功。Docker 部署时最容易忘
-e GEMINI_API_KEY,容器里根本没这个变量。 - 管理 Key 是否匹配。请求头里的
Authorization必须和master_key一致。 - 虚拟 Key 是否过期或被撤销。
5.2 429 限流
Gemini 官方对单个 Key 限流比较严格,短时间大量请求很容易触发。遇到 429,我的处理思路是:
- 确认上游限流是超 QPS 还是超每日额度。
- 如果是 QPS 限流,给同一个
model_name配多个上游 Key,启用负载均衡。 - 打开
num_retries并配合cooldown_time,被限流后冷却一段时间再重试。 - 超出每日额度就只能等额度刷新,或者申请更高配额。
5.3 模型名对不上,报错 Model Not Found
请求返回 404 或模型不存在,九成是 model 字段填错了。请求里的模型名必须等于配置里的 model_name 别名,不是上游模型名。也就是说请求里填 gemini-flash,而不是 gemini/gemini-2.0-flash。
另一个常见问题是配置里的上游模型标识少了 gemini/ 前缀。没有前缀,LiteLLM 会当成未知提供商处理,直接在启动时就报错或者调用时找不到对应的转换逻辑。
5.4 参数不兼容导致的报错
Gemini 不支持的参数,比如某些 OpenAI 特有字段,可能导致上游报错。drop_params: true 能解决大部分这类问题。如果某个参数你需要保留、又不确定 Gemini 支不支持,可以先在本地用一个最小请求测一遍,确认后再进配置。
5.5 流式输出异常
流式请求最常见的问题是首包延迟或者中途断流。Gemini 流式返回的 chunk 结构跟 OpenAI 差异比较大,LiteLLM 转换后理论上是无感的。如果客户端拿不到内容,先试 curl 直接请求网关的流式接口,确认是网关问题还是业务代码问题。另外确认 stream 参数在整条链路里都传对了,有些 SDK 版本会默认吞掉这个参数。
可以整理成一个速查表:
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| 401 Unauthorized | 上游 Key 无效或环境变量没注入 | 直接调上游验证 Key,检查容器环境变量 |
| 429 Too Many Requests | 触发上游速率限制 | 多 Key 负载均衡、加大重试间隔 |
| Model Not Found | 请求模型名不是配置里的别名 | 请求里填 model_name,不是上游模型 id |
| 参数报错 | Gemini 不支持某些参数 | 开启 drop_params |
| 流式无输出 | 流式参数未正确传递 | 用 curl 直连网关排查链路 |
| 响应超时 | 模型思考时间过长 | 调大 request_timeout |
6. 实操心得与后续扩展
6.1 我踩过的几个坑
第一个坑是版本差异。LiteLLM 迭代很快,早期版本的配置项在最新版里可能已经改名。对着网上老教程抄配置,启动时会报 invalid config。解决办法很简单:启动时如果报配置错误,优先看官方文档里对应版本的配置示例,别硬改。
第二个坑是数据库文件权限。容器里跑的时候,SQLite 文件挂在宿主机目录,容器内用户不一定有写权限。现象是网关能起来,但一写入调用记录就报错。挂载目录时注意权限,或者干脆用 Postgres。
第三个坑是思考模型和超时。Gemini 有些带思考模式的模型,输出前要“想”很久,首次响应可能几十秒。一开始我把 request_timeout 设成 30 秒,结果大量请求被客户端当成超时重试,白白浪费额度。后来调大到 120 秒才稳定。
第四个坑是把虚拟 Key 和管理 Key 混淆。创建虚拟 Key 的接口本身也要用管理 Key 鉴权,很多人拿业务方的虚拟 Key 去调管理接口,只得到一个权限不足的报错。这俩角色是分开的,别混用。
6.2 还能怎么扩展
这个网关跑起来之后,扩展是很容易的。想接入其他模型,只需要往 model_list 里追加条目,配好对应的环境变量,重启即可。业务方无感,因为它们请求的格式没变。
团队场景下,可以给每个项目建一个虚拟 Key,设好预算和限流。到月底看一眼 /spend/keys,谁用了多少一目了然,不用再对着账单猜。
外部的一些支持自定义接口地址的工具,也可以直接把 Base URL 填成网关地址,把模型名填成你的别名,就能直接用上 Gemini。相当于把网关变成一个兼容层,让原本只认一种协议的工具也能跑别的模型。
我个人在实际操作中最大的体会是:这个网关联调阶段投入半天,后面几乎不用管。它解决的痛点不是“调通一个接口”,而是把整个团队的模型接入方式收敛到了一个统一入口,Key、账单、限流、高可用全在一个地方管起来。如果你现在正在被多模型接入和 Key 管理折磨,从最小配置跑起来,按上面的排查表处理问题,会省下很多意料之外的麻烦。
