[Bug]: Proxy keeps upstream LLM connection open after a streaming client disconnects; backend keeps generating or stays blocked

该问题通常发生在 LiteLLM Proxy 流式转发(stream=true)过程中,客户端中途断开或停止读取时,Proxy 未关闭上游 LLM 连接,导致后端持续生成或阻塞;应优先排查客户端断开路径上是否真正调用了 CustomStreamWrapper.aclose() ,以及超时配置是否兜底

快速结论:该问题通常发生在 LiteLLM Proxy 流式转发(stream=true)过程中,客户端中途断开或停止读取时,Proxy 未关闭上游 LLM 连接,导致后端持续生成或阻塞;应优先排查客户端断开路径上是否真正调用了 CustomStreamWrapper.aclose(),以及超时配置是否兜底。

适用环境:Issue 复现环境为 litellm_internal_staging @ 0d120de785、uvicorn 0.33.0(ASGI spec_version 2.3)、starlette 1.1.0;评论中的实测环境为 LiteLLM 1.105.1、vLLM 0.31.0、Qwen3-8B、单张 L4。Proxy 使用 openai/mock-model 指向本地 OpenAI 兼容 mock 后端。

最快修复方案:暂无确认的一步修复方案。Issue 明确指出 CustomStreamWrapper.aclose() 逻辑本身正确,问题在于断开路径上没有任何地方调用它;评论中的实测表明配置 1 s LiteLLM 超时可在三种客户端行为下停止上游,但这只是该场景下的规避手段,不是 Issue 验证过的代码修复。

注意事项:评论中的超时实测使用的是 openai/ provider 前缀,并未覆盖 hosted_vllm/ 路径(该路径由 #30245 修复)。短超时会影响正常长流式响应的可用性,是否适用于生产需自行评估。

问题场景

用户在 LiteLLM Proxy 上发起流式聊天补全请求(stream: true),后端为自托管的 vLLM / TGI / SGLang 等 OpenAI 兼容服务。客户端在流式传输中途断开连接,例如 curl 被 --max-time 杀掉,或 OpenWebUI 等 UI 点击停止并关闭连接。此时 Proxy 停止读取上游流,但不会关闭它。

报错原文

[Bug]: Proxy keeps upstream LLM connection open after a streaming client disconnects; backend keeps generating or stays blocked

原因分析

Issue 给出的根因是:CustomStreamWrapper.aclose() 存在且能正确关闭上游流,但断开路径上没有任何调用方。在 uvicorn 0.33(ASGI spec_version 2.3)下,Starlette 的 StreamingResponse 会让 stream_response 与 listen_for_disconnect 竞争;一旦检测到断开,它会直接放弃 body 迭代器,而不调用其 aclose()。

由此,生成器链(combined_generator → async_streaming_data_generator / async_data_generator → CustomStreamWrapper)被挂起,只在 GC 时才可能被终结。上游连接因此保持 ESTABLISHED:小响应被写入 TCP 缓冲区,后端误以为正常完成;大响应(如 256KB 分块)会填满缓冲区并让后端永久阻塞。对 vLLM 而言,对应的 GPU 生成槽位会一直占用。

可能的相关影响:断开前已流出的 token 不会计入 spend log,因为 CustomStreamWrapper 只在自然收到最后一个 chunk 时触发日志。

环境排查

  • 确认 uvicorn 版本是否为 0.33.x,以及 ASGI spec_version 是否为 2.3(该行为在 Issue 中与 starlette 1.1.0 组合复现)。
  • 确认 Starlette 版本。
  • 确认 LiteLLM 版本(复现版本为 litellm_internal_staging @ 0d120de785;评论实测为 1.105.1)。
  • 确认后端类型与版本,Issue 涉及 vLLM(评论实测 0.31.0)、TGI、SGLang。
  • 确认 Proxy 配置中 provider 前缀是 openai/ 还是 hosted_vllm/,两者修复路径不同。
  • 确认是否配置了 LiteLLM 超时;评论实测 1 s 超时可使上游停止。

解决步骤

  1. 先在测试环境复现并观察上游连接状态:客户端中途中止流式请求后,用 lsof -nP -iTCP:9090 -sTCP:ESTABLISHED 检查 Proxy 与后端之间是否仍有 ESTABLISHED 连接,并查看后端日志是否出现 abort/完成记录。
  2. 对照环境确认 uvicorn / starlette 版本是否命中上述断开时跳过 aclose() 的路径,缩小问题范围。
  3. 可优先尝试:在 LiteLLM 侧配置较短的请求超时(评论中 1 s 超时在“客户端关闭连接”“停止读取但保持 socket”“读到结尾”三种行为下都停止了上游)。注意这只是规避,且会限制正常长流式请求。
  4. 若使用 hosted_vllm/ provider,请关注 #30245 中的修复,而不是按评论中的 openai/ 配置结论处理。
  5. Token 计费方面,由于断开前已流出的 token 不会写入 spend log(参见 #14457),如有计费需求需单独核对,不要依赖日志完整性。

验证方法

重复断开场景:客户端中止后,检查 Proxy 到后端的连接是否在短时间内消失,后端日志是否记录到 abort 而非继续生成或长时间挂起;若后端为 vLLM,可观察对应请求的生成槽位是否及时释放。评论中的方法是通过 vLLM 0.31.0 scheduler 统计取消后接受的 token 数,与直连 vLLM 对照,以此确认上游是否真正被停止。

参考来源

BerriAI/litellm #30244

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29676

发表回复

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