minimax 的 enable_thinking 是空声明:设 false 完全不生效,实际开关是 reasoning_effort #5

Closed
opened 2026-08-02 11:02:49 +08:00 by iomgaa · 1 comment
Owner

问题

providers.py 里 minimax 的 profile 是这样的:

"minimax": ProviderProfile(
    name="minimax",
    thinking_on={},
    thinking_off={},
    strip_think_tags=False,
),

两个都是空字典,于是 transports/openai_compat.py 里的 payload.update(profile.thinking_off)
是个空操作。也就是说 SourceConfig.enable_thinking=False.env
{SCOPE}__MINIMAX__1__ENABLE_THINKING=false)对 MiniMax 源完全不产生任何效果
而配置方会以为自己关掉了推理。

这比"不提供这个开关"更危险:不提供的话调用方会去找别的办法,提供了但静默失效,
调用方就带着一个错误的前提往下走了。ProviderProfile 的模块 docstring 写的是
「消灭 "qwen" in provider 式字符串猜测……每个 provider 显式声明 thinking 参数注入
形态」,而这里的"显式声明"实际是一份空声明。

实测:MiniMax 的开关是 reasoning_effort

经中转网关(OpenAI 兼容端点)对 MiniMax-M3 实测,同一个问题、temperature=0
max_tokens=800,只改 reasoning_effort

reasoning_effort completion_tokens
none 2
minimal 120
low 91
medium 116
high 800(撞上限)

none 与不传的默认行为一致(都是 2)。而 thinking={"type":"enabled"}
enable_thinking=truethinking={"type":"disabled"} 这三种写法对输出长度没有任何
影响
,说明 MiniMax 侧不认这些参数。

MiniMax-M2.7reasoning_effort 同样有效(默认 248 tokens → none 后 131)。

建议

把 minimax 的 profile 补成实际生效的映射:

"minimax": ProviderProfile(
    name="minimax",
    thinking_on={"reasoning_effort": "high"},   # 取值待定,见下
    thinking_off={"reasoning_effort": "none"},
    strip_think_tags=False,
),

thinking_on 该映射到哪一档需要斟酌——enable_thinking=True 是个布尔,而
reasoning_effort 有五档,硬映射到某一档会丢掉信息。两个方向:

一是保持布尔语义,on 映射到供应商默认档(也就是不注入),off 映射到 none
好处是"关"这个操作精确,"开"则等同于不干预。

二是承认这个 provider 的推理是多档的,让调用方通过 extra_body / overlay 自己传
reasoning_effort,而在 profile 或 docstring 里写明 enable_thinking 对 minimax
只支持"关"。

我这边(dissect)暂时走的是第二条路:用 extra_body={"reasoning_effort": "none"}
但无论选哪条,都需要修掉"设了 false 却什么也没做"这个静默失效。

顺带

同样的检查值得对 qwen / deepseek 做一遍——它们的注入片段出处注释指向的是别的项目的
历史代码(VT llm.py / CHS invokers.py),是否仍与供应商现状一致我没有验证。

