From 50e0bc651387951a83ed842c736edcca1ab1c460 Mon Sep 17 00:00:00 2001 From: xiaoxi68 <3520824673@qq.com> Date: Sat, 1 Nov 2025 16:40:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(openai):=20=E4=BF=AE=E5=A4=8D=E7=A9=BA?= =?UTF-8?q?=E5=9B=9E=E5=A4=8D=20TypeError=EF=BC=88choices=3DNone=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=9C=A8=E6=8A=9B=E9=94=99=E5=89=8D=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/llm_models/model_client/openai_client.py | 29 ++++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/llm_models/model_client/openai_client.py b/src/llm_models/model_client/openai_client.py index 137ca78e..36af7775 100644 --- a/src/llm_models/model_client/openai_client.py +++ b/src/llm_models/model_client/openai_client.py @@ -370,9 +370,32 @@ def _default_normal_response_parser( """ api_response = APIResponse() - if not hasattr(resp, "choices") or len(resp.choices) == 0: - raise EmptyResponseException("响应解析失败,缺失choices字段或choices列表为空") - message_part = resp.choices[0].message + # 兼容部分 OpenAI 兼容服务在空回复时返回 choices=None 的情况 + choices = getattr(resp, "choices", None) + if not choices: + try: + model_dbg = getattr(resp, "model", None) + id_dbg = getattr(resp, "id", None) + usage_dbg = None + if hasattr(resp, "usage") and resp.usage: + usage_dbg = { + "prompt": getattr(resp.usage, "prompt_tokens", None), + "completion": getattr(resp.usage, "completion_tokens", None), + "total": getattr(resp.usage, "total_tokens", None), + } + try: + raw_snippet = str(resp)[:300] + except Exception: + raw_snippet = "" + logger.debug( + f"empty choices: model={model_dbg} id={id_dbg} usage={usage_dbg} raw≈{raw_snippet}" + ) + except Exception: + # 日志采集失败不应影响控制流 + pass + # 统一抛出可重试的 EmptyResponseException,触发上层重试逻辑 + raise EmptyResponseException("响应解析失败,choices 为空或缺失") + message_part = choices[0].message if hasattr(message_part, "reasoning_content") and message_part.reasoning_content: # type: ignore # 有有效的推理字段 From b63057edeca6e9e9090634aec798df273bc31f6a Mon Sep 17 00:00:00 2001 From: exynos <110159911+exynos967@users.noreply.github.com> Date: Sun, 2 Nov 2025 17:33:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(model=5Futils):=20HTTP=20400=20?= =?UTF-8?q?=E4=B8=8D=E7=BB=88=E6=AD=A2=E5=85=A8=E5=B1=80=E5=B0=9D=E8=AF=95?= =?UTF-8?q?=EF=BC=8C=E7=BB=A7=E7=BB=AD=E5=88=87=E6=8D=A2=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/llm_models/utils_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llm_models/utils_model.py b/src/llm_models/utils_model.py index 4d7865d9..0474b9d7 100644 --- a/src/llm_models/utils_model.py +++ b/src/llm_models/utils_model.py @@ -369,8 +369,8 @@ class LLMRequest: failed_models_this_request.add(model_info.name) if isinstance(last_exception, RespNotOkException) and last_exception.status_code == 400: - logger.error("收到不可恢复的客户端错误 (400),中止所有尝试。") - raise last_exception from e + logger.warning("收到客户端错误 (400),跳过当前模型并继续尝试其他模型。") + continue logger.error(f"所有 {max_attempts} 个模型均尝试失败。") if last_exception: