Skip to content

DeepSeek 模型使用 openai-legacy provider 时 xhigh/max thinking effort 被错误 clamp 为 high (v0.11.0 regression #457) #525

@chengkeen

Description

@chengkeen

DeepSeek 模型使用 openai-legacy provider 时 xhigh/max thinking effort 被错误 clamp 为 high

问题描述

当用户配置了 DeepSeek 模型(deepseek/deepseek-v4-flashdeepseek/deepseek-v4-pro 等)并通过 openai-legacy adapter 使用时,xhighmax 的 thinking effort 会被 clampChatCompletionsReasoningEffort 函数强行降级为 high,导致 DeepSeek 实际支持的 max 级别无法生效。

复现步骤

  1. 配置 DeepSeek 模型(type = "openai"),例如:

    [models."deepseek/deepseek-v4-flash"]
    provider = "deepseek"
    model = "deepseek-v4-flash"
    capabilities = ["thinking", "tool_use"]
    reasoning_key = "reasoning_content"
  2. 设置 thinking effort 为 xhighmax

    [thinking]
    effort = "xhigh"
  3. 发起对话时,实际发送给 DeepSeek API 的 reasoning_effort"high" 而非 "xhigh"/"max"

根因分析

问题出在 packages/kosong/src/providers/openai-legacy.ts:138-146clampChatCompletionsReasoningEffort 函数:

function clampChatCompletionsReasoningEffort(
  reasoningEffort: string | undefined,
  model: string,
): string | undefined {
  if (reasoningEffort !== 'xhigh') {
    return reasoningEffort;
  }
  return supportsOpenAIChatCompletionsXHighReasoning(model) ? 'xhigh' : 'high';
}

该函数调用 supportsOpenAIChatCompletionsXHighReasoning(定义在 capability-registry.ts:209-211)来判断模型是否支持 xhigh,但该函数只检查 OpenAI 的模型白名单:

const OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS = new Set([
  'gpt-5.2',
  'gpt-5.4',
  'gpt-5.5',
]);

export function supportsOpenAIChatCompletionsXHighReasoning(modelName: string): boolean {
  return OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS.has(modelIdLeaf(modelName));
}

由于 DeepSeek 模型名(如 deepseek-v4-flash)不在该白名单中,xhighmax 被统一降级为 high

完整的代码链路

用户配置: thinking.effort = "xhigh"
    ↓
thinkingEffortToReasoningEffort("xhigh") → "xhigh"       (openai-common.ts:176-178)
    ↓
clampChatCompletionsReasoningEffort("xhigh", "deepseek-v4-flash")  (openai-legacy.ts:520-528)
    ↓
supportsOpenAIChatCompletionsXHighReasoning("deepseek-v4-flash") → false  (capability-registry.ts:209-211)
    ↓
返回 "high"   ← xhigh 被错误降级

同时 max 也是同样的命运:

thinkingEffortToReasoningEffort("max") → "xhigh"  (openai-common.ts:177-178)
    ↓ ...同样的 clamp 路径...
    ↓ 返回 "high"

回归分析(v0.11.0 引入)

该问题由 PR #457v0.11.0 中引入。v0.10.1 及之前版本没有此问题。

v0.10.1 的行为(正常)

`thinking.effort = "xhigh"` → `thinkingEffortToReasoningEffort("xhigh")` → `"xhigh"` → 直接发给 DeepSeek ✅
`thinking.effort = "max"`   → `thinkingEffortToReasoningEffort("max")`   → `"xhigh"` → 直接发给 DeepSeek ✅

v0.10.1 中 withThinking 的实现是直接调用 thinkingEffortToReasoningEffort,没有任何 clamping:

// openai-legacy.ts v0.10.1 (第 508 行)
const reasoningEffort = thinkingEffortToReasoningEffort(effort);

DeepSeek 收到 reasoning_effort: "xhigh" 后正常接受,按文档说明映射为 max 处理。

v0.11.0 的变更(导致 bug)

PR #457 出于对 OpenAI Pro/Codex 模型(Responses-only,不支持 v1/chat/completions 上的 xhigh)的兼容考虑,在共享的 openai-legacy provider 中新增了 clamping 层:

// openai-legacy.ts v0.11.0 (第 520-524 行)
+ const reasoningEffort = clampChatCompletionsReasoningEffort(
+   thinkingEffortToReasoningEffort(effort),
+   this._model,   // ← 新增 model 参数用于白名单检查
+ );

同时新增了 capability-registry.ts 中的白名单:

+ const OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS = new Set([
+   'gpt-5.2',
+   'gpt-5.4',
+   'gpt-5.5',
+ ]);
+ export function supportsOpenAIChatCompletionsXHighReasoning(model) { ... }

问题核心: clamping 逻辑在共享的 openai-legacy provider 中实现,没有区分 OpenAI 原生模型和其他 OpenAI-compatible 供应商(DeepSeek、Qwen、One API 网关等),导致所有非 OpenAI xhigh 白名单内的模型都被误伤。

涉及文件 diff

  • packages/kosong/src/providers/openai-legacy.ts — 新增 clampChatCompletionsReasoningEffort 函数和调用
  • packages/kosong/src/providers/capability-registry.ts — 新增 OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS 白名单和 supportsOpenAIChatCompletionsXHighReasoning 函数
  • packages/kosong/src/providers/openai-common.ts — 无变化

预期行为

DeepSeek 官方 API 文档(https://api-docs.deepseek.com/zh-cn/guides/thinking_mode)明确支持 reasoning_effort"high""max",且 xhigh 会被映射为 max。因此:

  1. 对于 DeepSeek 模型,xhighreasoning_effort: "xhigh"(DeepSeek 自行映射为 max
  2. 对于 DeepSeek 模型,maxreasoning_effort: "max"(DeepSeek 原生支持)

建议修复方案

clampChatCompletionsReasoningEffort 的 clamping 逻辑不应该无差别应用于所有 openai-legacy provider 的模型。建议:

  1. 将 clamping 逻辑限制为仅对已知的 OpenAI 模型生效(即检查 model 是否包含 gpt-o1o3 等 OpenAI 前缀),或者
  2. 让 provider 类型(如 DeepSeek 使用独立的 provider 类)来决定是否需要 clamping,或者
  3. 在配置层面增加一个选项,让用户指示该 provider 是否支持 xhigh/max reasoning effort。

涉及的文件

  • packages/kosong/src/providers/openai-legacy.ts — clamping 函数 clampChatCompletionsReasoningEffort(第 138-146 行)和调用点 withThinking(第 520-528 行)
  • packages/kosong/src/providers/capability-registry.ts — OpenAI xhigh 模型白名单(第 27-31 行)和判断函数(第 209-211 行)
  • packages/kosong/src/providers/openai-common.tsthinkingEffortToReasoningEffort 映射函数(第 166-182 行)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions