这套组合能用。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,网关会在这两个后端之间分发。本机只验证了单后端与别名,跨机分发的实际表现要按你的网络另测,别直接照搬。
延伸阅读
- 本地大模型显存怎么算:8B 每 1K 上下文 144MB6 天前
- safetensors 转 GGUF:六步跑通与三处静默失败3 天前
- Open WebUI 免 Docker 怎么装:首启 4 分 17 秒卡在哪2 天前
- ComfyUI 装 FLUX 模型:safetensors 损坏与下拉框空白怎么修1 周前
继续读
往下这几篇值得接着看:
- aider 接本地 Ollama:num_ctx 每轮重算的四个坑2026-11-14
- Qwen3-VL 读表格实测:900px 全对,手机拍的返回空2026-11-14
- MLX 微调 0.6B 只花 105 秒:JSON 准确率从 0 到全对2026-11-14
