AttributeError: ‘AsyncStream’ object has no attribute ‘aclose’. Did you mean: ‘close’?

这个报错通常出现在使用 OpenAI Python SDK 的异步流式结构化输出(如 client.beta.chat.completions.stream() )并叠加 Langfuse 等埋点/包装库时,包装层让 AsyncStream 的 .response 指回自身而不是底层的 httpx.

快速结论:这个报错通常出现在使用 OpenAI Python SDK 的异步流式结构化输出(如 client.beta.chat.completions.stream())并叠加 Langfuse 等埋点/包装库时,包装层让 AsyncStream.response 指回自身而不是底层的 httpx.Response,触发 AttributeError: 'AsyncStream' object has no attribute 'aclose'. Did you mean: 'close'?。优先排查埋点库是否包装了原始流,以及 SDK 版本是否已包含修复。

适用环境:Issue 中确认的环境为 openai SDK 2.9.0、Python 3.12、Langfuse 3.11.2+(包装 OpenAI 流式响应),配合 LangChain + langchain-openai(使用 with_structured_output() 流式调用)。

最快修复方案:社区已提交修复 PR #2954,为 AsyncStream 添加 aclose() 作为 close() 的别名;可优先尝试升级到包含该修复的 SDK 版本。若无法立即升级,可按评论中给出的临时规避方式(处理 _response 或改用显式流式响应上下文)绕过。

注意事项:Issue 中提到的临时 workaround 属于社区经验,并非官方保证方案;直接访问 stream._response 属于私有属性,SDK 版本变化后可能失效。升级前请确认实际安装版本确实包含 aclose()

问题场景

用户在使用 OpenAI Python SDK 的异步流式接口时触发该问题,典型路径为 client.beta.chat.completions.stream(),或任何经过 AsyncChatCompletionStream 的调用。触发条件是在此之上叠加了会包装原始流的 instrumentation 库(Issue 中为 Langfuse),并配合 LangChain + langchain-openai 的 with_structured_output() 进行流式结构化输出。同步的 Stream 类不受影响,因为其调用方使用 close()

报错原文

File ".../openai/lib/streaming/chat/_completions.py", line 290, in __aexit__
    await self.__stream.close()
File ".../openai/lib/streaming/chat/_completions.py", line 215, in close
    await self._response.aclose()
AttributeError: 'AsyncStream' object has no attribute 'aclose'. Did you mean: 'close'?

原因分析

调用链是:AsyncChatCompletionStreamManager.__aexit__ 调用 self.__stream.close(),后者调用 self._response.aclose()。问题在于 self._response = raw_stream.response:当 instrumentation 库包装了 AsyncStream 后,.response 解析到的是 AsyncStream 本身,而不是底层的 httpx.Response。而 AsyncStream 只暴露了 close(),没有 aclose(),因此抛出 AttributeError。也就是说,根本原因是 AsyncStream 未遵循 PEP 525 的异步清理约定提供 aclose(),在被包装、.response 指向自身时暴露出来。

环境排查

  • 确认 openai SDK 版本,Issue 中出问题版本为 2.9.0,需确认是否已升级到包含 PR #2954 的版本。
  • 确认 Python 版本,Issue 中为 3.12。
  • 确认是否使用了 instrumentation/埋点库包装流式响应,Issue 中为 Langfuse 3.11.2+。
  • 确认是否通过 LangChain + langchain-openai 的 with_structured_output() 走流式路径。
  • 检查出错堆栈是否命中 _completions.py__aexit__ / close / _response.aclose(),以确认与本次问题同源。

解决步骤

  1. 先确认是否命中了同一个报错堆栈,即 _completions.py__aexit__close_response.aclose(),且异常为 AttributeError: 'AsyncStream' object has no attribute 'aclose'. Did you mean: 'close'?
  2. 可优先尝试升级 OpenAI Python SDK:社区已在 PR #2954 中为 AsyncStream 添加 aclose() 作为 close() 的别名,升级到包含该改动的版本后此调用链应不再报错。
  3. 若暂时无法升级,可按 Issue 评论中的临时规避思路处理:在流消费结束后显式对底层响应做清理,例如在 finally 中判断 hasattr(stream, '_response') 后调用 await stream._response.aclose();注意该写法访问私有属性,属于 workaround。
  4. 另一种规避方式是改用显式流式响应上下文,即通过 async with client.with_streaming_response.chat.completions.create(...) 消费流,由上下文管理器负责清理。
  5. 如需防止流长时间挂起,可考虑为流消费加超时包装(async timeout),但这是健壮性增强,并非本报错的根因修复。
  6. 如果升级后问题仍存在,检查埋点库是否仍以老方式包装流,以及其版本是否适配当前 SDK。

验证方法

在同样的异步流式调用路径(含埋点包装)下重新运行,确认 AsyncStream 已具备 aclose() 属性,且 __aexit__ 清理阶段不再抛出 AttributeError;同时观察生产环境中的连接是否不再泄漏。若使用 workaround,验证重点是流消费结束后底层响应被正确关闭。

参考来源

openai/openai-python #2853

langfuse/langfuse #5685

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 22717

发表回复

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