## 问题 `providers.py` 里 minimax 的 profile 是这样的: ```python "minimax": ProviderProfile( name="minimax", thinking_on={}, thinking_off={}, strip_think_tags=False, ), ``` 两个都是空字典,于是 `transports/openai_compat.py` 里的 `payload.update(profile.thinking_off)` 是个空操作。也就是说 `SourceConfig.enable_thinking=False`(`.env` 写 `{SCOPE}__MINIMAX__1__ENABLE_THINKING=false`)对 MiniMax 源**完全不产生任何效果**, 而配置方会以为自己关掉了推理。 这比"不提供这个开关"更危险:不提供的话调用方会去找别的办法,提供了但静默失效, 调用方就带着一个错误的前提往下走了。ProviderProfile 的模块 docstring 写的是 「消灭 `"qwen" in provider` 式字符串猜测……每个 provider 显式声明 thinking 参数注入 形态」,而这里的"显式声明"实际是一份空声明。 ## 实测:MiniMax 的开关是 `reasoning_effort` 经中转网关(OpenAI 兼容端点)对 `MiniMax-M3` 实测,同一个问题、`temperature=0`、 `max_tokens=800`,只改 `reasoning_effort`: | reasoning_effort | completion_tokens | |---|---| | none | 2 | | minimal | 120 | | low | 91 | | medium | 116 | | high | 800(撞上限) | `none` 与不传的默认行为一致(都是 2)。而 `thinking={"type":"enabled"}`、 `enable_thinking=true`、`thinking={"type":"disabled"}` 这三种写法对输出长度**没有任何 影响**,说明 MiniMax 侧不认这些参数。 `MiniMax-M2.7` 上 `reasoning_effort` 同样有效(默认 248 tokens → `none` 后 131)。 ## 建议 把 minimax 的 profile 补成实际生效的映射: ```python "minimax": ProviderProfile( name="minimax", thinking_on={"reasoning_effort": "high"}, # 取值待定,见下 thinking_off={"reasoning_effort": "none"}, strip_think_tags=False, ), ``` `thinking_on` 该映射到哪一档需要斟酌——`enable_thinking=True` 是个布尔,而 `reasoning_effort` 有五档,硬映射到某一档会丢掉信息。两个方向: 一是保持布尔语义,`on` 映射到供应商默认档(也就是不注入),`off` 映射到 `none`。 好处是"关"这个操作精确,"开"则等同于不干预。 二是承认这个 provider 的推理是多档的,让调用方通过 `extra_body` / `overlay` 自己传 `reasoning_effort`,而在 profile 或 docstring 里写明 `enable_thinking` 对 minimax 只支持"关"。 我这边(dissect)暂时走的是第二条路:用 `extra_body={"reasoning_effort": "none"}`。 但无论选哪条,都需要修掉"设了 false 却什么也没做"这个静默失效。 ## 顺带 同样的检查值得对 qwen / deepseek 做一遍——它们的注入片段出处注释指向的是别的项目的 历史代码(VT llm.py / CHS invokers.py),是否仍与供应商现状一致我没有验证。
Author
Owner

已在 1.0.6 落地,关闭。

  • 82f4ec4 把推理开关建模为「形态(provider 级) + 能力(model 级)」两层:ProviderProfile 的 thinking 两档类型放宽为 Mapping | None,三值语义分开——{...} 已知注入片段 / {} 已知无需注入 / None 未知;空字典同时承载后两种含义正是本 bug 的根因。
  • MiniMax 按本 issue 的实测结论改为注入 reasoning_effortFalsenoneTruemedium(五档旋钮映射到布尔开关是库做的选择,精确控制走 extra_body)。
  • 另外两条随之而来的行为变更:MiniMax-M2.7 / M2.5 推理关不掉(模型固有属性,外部注册表独立佐证),配 ENABLE_THINKING=false 在装配期报错而不是装出一个骗人的 client;provider=openai 段名配任何非 None 的 ENABLE_THINKING 同样报错,因为该段名实践中被复用为任意 OpenAI 兼容厂商的兜底。
  • enable_thinking 已进缓存指纹(它现在真的改变请求体);配了该项的 scope 有一次性冷启动,未配的 scope 指纹逐字不变。
  • 48805cb 修独立验证发现,4c13507 是对真实 API 的验证测试。详见 CHANGELOG 1.0.6。
已在 1.0.6 落地,关闭。 - `82f4ec4` 把推理开关建模为「形态(provider 级) + 能力(model 级)」两层:`ProviderProfile` 的 thinking 两档类型放宽为 `Mapping | None`,三值语义分开——`{...}` 已知注入片段 / `{}` 已知无需注入 / `None` 未知;空字典同时承载后两种含义正是本 bug 的根因。 - MiniMax 按本 issue 的实测结论改为注入 `reasoning_effort`:`False` → `none`,`True` → `medium`(五档旋钮映射到布尔开关是库做的选择,精确控制走 `extra_body`)。 - 另外两条随之而来的行为变更:`MiniMax-M2.7` / `M2.5` 推理关不掉(模型固有属性,外部注册表独立佐证),配 `ENABLE_THINKING=false` 在装配期报错而不是装出一个骗人的 client;`provider=openai` 段名配任何非 None 的 `ENABLE_THINKING` 同样报错,因为该段名实践中被复用为任意 OpenAI 兼容厂商的兜底。 - `enable_thinking` 已进缓存指纹(它现在真的改变请求体);配了该项的 scope 有一次性冷启动,未配的 scope 指纹逐字不变。 - `48805cb` 修独立验证发现,`4c13507` 是对真实 API 的验证测试。详见 CHANGELOG 1.0.6。
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: iomgaa/PolyGateway#5