LiteLLM 代理 Ollama 怎么配:五处静默失败实测

这套组合能用。LiteLLM 1.109.1 在本机把 Ollama 的 qwen3:8b 包成标准 OpenAI 接口,冷启动 7.19 秒,单次调用额外开销 8 到 27 毫秒。适合已经有 Ollama、要给几个客户端或几个同事发同一个地址同一个 key 的人,从装到跑通约 10 分钟。真正卡人的是启动门槛和参数透传两处,下面按实测顺序写。

一、先看清三个数字

装在 M4 16GB 上做,Python 3.12.12,uv 建的干净虚拟环境,只装了 litellm 的 proxy 依赖组。装是一次性成本,跑起来才知道谁在占资源。

项目 实测值 怎么测的
依赖包数 117 个 importlib.metadata 列 distribution
虚拟环境体积 493MB du 全部依赖
冷启动耗时 7.19 秒 进程拉起到存活探针返 200
常驻内存 117MB RSS,不含模型
单次调用额外开销 8 到 27 毫秒 响应头 x-litellm-overhead-duration-ms
端到端耗时 1.315 秒,直连 1.31 秒 同一提示词各跑 4 轮取中位数

最后一行说明这层代理几乎不吃时间。响应头里的 x-litellm-overhead-duration-ms 更直接,它记录网关自身处理耗时,冷启动第一次 206 毫秒,稳定后落在 8 到 27 毫秒。那些说加一层明显变慢的说法,在这台机器上站不住。

二、三步跑起来

建环境装包,走国内镜像,命令连着敲,中间别断。版本号固定住,PyPI 上最新就是 1.109.1,2026-11-12 上传;而 1.107.0 这个版本条目现在在 releases 里查不到,站内十月那篇 LiteLLM 投毒报道点的正是这一代,写死版本比追 latest 稳。

uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python 'litellm[proxy]==1.109.1'

接着写配置。四个字段决定成败:model_name 是客户端看到的名字,litellm_params.model 是真实后端加 provider 前缀,api_base 写到端口为止,master_key 是访问凭据。

model_list:
  - model_name: local-qwen
    litellm_params:
      model: ollama_chat/qwen3:8b
      api_base: http://127.0.0.1:11434

general_settings:
  master_key: sk-换成你自己的长随机串

然后启动。前台跑会一直刷访问日志,实验时丢后台更省事。

.venv/bin/litellm --config config.yaml --host 127.0.0.1 --port 4000

起来后按存活探针、模型清单、真实请求三步验。三条命令的期望返回分别是一句 "I'm alive!"、一个含 local-qwen 的 data 数组、一段正常中文回答。

curl http://127.0.0.1:4000/health/liveliness
curl -H 'Authorization: Bearer sk-...' http://127.0.0.1:4000/v1/models
curl -H 'Authorization: Bearer sk-...' -H 'Content-Type: application/json' \
  -d '{"model":"local-qwen","messages":[{"role":"user","content":"回答两个字:好的"}],"max_tokens":40}' \
  http://127.0.0.1:4000/v1/chat/completions

三、1.109 起没设 master_key 直接不启动

这是本轮第一个硬门槛。照很多中文教程那样只写 model_list 就启动,进程会拉起一半然后退出,日志末尾是 UnsafeMasterKeyError。

litellm.proxy.auth.master_key_boot_check.UnsafeMasterKeyError: LiteLLM proxy refused
to start: no master key is set, so every request would be accepted without
authentication.

报错自带三条修法:写进 general_settings.master_key、设环境变量 LITELLM_MASTER_KEY、或本地开发时开逃生阀。逃生阀是 LITELLM_DANGEROUSLY_PERMIT_WEAK_OR_UNSET_MASTER_KEY=true,实测能起来,但每次启动都打一行警告,明写所有请求免认证。本机实验可以开,绑到公网端口千万别开。

