Skip to content

feat: 允许为 openai-compatible(中转站)连接手动声明 thinkingOptions,以启用思考深度调节 #2219

Description

@cat0825

概述

openai-compatible(中转站/代理)连接无法调节模型思考深度:聊天输入框左下角不显示"思考级别"选择器,请求体也不会带上 reasoning_effort

DeepSeek 官方 API 已支持 reasoning_effort: low/high/max + thinking: {type: enabled/disabled}(OpenAI 兼容格式),且该参数是 OpenAI 兼容协议的标准顶层参数,透传型中转站原样转发即可生效。堵住的不是中转站,而是 Maka 这一层没有暴露声明入口。

期望:用户能在 openai-compatible 连接的模型上手动声明思考能力,声明后即可使用思考级别选择器,Maka 在请求中发送对应的 reasoning_effort

复现

  1. Maka 0.1.5(macOS Apple Silicon)。
  2. 设置中添加 openai-compatible 连接(例如 DeepSeek 中转站,baseURL https://tokenrhythm.studio/v1),模型列表通过 /v1/models 拉取。
  3. 新建聊天,选中该连接的 reasoning 模型(如 deepseek-v4-flash-0731)。
  4. 观察输入框左下角:模型选择器旁没有"思考级别"选择器。

根因

代码定位(当前 0.1.5):

  • packages/core/src/model-thinking.tsthinkingVariantsForModel(providerType, modelId)
    • 只按 providerType + modelId 查询内置目录 model-metadata.ts
    • openai-compatible 无任何目录条目,直接返回 [];源码注释明确这是保守策略:"backing model is user-configured and unknown"。
  • UI 层(packages/ui/src/chat-model-switcher.tsxThinkingLevelSelector):levels 为空时直接 return null,控件不渲染。
  • 服务端校验(apps/desktop/src/main/sessions-ipc-main.tsnormalizeSupportedSessionThinkingLevel):同一函数校验,空列表时抛"当前模型不支持思考级别"。
  • 连接模型条目 schema(packages/core/src/llm-connections.ts):只有 id / displayName / apiProtocol / contextWindow / maxOutputTokens / capabilities / modalities没有 thinkingOptions 字段,用户无从声明。

wire 层已就绪(无需改动)

  • ai-sdk @ai-sdk/openai-compatible:providerOptions 支持 reasoningEffort,映射为请求体顶层 reasoning_effortdist/index.jsreasoning_effort: compatibleOptions.reasoningEffort ?? ...)。
  • packages/runtime/src/model-factory.tsbuildFamilyWire 已有 openai-compatible 分支:{ [openAiCompatibleProviderOptionsName(...)]: { reasoningEffort } },命名空间为 connection.slug

即:只要 thinkingLevel 能进入 buildProviderOptions,请求就会自动带上 reasoning_effort。缺的只是"声明 → 查询 → 校验 → UI"这一条链。

建议方案(per-model 声明)

  1. 数据模型packages/core/src/llm-connections.ts):连接模型条目新增可选字段,复用现有 ThinkingOptions 类型:
    thinkingOptions?: ThinkingOptions; // { efforts?: ['low','high','max'], toggle?: true }
    向后兼容,未声明时行为与现在一致。
  2. 查询packages/core/src/model-thinking.ts):新增带 connection 的变体,目录 miss 时回退到连接声明:
    export function thinkingVariantsForConnection(connection, modelId) {
      if (connection.providerType === 'openai-compatible') {
        const m = connection.models?.find((x) => x.id === modelId);
        if (m?.thinkingOptions) return deriveThinkingChoices(m.thinkingOptions);
      }
      return thinkingVariantsForModel(connection.providerType, modelId);
    }
  3. 校验apps/desktop/src/main/sessions-ipc-main.ts):normalizeSupportedSessionThinkingLevel 改用新函数(该处已有 connection 对象)。
  4. UI
    • apps/desktop/src/renderer/use-shell-chat-model.ts(L123 / L139):thinkingVariantsForModel(providerType, model) → 换成带 connection 的版本;
    • 连接设置页模型管理:新增"思考级别"编辑(启用开关 + 档位多选);subagent 设置页同步换函数。
  5. 测试model-thinking.test.ts 与 sessions-ipc 测试各补一个 openai-compatible 声明 case。

实现时需注意的坑

  1. off 档不能给 openai-compatible:ai-sdk openai-compatible 只映射 reasoning_effort,无 thinking: {type: 'disabled'} 通道;DeepSeek 的关闭思考依赖 thinking: {type: 'disabled'},而 reasoning_effort: 'none' 不在其取值表(low/high/max)。所以该场景档位只声明 low/high/max
  2. xhigh 会被服务端映射:DeepSeek 官方映射表 xhigh → high,声明档位时建议直接给 low/high/max,避免暴露无效档位。
  3. 透传需用户自测:部分中转站会吞掉未知参数或报错,UI 或文档中应提示用户先用 curl 验证 reasoning_effort 是否透传。
  4. 不建议启发式模型名匹配:保持保守策略,只在用户显式声明后启用,不要自动猜。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions