ImportError: import httpx

这个报错通常出现在使用 OpenAI Python SDK 消费流式响应(stream=True)时,如果流中途发生读取超时或连接中断,SDK 没有包装异常,而是直接把原始 httpx 异常抛出;优先排查你的异常捕获是否只写了 except openai.APIError ,以及你是否依赖 max_

快速结论:这个报错通常出现在使用 OpenAI Python SDK 消费流式响应(stream=True)时,如果流中途发生读取超时或连接中断,SDK 没有包装异常,而是直接把原始 httpx 异常抛出;优先排查你的异常捕获是否只写了 except openai.APIError,以及你是否依赖 max_retries 对中途失败的流进行重试。

适用环境:Issue 中确认的环境为 macOS、Python 3.12.13;受影响库版本为 openai v2.26.0(搭配 httpx 0.28.1)和 openai v3.8.0(搭配 httpx 2.12.0)。

最快修复方案:Issue 中已验证的修复来自 PR #3827,修复后流读取失败会抛出 APITimeoutErrorAPIConnectionError,并将原始异常保留为 __cause__。升级到包含该修复的版本即可。

注意事项:该修复只解决异常包装问题,不会自动重试已部分消费的流。因此即使升级后,流中途失败仍可能需要你自己重建请求并重新消费,不能依赖 max_retries 自动补齐流式请求。

问题场景

用户通过 OpenAI Python SDK 发起流式请求,例如 client.chat.completions.create(..., stream=True),并在循环中逐块消费响应。当流在传输过程中发生读取超时、连接中断或响应体解码错误时,异常会直接逃逸到用户代码。Issue 中的复现脚本使用 MockTransport,先正常产出一个 SSE 数据块,随后在迭代中抛出 httpx.ReadTimeout,从而模拟流中途超时。

报错原文

escaped: httpx.ReadTimeout: timed out while reading the stream
isinstance(e, openai.APIError) = False
requests made with max_retries=2: 1

escaped: httpx2.ReadTimeout: timed out while reading the stream
isinstance(e, openai.APIError) = False
requests made with max_retries=2: 1

原因分析

根据 Issue 描述,_base_client 会在首次发送请求时包装传输层异常:httpx.TimeoutException 转为 APITimeoutError,其他传输错误转为 APIConnectionError,并进入重试循环。但一旦响应进入流式阶段,_streaming.py 在迭代响应时没有做同等处理,因此读取超时或连接中断会以原始 httpx 异常形式抛出。这导致两个直接后果:

  • 异常不属于 openai.APIError,常见的 except openai.APIError 无法捕获;
  • max_retries 不参与流式阶段,复现中设置 max_retries=2 但实际只发出一次请求。

Issue 还指出 anthropic-sdk-python 存在相同的生成基础代码缺陷,但这不影响本仓库的定位。

环境排查

  • 确认 openai 版本:Issue 中复现于 v2.26.0 和 v3.8.0。
  • 确认 httpx 版本及命名空间:httpx 0.28.1 对应 httpx.*,httpx 2.12.0 对应 httpx2.*
  • 确认 Python 版本:Issue 为 3.12.13,建议保持一致以复现问题。
  • 确认调用方式是否为流式:stream=True 并显式迭代响应对象。
  • 确认异常捕获方式:是否只捕获了 openai.APIError
  • 确认 max_retries 设置:如果依赖它在流中途失败后重试,需要确认实际请求次数。
  • 确认是否使用了自定义 http_client 或 MockTransport,此类自定义传输层更容易复现流中异常。

解决步骤

  1. 升级到包含 PR #3827 修复的 openai 版本。该 PR 覆盖同步/异步流中途的超时、连接错误和解码错误,并保留原有 Assistants 流式行为。
  2. 升级后,流读取失败将抛出 APITimeoutErrorAPIConnectionError,而不是原始 httpx.ReadTimeouthttpx.RemoteProtocolError
  3. 如果升级后仍需要定位根本原因,检查异常的 __cause__,修复会将原始异常保留在该属性中。
  4. 如果你的代码中只捕获 openai.APIError,升级后即可正常捕获;但在升级前,可优先尝试同时捕获对应的 httpx 异常类型作为过渡。此处为推测性做法,未在 Issue 中明确验证。
  5. 对于流中途失败后是否重试,需要由你的业务逻辑决定。修复明确说明不会自动重试已部分消费的流。

验证方法

首先确认 openai 版本已包含 #3827 修复。然后重跑 Issue 中的复现脚本或等价的流式请求,观察异常类型是否变为 openai.APITimeoutErroropenai.APIConnectionError,并确认 isinstance(e, openai.APIError) 返回 True。同时检查 max_retries 行为是否符合预期:修复不会对已部分消费的流失效重试,因此 requests_seen 仍应只计一次。

参考来源

openai/openai-python #3811

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 22871

发表回复

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