尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

LiteLLM 启动与接口测试排错记录

LiteLLM 启动与接口测试排错记录 LiteLLM 启动与接口测试排错记录本文记录my-litellm-service第一次在本地启动 LiteLLM Proxy并通过 OpenAI 兼容接口调用 Gemini 时遇到的问题、排查过程和最终解决方式。这次排错涉及的内容比较多Python 依赖、uv环境、FastAPI 版本、Redis 网络路径、Tailscale、LiteLLM 网关认证、健康检查、模型输出 Token以及 Gemini 的 thinking 和 429 限流。1. LiteLLM Proxy 启动方式当前项目不是通过python main.py启动 LiteLLM。LiteLLM Proxy 是第三方包提供的命令行程序入口来自虚拟环境中的.venv/bin/litellm推荐启动命令cd/home/gateman/projects/github/my-litellm-service uv run --env-file .env\litellm\--configconfig.yaml\21|tee-a/var/log/my-litellm-service/litellm.log这里的--env-file .env只负责把环境变量注入 LiteLLM 进程例如OPENAI_API_KEY_FREE_1... LITELLM_MASTER_KEY... REDIS_HOST... REDIS_PASSWORD...它不会修改当前 shell 的环境变量。之后使用curl的终端仍需要单独执行set-asource.envseta否则下面的变量可能为空或仍然是旧值$LITELLM_MASTER_KEY这是本次排错中非常关键的一点uv --env-file .env → LiteLLM 进程 source .env → 当前 shell 和 curl2. 第一个问题缺少 LiteLLM Proxy 依赖最初的依赖声明是litellm1.74.0,2.0.0启动 Proxy 时出现ModuleNotFoundError: No module named backoffLiteLLM 的基础包和 Proxy 所需依赖不是完全相同的集合。基础包可以用于 SDK 调用但启动完整 Proxy 还需要额外依赖。因此将依赖修改为litellm[proxy]1.74.0,2.0.0然后重新解析和同步环境uv lock uvsync--devlitellm[proxy]会额外安装 Proxy 所需的依赖例如backoff、Proxy 运行组件、Redis 相关组件和 Web 服务组件。3. 第二个问题LiteLLM 与 FastAPI 版本不兼容安装 Proxy extra 后LiteLLM 可以继续启动但出现了ImportError: cannot import name get_flat_dependant from fastapi.dependencies.utils检查实际版本LiteLLM 1.97.0 FastAPI 0.141.1LiteLLM Proxy 代码仍然导入get_flat_dependant而较新的 FastAPI 已经移除了这个接口。问题不是缺少 Python 文件而是两个包的版本接口不兼容。最后将 FastAPI 固定到仍然提供该接口的版本fastapi0.136.3,0.137.0然后重新执行uv lock uvsync--dev验证.venv/bin/python-c\from fastapi.dependencies.utils import get_flat_dependant; print(compatible)LiteLLM 随后可以正常进入Application startup complete. Uvicorn running on http://0.0.0.0:4000这里得到的经验是使用 LiteLLM Proxy 时不能只看 LiteLLM 自己的版本还要检查它的 Proxy extra 对 FastAPI、Starlette 和 Uvicorn 的兼容约束。4. 日志输出到指定文件直接启动 LiteLLM 时日志默认输出到终端。为了保存日志使用21|tee-a/var/log/my-litellm-service/litellm.log第一次执行时出现/var/log/my-litellm-service/litellm.log: No such file or directory原因是目标目录还不存在。先创建并授权sudomkdir-p/var/log/my-litellm-servicesudochowngateman:gateman /var/log/my-litellm-servicesudochmod750/var/log/my-litellm-service之后重新启动即可uv run --env-file .env\litellm--configconfig.yaml\21|tee-a/var/log/my-litellm-service/litellm.logLiteLLM 是前台服务启动命令不返回 shell 是正常现象不是卡死。看到下面的日志就说明服务已经启动Application startup complete. Uvicorn running on http://0.0.0.0:40005. Redis 缓存配置与连接问题当前config.yaml启用了 LiteLLM 原生 Redis Response Cachelitellm_settings:cache:truecache_params:type:redishost:os.environ/REDIS_HOSTport:os.environ/REDIS_PORTpassword:os.environ/REDIS_PASSWORDsupported_call_types:[chat_completion]ttl:3600LiteLLM 会自动创建 Redis 客户端、查询缓存、写入响应和处理 TTL不需要我们再编写一套缓存读写代码。5.1 Redis 的部署位置Redis 实际部署在 Tencent K3s 集群中的 OCIfree-arm-vm节点free-arm-vm └── Redis Pod通过集群检查确认free-arm-vm Ready Redis Pod Running Redis Service 6379Redis 的实际 Tailscale 地址是100.105.130.05.2 一开始使用了错误的地址曾经把 Redis 配置成REDIS_HOST100.104.150.19这个地址实际上是 NUC 节点不是 Redis 所在的 OCI 节点。后来改回REDIS_HOST100.105.130.0 REDIS_PORT63795.3 为什么本地连接一开始超时从 Main PC 测试100.105.130.0:6379 → timeout检查路由发现Main PC 当时没有 Tailscale 路由把100.105.130.0当成普通局域网地址发送到家庭网关。后来在 Main PC 安装并启用 Tailscaletailscaledactive 开机启动enabled Tailscale IP100.121.12.126现在本地 LiteLLM 才具备访问 OCI Redis Tailscale 地址的网络条件。5.4 Kong/KIC 与 Redis 的关系KIC 负责将 Kubernetes 配置同步到 KongKong Proxy Service 才负责实际网络转发。但部署记录中的低延迟方案不是绕经 Tencent 节点而是LiteLLM → Tailscale → 100.105.130.0:6379 → Redis Pod on free-arm-vm如果 LiteLLM 也部署在 K3s 集群内部则应该使用 Redis Service DNS如果 LiteLLM 在集群外且已加入 Tailscale则使用100.105.130.0。Redis 不应直接暴露到公网。公网入口应该给 LiteLLM API 使用Redis 继续走 K3s 内部网络或 Tailscale。6.Setting Cache on Proxy不等于 Redis 已连接启动时看到Setting Cache on Proxy只表示 LiteLLM 正在初始化缓存功能。如果 Redis 不可达日志可能继续出现Timeout connecting to server Error connecting to Sync Redis client这时可能出现LiteLLM Proxy启动成功 Redis 配置已开启 Redis 连接失败 缓存不可用或降级后来 Tailscale 配置完成后启动日志不一定每次都打印Setting Cache on Proxy但这不表示缓存被关闭。是否开启应看config.yaml是否可用则要看 Redis 连接结果或实际缓存命中。当前 Redis 是精确响应缓存不是语义缓存。只有请求的模型、Prompt、消息顺序和相关参数完全一致时才可能复用响应。语义相近但文字不同的请求不会自动命中。7. LiteLLM 的两类 API Key本项目同时使用两把不同用途的 KeyOPENAI_API_KEY_FREE_1Gemini API Key LITELLM_MASTER_KEYLiteLLM 网关访问 Key调用链路是客户端 使用 LITELLM_MASTER_KEY ↓ LiteLLM Proxy 使用 OPENAI_API_KEY_FREE_1 ↓ Gemini API因此客户端调用 LiteLLM 时必须携带Authorization: Bearer $LITELLM_MASTER_KEY不能把 Gemini API Key 直接当作客户端访问 LiteLLM 的 Key。7.1 占位 Master Key 导致的错误最初.env中虽然存在LITELLM_MASTER_KEY但它仍然是占位值replace-with-private-master-key这会导致 LiteLLM 报Malformed API Key passed in.后来生成真实的sk-...Key 并写入.env。修改后必须重启 LiteLLM因为 LiteLLM 只在进程启动时读取环境变量。7.2curl命令末尾多写字符还遇到过这样的命令-HAuthorization: Bearer$LITELLM_MASTER_KEY1末尾的1会被拼接到 Header 值中导致 Key 失效。正确写法是-HAuthorization: Bearer$LITELLM_MASTER_KEY8./health和/v1/models返回 500 的原因匿名访问curlhttp://127.0.0.1:4000/health日志首先出现No api key passed in.随后 LiteLLM 的异常处理器又尝试导入可选的 Prisma 依赖ModuleNotFoundError: No module named prisma最终客户端看到的是{type:internal_server_error}这个 500 的首要原因不是 Redis也不是 MySQL而是认证失败Prisma 错误是错误处理路径中的二次异常。正确的调用方式是set-asource.envsetacurlhttp://127.0.0.1:4000/v1/models\-HAuthorization: Bearer$LITELLM_MASTER_KEY最终成功返回{data:[{id:gemini-3.7-flash}],object:list}这里也再次证明uv run --env-file .env给 LiteLLM 加载环境变量并不会自动给另一个终端里的curl加载环境变量。9. 模型别名和真实模型名称LiteLLM 配置中可以给模型定义别名model_list:-model_name:gemini-3.6-flash-freelayerlitellm_params:model:gemini/gemini-3.6-flashapi_key:os.environ/OPENAI_API_KEY_FREE_1客户端请求使用的是gemini-3.6-flash-freelayer真正交给 Gemini Provider 的模型是gemini/gemini-3.6-flashfreelayer只是项目自定义别名不会自动让账号进入 Gemini 免费层。免费额度和限流策略由 Gemini API Key 对应的账号决定。LiteLLM 可能在模型尚未被真正调用前就成功启动即使底层模型名称写错实际请求时仍可能返回模型不存在或 404。因此模型别名加载成功不代表上游模型调用已经验证成功。10.max_tokens与 Gemini thinking第一次请求使用max_tokens:128返回finish_reason: length content: 很短或不完整原因是 Gemini 3.x 的 thinking/reasoning token 也会占用输出额度。后来把额度提高到max_tokens:1024模型正常返回finish_reason: stop实际 Token 统计类似{completion_tokens:553,reasoning_tokens:526,text_tokens:27}这说明max_tokens不是单纯的“可见文字上限”而是包含模型推理过程在内的输出预算。对于一句简单回答128 可能仍然太小1024 可以让模型有足够空间完成 thinking 和正文。响应中的thought_signatures:[...]是 Gemini Provider 的思考签名元数据不是乱码。客户端通常只需要读取curl...|jq-r.choices[0].message.content11. LiteLLM 的模型成本警告启动时还出现过model... not in built-in cost map cache cost fields will default to 0这表示当前 LiteLLM 内置价格表没有识别某个内部模型标识。它影响的是缓存成本统计不影响Proxy 启动Gemini 请求Redis 连接OpenAI 兼容响应如果以后需要精确统计缓存成本可以补充模型价格信息当前阶段可以先忽略这条警告。12. 最终验证命令12.1 查看模型列表set-asource.envsetacurlhttp://127.0.0.1:4000/v1/models\-HAuthorization: Bearer$LITELLM_MASTER_KEY12.2 调用 OpenAI 兼容聊天接口curlhttp://127.0.0.1:4000/v1/chat/completions\-HAuthorization: Bearer$LITELLM_MASTER_KEY\-HContent-Type: application/json\-d{ model: gemini-3.6-flash-freelayer, messages: [ {role: user, content: 你好请用一句话介绍你自己。} ], max_tokens: 1024 }12.3 只显示模型正文curlhttp://127.0.0.1:4000/v1/chat/completions\-HAuthorization: Bearer$LITELLM_MASTER_KEY\-HContent-Type: application/json\-d{ model: gemini-3.6-flash-freelayer, messages: [ {role: user, content: Reply with exactly: OK} ], max_tokens: 1024 }|jq-r.choices[0].message.content13. 关于 429429 Too Many Requests与本地 LiteLLM 启动问题不同。它通常来自 Gemini 上游常见原因包括免费层请求频率超过限制项目或 API Key 配额耗尽并发请求过多模型本身的配额策略如果gemini-3.7-flash经常返回 429而gemini-3.6-flash可以成功说明网络、LiteLLM 和认证链路未必有问题更可能是特定模型或账号配额问题。当前配置只有一个模型别名时LiteLLM 没有备用模型可以切换。后续如果要做容灾需要在model_list中声明多个模型并配置 fallback否则 429 会直接返回给客户端。14. 当前结论这次本地验证最终确认了以下链路curl → LiteLLM Proxy :4000 → LITELLM_MASTER_KEY 网关认证 → gemini-3.6-flash-freelayer 模型别名 → gemini/gemini-3.6-flash Provider → Gemini API同时LiteLLM Proxy 可以正常启动。litellm[proxy]是运行 Proxy 所需的依赖集合。FastAPI 版本必须与 LiteLLM Proxy 兼容。Redis 部署在 OCIfree-arm-vm节点上跨集群访问依赖 Tailscale。Redis 是精确响应缓存不是语义缓存。Gemini API Key 和 LiteLLM Master Key 是两把不同的 Key。--env-file不会自动更新另一个终端的 shell 环境。/v1/models和聊天接口需要携带 LiteLLM Master Key。prisma报错是认证失败后的二次异常不是本次最初原因。Gemini 3.x 的 thinking 会消耗max_tokens预算。429 需要单独按上游配额和限流问题处理。
返回列表