一个反直觉的点,它不校验强度。master_key 填 sk-change-me 这种一眼假的串,实测照常启动,只有完全没设才拦。所以别以为设了 key 就安全,长度和随机性得自己盯。

四、两个字段别混:model_name 与 litellm_params.model

漏掉 provider 前缀,症状极其隐蔽。配置里写四条目,其中一条把 model 写成 qwen3:8b 不带前缀,服务照样起来,/v1/models 只返回三条,少的那条没有任何提示。

线索只在启动日志里。一条 BadRequestError,后面跟 LLM Provider NOT provided,再跟 You passed model=qwen3:8b。整段是 Python traceback 的长相,很容易被当成普通告警划过去。四个条目里命中两次,说明它在初始化阶段对每条都试了一遍。

第二个隐蔽点是 api_base。Ollama 的 OpenAI 兼容端点在 /v1 上,但 LiteLLM 的 ollama_chat 前缀走的是 /api/chat,base 必须写到端口。多写一个 /v1,请求立刻 404,原文是 Ollama_chatException – 404 page not found。光看状态码会误判成模型名写错。

model_name 允许带前缀,直接写成 ollama_chat/qwen3:8b 也能跑。代价是客户端调用时得一字不差带上前缀,只写 qwen3:8b 就返 400。想让上层无感,还是给个短名字更好。

五、num_ctx 只有一种写法有效

这是整轮最值钱的发现。上下文长度由 Ollama 启动 llama-server 时的 -c 决定,LiteLLM 会从请求体带过去,但只有放在顶层才带得动。

请求体写法 llama-server 拿到的 -c 是否触发重载 结论
顶层 num_ctx 8192 8192 会 唯一有效写法
完全不写 4096 会(从 8192 回落) 等于显式写 4096
options 包一层 num_ctx 12288 4096 不会 静默丢弃
extra_body 包一层 num_ctx 20480 4096 不会 静默丢弃

证据在 Ollama 自己的日志里。带 num_ctx 8192 时启动命令含 -c 8192,改 16384 就变 -c 16384,完全不写则是 -c 4096。两种包一层的写法返回体全是 200,看不出任何异常,参数被吞得干净。

更要紧的是切换代价。这个参数属于加载参数,改一次就换一个 runner。

状态 单次调用耗时
上下文不变(热) 0.34 到 0.35 秒
切到 8192 2.81 到 3.05 秒
从 8192 切回默认 4096 3.05 秒
切到 32768 4.14 秒

所以混用会抖。让同一个代理交替收到带 num_ctx 与不带 num_ctx 的请求,六次调用耗时 3.59、2.66、2.90、2.63、2.88、2.68 秒,一次热路径都没命中。同一台机器热路径只要 0.34 秒,差七到八倍。

处置很简单:两个客户端要么写同一个值,要么都不写。更稳的做法是在 litellm_params 段给一个固定值,让所有请求共享同一个上下文窗口,谁也别踢谁。

这点跟直连正好相反。直连 Ollama 的 /v1/chat/completions 时 num_ctx 完全不生效,怎么传都按 4096 算;经过这一层反而把参数送到了位,代价是切换即重载。客户端自己每轮重算上下文的场景更麻烦,aider 那种 按 token 数反推 num_ctx 的做法会让加载频率比手写请求高一个量级。

六、流式默认拿不到 usage

开 stream 之后,usage 在所有分片里都是 null。79 个分片里一个带用量的都没有,限流与计费脚本读不到 token 数,会静默算成 0。

补一个字段即可。请求体加 stream_options,把 include_usage 打开,最后一个分片会带完整用量。

{"model":"local-qwen","stream":true,
 "stream_options":{"include_usage":true},
 "messages":[{"role":"user","content":"回答两个字:好的"}],"max_tokens":80}

顺带一个判据。qwen3:8b 默认带思考链,max_tokens 给 80 时用量是 completion_tokens 80,其中 reasoning_tokens 80、text_tokens 0。看到 text_tokens 是 0,就是思考链吃满了,正文一个字没出。

