Skip to content

fix(deepseek): map max thinking level to max instead of high - #360

Open
xiaYuTian11 wants to merge 2 commits into
Stack-Cairn:mainfrom
xiaYuTian11:fix/deepseek-max-reasoning-effort
Open

fix(deepseek): map max thinking level to max instead of high#360
xiaYuTian11 wants to merge 2 commits into
Stack-Cairn:mainfrom
xiaYuTian11:fix/deepseek-max-reasoning-effort

Conversation

@xiaYuTian11

@xiaYuTian11 xiaYuTian11 commented Aug 2, 2026

Copy link
Copy Markdown

Linked issue

Closes #361

Summary

DeepSeek 适配器缺失 max 思考档位的映射,导致 UI 上选择「最高」与「高」发出完全相同的请求。

模型目录 catalog.generated.ts 声明 deepseek-v4-flash / deepseek-v4-pro 支持 ["high", "max"],UI 因此渲染出「高 / 最高」两档。但适配器侧 DEEPSEEK_THINKING_LEVEL_MAPmapDeepSeekReasoningEffort 只认 xhigh → max;而 xhigh 目录并未声明、永远不可选,于是 max → max 这条路径不可达,所有档位都落进 else 分支被压成 "high"

目录与适配器是同一发布包内的两个文件,属于构造性不对齐,用户侧无任何配置可以绕过。

UI 档位 修复前 reasoning_effort 修复后
高 (high) "high" "high"
最高 (max) "high" ← bug "max"

Change scope

  • Modules: agent-gui
  • Key paths: crates/agent-gui/src/lib/providers/deepSeekProviderAdapter.ts(单文件,+2/-1)

两处改动:

// 1) DEEPSEEK_THINKING_LEVEL_MAP 补 max
   high: "high",
+  max: "max",
   xhigh: "max",

// 2) mapDeepSeekReasoningEffort 把 max 与 xhigh 同等对待
-  return reasoning === "xhigh" ? "max" : "high";
+  return reasoning === "xhigh" || reasoning === "max" ? "max" : "high";

修复覆盖三个调用点:

调用点 字段
normalizeDeepSeekOpenAIPayload reasoning_effort
normalizeDeepSeekAnthropicPayload output_config.effort
resolveDeepSeekAnthropicThinkingRuntimestreamByApi.ts Anthropic thinking runtime effort

Screenshots / preview

DeepSeek thinking level to wire reasoning_effort — before/after

关于「无可视变化」:本 PR 虽改动 crates/agent-gui/src/ 下的文件,但不触及渲染层。composer 的 ✨ 档位下拉在修复前后都显示「高 / 最高」两档,界面截图逐像素一致、不构成任何证据。真正变化的是发往模型的请求体,故上图给出 wire payload 的前后对照(并按 CONTRIBUTING 对后端类改动的要求,在下方以文本复现)。

驱动真实 streamSimpleByApi + onPayload 管线(模型经 createModelFromConfig 构造,mock openai-completionsstream 拦截请求体):

修复前

deepseek-v4-pro   UI=high | clampOpenAI=high | wire reasoning_effort=high | thinking={"type":"enabled"}
deepseek-v4-pro   UI=max  | clampOpenAI=max  | wire reasoning_effort=high | thinking={"type":"enabled"}   <-- 应为 "max"
deepseek-v4-flash UI=high | clampOpenAI=high | wire reasoning_effort=high
deepseek-v4-flash UI=max  | clampOpenAI=max  | wire reasoning_effort=high                                  <-- 应为 "max"

修复后

deepseek-v4-pro   UI=high | clampOpenAI=high | wire reasoning_effort=high | thinking={"type":"enabled"}
deepseek-v4-pro   UI=max  | clampOpenAI=max  | wire reasoning_effort=max  | thinking={"type":"enabled"}
deepseek-v4-flash UI=high | clampOpenAI=high | wire reasoning_effort=high
deepseek-v4-flash UI=max  | clampOpenAI=max  | wire reasoning_effort=max

