Title: Vertex AI Gemini streaming silently drops per-request timeout, falling back to litellm.request_timeout (6000s)

当你在 LiteLLM 里对 Vertex AI / Google AI Studio Gemini 模型使用 stream=True (含 timeout= )时,per-request 超时会被静默丢弃,流卡住时不会按你设置的秒数失败,而是回退到 litellm.request_timeout

快速结论:当你在 LiteLLM 里对 Vertex AI / Google AI Studio Gemini 模型使用 stream=True(含 timeout=)时,per-request 超时会被静默丢弃,流卡住时不会按你设置的秒数失败,而是回退到 litellm.request_timeout(默认 6000 秒)。优先检查你用的 LiteLLM 版本是否已包含该修复。

适用环境:工具 LiteLLM;版本 litellm == 1.83.0(main 分支亦可复现);Python 3.10;Provider 为 vertex_ai 与 gemini(两者走同一个 handler)。

最快修复方案:暂无确认的一步修复方案。Issue 中提到的分支补丁(bugfix/vertex-streaming-timeout-forwarding,commit 87f2884cc7)尚未合入上游,可优先尝试升级到包含该修复的 LiteLLM 版本,或按“解决步骤”手动为 streaming 分支传递 timeout。

注意事项:不要依赖 litellm.request_timeout 临时兜底,它只会掩盖单次超时被忽略的问题;异常信息里的 None(Connection timed out after None seconds.)是报错文案缺陷,不代表真的没有传 timeout。

问题场景

用户在 LiteLLM 中调用 litellm.completion(..., stream=True) 访问 Vertex AI 或 Google AI Studio 的 Gemini 模型(例如 vertex_ai/gemini-2.5-flash),并显式传入 per-request 的 timeout=2。当上游流在输出第一个 token 之前卡住(高负载下常见)时,调用不会在约 2 秒后失败,而是挂到 litellm.request_timeout(示例中为 30 秒,默认 6000 秒)才抛出超时。同一 handler 的非流式分支超时传递正常,只有流式分支失效。

报错原文

Title: Vertex AI Gemini streaming silently drops per-request timeout, falling back to litellm.request_timeout (6000s)

litellm.Timeout: Connection timed out after None seconds.

# repro
litellm.request_timeout = 30

response = litellm.completion(
    model="vertex_ai/gemini-2.5-flash",
    messages=[{"role": "user", "content": "hello"}],
    stream=True,
    timeout=2,
)
# expected: fail in ~2s
# observed: hangs ~30s (litellm.request_timeout)

原因分析

最可能的原因在 litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py:VertexLLM.completion() 的流式分支(约 2944 行)在构造 make_sync_call 的 partial 时没有传入 timeout,而 make_sync_call 本身也没有 timeout 参数,其内部 client.post(...) 自然无法传递超时。于是用户传入的 timeout 被丢弃,最终由复用/新建的 httpx client 的默认超时接管(HTTPHandler 使用 _DEFAULT_TIMEOUT = httpx.Timeout(5.0, connect=5.0))。

异步路径同样存在问题:VertexLLM.async_streaming() 接受 timeout 参数,但没有把它传进 HTTP 请求;它构造的 CustomStreamWrapper 的 make_call 是 functools.partial(make_call, ...),而模块级 make_call() 签名里没有 timeout。流真正发起 POST 时使用的是进程级缓存的 AsyncHTTPHandler,其超时被固定在 COMPLETION_HTTP_FALLBACK_SECONDS(600 秒),调用方的 per-request timeout 被静默忽略。作为对照,非流式的 async_completion() 已经通过构造带超时的 httpx client 正确处理了 timeout。

异常文案中的 None 来自 litellm/llms/custom_httpx/http_handler.py:1031 附近的同步 HTTPHandler.post():它用本地 timeout 变量拼接消息,而该变量此时为 None。

环境排查

  • 确认 LiteLLM 版本:litellm == 1.83.0(或是否已升级到含修复的版本)。
  • 确认 Python 版本:Issue 报告为 Python 3.10。
  • 确认 provider:vertex_ai 和 gemini 两条路由都会命中同一个 handler。
  • 确认调用方式:是否为 stream=True,且 timeout 是通过 litellm.completion(..., timeout=...) 传入的 per-request 参数。
  • 确认是否同时设置了全局 litellm.request_timeout,以免混淆实际生效的超时来源。
  • 若涉及代理/Router,确认 timeout 是否从 Router 正确透传到 async_streaming()。

解决步骤

  1. 先确认问题是否已在当前版本修复:将 LiteLLM 升级到包含相关改动的版本,再复跑 Issue 中的 repro 脚本,观察失败时间是否接近 timeout=2。
  2. 若暂不能升级,可按 Issue 的补丁思路手动修改 litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py,共四处改动。
  3. 给异步 make_call() 增加 timeout: Optional[Union[float, httpx.Timeout]] = None 参数,并在其 await client.post(...) 中传入 timeout=timeout。
  4. 给同步 make_sync_call() 增加同样的 timeout 参数,并在其 client.post(...) 中传入 timeout=timeout。
  5. 在 async_streaming() 与流式 completion() 构造的 partial(make_call, ...) / partial(make_sync_call, ...) 闭包中补上 timeout=timeout。
  6. 无需新建 httpx client:AsyncHTTPHandler.post() 和 HTTPHandler.post() 本身已接受 timeout kwarg,可在单次调用上覆盖 client 级超时。
  7. 修改后重启相关进程,使进程内缓存的 HTTP handler 不再沿用旧代码路径。

验证方法

使用 Issue 中的 repro 脚本:设置较小的 litellm.request_timeout(例如 30),对会卡住的流式请求传入 timeout=2,预期约 2 秒失败,而不是约 30 秒或 6000 秒。同时确认异常不再出现 after None seconds 这类无意义占位;若失败时间仍贴合全局 request_timeout,说明修复未生效。

参考来源

BerriAI/litellm #26939

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29130

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注