Skip to content

fix: DeepSeek V4 proxy model recognition — substring match instead of exact set match for reasoning_content injection#9015

Open
irmia2026 wants to merge 1 commit into
AstrBotDevs:masterfrom
irmia2026:fix/deepseek-v4-proxy-reasoning-content
Open

fix: DeepSeek V4 proxy model recognition — substring match instead of exact set match for reasoning_content injection#9015
irmia2026 wants to merge 1 commit into
AstrBotDevs:masterfrom
irmia2026:fix/deepseek-v4-proxy-reasoning-content

Conversation

@irmia2026

@irmia2026 irmia2026 commented Jun 25, 2026

Copy link
Copy Markdown

Summary / 概述

Fix link: Closes #9008

_finally_convert_payload() 中对 DeepSeek V4 的模型识别使用精确集合匹配,导致通过代理/中转使用 DeepSeek V4 的用户(模型 ID 带前缀如 opencode/deepseek-v4-pro)无法被识别,reasoning_content 未被注入,引发 HTTP 400。

本 PR 将精确匹配改为子串匹配,与 MiMo 模型在 #8327 中采用的模式一致。


Root Cause / 根因

# 修改前(L936-940)—— 精确匹配,无法命中带前缀的模型 ID
deepseek_reasoning_models = {"deepseek-v4-pro", "deepseek-v4-flash"}
is_deepseek_v4_reasoning = (
    model in deepseek_reasoning_models         # "opencode/deepseek-v4-pro" ∉ set
    or "api.deepseek.com" in self.client.base_url.host  # 代理 host 也不匹配
)

代理模型 ID 如 opencode/deepseek-v4-pro 既不在精确集合中,host 也不是 api.deepseek.com,两条判断路径均失败 → is_deepseek_v4_reasoning=False → assistant 消息缺少 reasoning_content → API 400。


Changes / 改动

文件: astrbot/core/provider/sources/openai_source.py_finally_convert_payload() (L936-940)

-        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
-        )
+        _deepseek_v4_markers = ("deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4")
+        is_deepseek_v4_reasoning = (
+            any(marker in model for marker in _deepseek_v4_markers)
+            or "api.deepseek.com" in self.client.base_url.host
+        )
+        if is_deepseek_v4_reasoning and (
+            "deepseek-chat" in model or "deepseek-reasoner" in model
+        ):
+            is_deepseek_v4_reasoning = False

改动要点:

  • model in setany(marker in model):覆盖所有代理前缀
  • 新增 "deepseek-v4" 兜底标记:兼容未来子型号
  • 显式排除 deepseek-chat / deepseek-reasoner(v3 模型无需 reasoning_content)
  • 保留 api.deepseek.com host 判断以向后兼容

Verification / 验证

模型 ID 修改前 修改后
deepseek-v4-pro(直连)
deepseek-v4-flash(直连)
opencode/deepseek-v4-pro ❌ 400
opencode/deepseek-v4-flash ❌ 400
星见雅/deepseek-v4-pro ❌ 400
星见雅/deepseek-v4-flash ❌ 400
deepseek-chat(v3) ✅ 不注入 ✅ 不注入
deepseek-reasoner(v3) ✅ 不注入 ✅ 不注入
qwen3.6-plus(非 DeepSeek) ✅ 不注入 ✅ 不注入

真实日志验证(AstrBot v4.25.5, opencode/deepseek-v4-flash):

[11:41:49] [v4.25.5] Chat Model opencode/deepseek-v4-flash request error: Error code: 400 -
{'error': {'message': 'Error from provider (DeepSeek): Invalid assistant message:
content or tool_calls must be set'}}

Relation to #8483 / 与 #8483 的关系

本 PR 与 #8483_sanitize_assistant_messages 中保留带 reasoning_content 的消息)互补:

两者合起来形成 DeepSeek V4 代理场景的完整覆盖。


Checklist

Summary by Sourcery

Relax DeepSeek V4 model detection to support proxy-prefixed model IDs while keeping non-V4 DeepSeek models excluded from reasoning payload injection.

Bug Fixes:

  • Ensure reasoning_content is injected for DeepSeek V4 models accessed via proxy or prefixed model IDs to prevent HTTP 400 errors.

Enhancements:

  • Broaden DeepSeek V4 detection using substring markers including a generic deepseek-v4 marker for future variants while explicitly excluding DeepSeek v3 chat/reasoner models.

@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels Jun 25, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The substring-based _deepseek_v4_markers match is broader than the previous exact set and could accidentally classify unrelated models that happen to contain deepseek-v4; consider constraining this further (e.g., prefix match or a more structured pattern) to avoid false positives.
  • The DeepSeek V4 detection logic is starting to accumulate special cases (markers, host checks, explicit exclusions); it may be clearer and easier to maintain if extracted into a dedicated helper with well-documented rules, reused wherever DeepSeek reasoning behavior is needed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The substring-based `_deepseek_v4_markers` match is broader than the previous exact set and could accidentally classify unrelated models that happen to contain `deepseek-v4`; consider constraining this further (e.g., prefix match or a more structured pattern) to avoid false positives.
- The DeepSeek V4 detection logic is starting to accumulate special cases (markers, host checks, explicit exclusions); it may be clearer and easier to maintain if extracted into a dedicated helper with well-documented rules, reused wherever DeepSeek reasoning behavior is needed.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the DeepSeek v4 reasoning model detection logic in openai_source.py by expanding the model markers and excluding specific chat and reasoner models. The review feedback suggests simplifying this logic by removing redundant substring checks and consolidating the conditions into a single assignment expression.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +936 to +944
_deepseek_v4_markers = ("deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4")
is_deepseek_v4_reasoning = (
model in deepseek_reasoning_models
any(marker in model for marker in _deepseek_v4_markers)
or "api.deepseek.com" in self.client.base_url.host
)
if is_deepseek_v4_reasoning and (
"deepseek-chat" in model or "deepseek-reasoner" in model
):
is_deepseek_v4_reasoning = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since "deepseek-v4" is a substring of both "deepseek-v4-pro" and "deepseek-v4-flash", checking for those specific markers is redundant. We can simplify the entire logic into a single, clean assignment expression, which also avoids re-assigning is_deepseek_v4_reasoning.

        is_deepseek_v4_reasoning = (
            "deepseek-v4" in model
            or "api.deepseek.com" in self.client.base_url.host
        ) and not (
            "deepseek-chat" in model or "deepseek-reasoner" in model
        )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] DeepSeek V4 通过代理使用时,工具调用后 HTTP 400

1 participant