注意 clampOpenAI=max:档位完整通过目录钳制、以 "max" 抵达适配器,是适配器自身的映射把它丢弃的。

函数级对照:

=== mapDeepSeekReasoningEffort ===
输入        修复前      修复后
undefined   undefined   undefined
minimal     high        high
low         high        high
medium      high        high
high        high        high
xhigh       max         max
max         high  <-bug max   OK

Verification

无回归

  • 非 DeepSeek 模型不进适配器,档位原样透传:gpt-5.6-terralow/high/xhigh/max 全部未受影响,deepSeekProviderAdapter=false

  • thinkingLevelMap 仍与目录声明对齐,applyDeepSeekModelDefaults 中「wire 表不得复活目录裁掉的档」这一约束未被破坏:

    模型 派生 thinkingLevelMap 说明
    deepseek-v4-pro / -flash {minimal:null, low:null, medium:null, high:"high", max:"max"} 与目录 ["high","max"] 一致
    deepseek-chat reasoning=false,无 max 非推理模型,不受影响
    deepseek-reasoner 全档 null 思考恒开不可调,不受影响

执行的检查

cd crates/agent-gui && node --test test/providers/request-options.test.mjs \
  test/providers/thinking-levels.test.mjs test/models/model-thinking.test.mjs \
  test/models/model-thinking-consistency.test.mjs test/models/model-catalog.test.mjs \
  test/providers/provider-runtime-config.test.mjs
-> 86 tests, 86 pass, 0 fail

node scripts/check-mirror.mjs
-> mirror check passed (119 file(s))

cd crates/agent-gui && npm run test:frontend
-> 1415 tests, 1410 pass, 5 fail

那 5 项失败与本改动无关,已在父提交 7de95a20 上复现同样失败,属仓库既有状态:mention-composer-selection(2 项)与 mention-refetch(2 项)是测试自身的函数提取正则问题,preset scripts stay in sync with the Rust builtin presets 是 Rust 预设同步检查。

该适配器不在 scripts/mirror-manifest.json 内,gateway WebUI 侧亦无对应文件,无需同步改动。

关于测试用例:现有 request-options.test.mjs 已断言 model.thinkingLevelMap.max === "max"(目录侧),但没有覆盖 max 档的 wire 值。如维护者希望补一条针对 reasoning: "max"reasoning_effort: "max" 的回归测试,我可以在本分支追加。

Pre-submit checklist

DeepSeek adapter has a bug where the catalog declares 'max' as a
supported thinking level for deepseek-v4-flash and deepseek-v4-pro,
but both DEEPSEEK_THINKING_LEVEL_MAP and mapDeepSeekReasoningEffort
only map 'xhigh' → 'max'. Any non-xhigh value (including 'max')
falls through to 'high', making the UI's '最高' setting behave
identically to '高'.

Fix:
- Add max: 'max' to DEEPSEEK_THINKING_LEVEL_MAP so the wire value is
  correct when the catalog declares max support.
- Update mapDeepSeekReasoningEffort to treat both 'xhigh' and 'max'
  as 'max', so the payload adapter sends reasoning_effort: 'max'
  when the user selects the highest level.

This affects all three call sites:
1. normalizeDeepSeekOpenAIPayload (OpenAI-compat path)
2. normalizeDeepSeekAnthropicPayload (Anthropic-compat path)
3. resolveDeepSeekAnthropicThinkingRuntime in streamByApi.ts
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

PR governance checks passed. Awaiting human review.

@StackCairn
StackCairn marked this pull request as draft August 2, 2026 07:12
@xiaYuTian11
xiaYuTian11 marked this pull request as ready for review August 2, 2026 07:18
@StackCairn
StackCairn marked this pull request as draft August 2, 2026 07:19
@xiaYuTian11
xiaYuTian11 marked this pull request as ready for review August 2, 2026 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] DeepSeek 思考档位「最高」与「高」发出相同的 reasoning_effort,max 映射缺失

2 participants