From d3a03ad206f6a4c7fad95cfe89a29d34b75d88d2 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Mon, 27 Apr 2026 02:17:29 +0800 Subject: [PATCH] fix: handle empty reasoning content for DeepSeek v4 models Co-authored-by: Copilot --- astrbot/core/provider/sources/openai_source.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index f2d9474906..80f32159f1 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -963,6 +963,11 @@ def _finally_convert_payload(self, payloads: dict) -> None: """Finally convert the payload. Such as think part conversion, tool inject.""" model = payloads.get("model", "").lower() is_gemini = "gemini" in model + deepseek_reasoning_models = {"deepseek-v4-pro", "deepseek-v4-flash"} + is_deepseek_v4_reasoning = ( + model in deepseek_reasoning_models + or "api.deepseek.com" in self.client.base_url.host + ) for message in payloads.get("messages", []): if message.get("role") == "assistant" and isinstance( @@ -978,7 +983,14 @@ def _finally_convert_payload(self, payloads: dict) -> None: # Some providers (Grok, etc.) reject empty content lists. # When all parts were think blocks, fall back to None. message["content"] = new_content or None - if reasoning_content: + if is_deepseek_v4_reasoning and not reasoning_content: + logger.info( + "Deepseek v4 model requires non-empty reasoning content, but got empty. Setting to 'none' to satisfy the requirement." + ) + # Deepseek models require the field on assistant + # history messages, even when the reasoning content is empty. + message["reasoning_content"] = "none" + elif reasoning_content: message["reasoning_content"] = reasoning_content # Gemini 的 function_response 要求 google.protobuf.Struct(即 JSON 对象),