七、think 参数能透传,这点比直连强

qwen3 系列默认先思考。直连 Ollama 的 OpenAI 兼容端点时这个开关不被识别,模型照样先跑一段思考链;经过 ollama_chat 前缀时它落到 /api/chat,think 是原生字段,就生效了。

实测请求体带 "think": false,连跑三次都直接出正文,耗时 0.19 到 1.68 秒,思考链长度 0。不带这个字段的对照组,一次调用 22 秒,思考链 671 字符,正文只有 50 字。

要做低延迟短问答,这个开关比压 max_tokens 有效。max_tokens 调小只会截断思考链,正文还是空的,客户端拿到一个 200 和一个空串,最难查的一类故障。

八、四个错误码对应的真实原因

状态码 报错要点 真实原因
401 Authentication Error, No api key passed in. 请求没带 Authorization 头
400 Invalid model name passed in model=… 名字不在 model_list 里
404 Ollama_chatException – 404 page not found api_base 多写了 /v1
404 model ‘llama3.2:3b’ not found 配置有这条,Ollama 没 pull 该 tag
500 APIConnectionError … Cannot connect to host 后端端口没有服务,主机名会打成 REDACTED,只能靠端口定位

每个错都带一句 No fallback was attempted,说明当时没配回退。配置里加 fallbacks 才会去试下一个后端,默认就停在这里。

九、加这一层到底值不值

值钱的地方是名字解耦。配置里把 model_name 直接写成 gpt-4o-mini,后端指向本地 qwen3:8b,客户端一行代码不改,模型名照旧。实测这条别名路径 0.51 秒返回,正常出字。以后换成本地别的模型,只改配置一行,上层不用动。前端类工具接这种地址最省事,Open WebUI 这类需要 OpenAI 兼容端点的面板填进去就能用。

不值的地方在钱。响应头里四个成本字段全是 0.0,x-litellm-response-cost、x-litellm-key-spend 一个不落。本地模型没有价目表,网关只记 token 不记钱,想拿它做成本看板会失望。

还有一个盲区,清单正常不等于能跑。配置里声明一个本地没拉下来的 tag,/v1/models 照样把它列出来,只有真发请求才 404。这点跟前面漏前缀刚好相反,一个少一条,一个多一条,两种都不会在清单里说实话。

十、卡住时的三步定位

第一步翻启动日志找 traceback。服务起得来不代表配置全对,漏 provider 前缀那条会静默消失,唯一线索是 LLM Provider NOT provided。

第二步拿 /v1/models 的条数对配置文件条目数。少了就是第一步的问题;数量对得上但调用 404,去 Ollama 侧跑 ollama list 看 tag 在不在。

第三步盯 Ollama 日志里的 -c 值。忽快忽慢几乎都是它变了,切一次上下文就重载一次模型,8B 在这里是 2.8 到 4.1 秒。

常见问题

问:不装 Python,能不能直接用 Docker 跑?
能,官方有镜像,挂一份 config.yaml 进去即可。本机没有 docker 时用 pip 装 proxy 依赖组最省事,代价是 117 个包、493MB 磁盘。网关只负责转发,模型仍然跑在 Ollama 那边,两者可以不在同一台机器上。

问:多一层代理会不会拖慢本地模型?
实测不会。同一提示词直连与经代理各跑四轮,中位数 1.31 秒对 1.315 秒,差值落在噪声里。网关自身处理耗时写在响应头 x-litellm-overhead-duration-ms,稳定后 8 到 27 毫秒。真正拖慢的是上下文参数被来回改导致的模型重载,一次 3 秒左右。

问:能不能用同一个 key 把请求分到两台 Ollama?
配置层面可以,同一个 model_name 写两条 litellm_params 指向不同 api_base,网关会在这两个后端之间分发。本机只验证了单后端与别名,跨机分发的实际表现要按你的网络另测,别直接照搬。

全部文章归档与模型专题