--- type: finding node_id: finding:2026-08-25-thinking-observability-regression title: "issue #16/#17 实测: M3 推理正常,失效的是推理的可观测信号" date: 2026-08-25 --- # issue #16/#17 实测:M3 推理正常,失效的是推理的**可观测信号** > 类型:finding|日期:2026-08-25|网关 `newapi.iomgaa.online` > 本文推翻 issue #16/#17 的原始诊断("模型不再推理"),是 `designs/2026-08-25-thinking-observability-design.md` 的事实基础。 ## 1. 为什么要重测 issue #16/#17 判定 MiniMax-M3 的开启推理"静默失效:模型没有推理",依据是 `tests/e2e/test_thinking_live.py` 的 L2/L3b/L4/L5 四条全红,四条的共同判据是 `reasoning_tokens > 0`。issue 自己留了一个未区分的岔路:网关侧模型行为变了,还是库的注入失效了。区分方法写得很清楚——抓一次真实请求体与原始响应。本文就是那次抓取。 ## 2. 方法 两层探针,都不走 slow 套件: 其一**绕开库**,用裸 `httpx` 直接 POST `/chat/completions`,矩阵化七种参数形态 × 流式/非流式,记录完整 `usage` 与 `message` 的键集合。绕开库是必要的——要证的命题之一正是"库有没有把参数弄丢",用库测这一条是循环论证。 其二**用库本身**跑 `GatewayClient.chat`,记录 `LLMResponse` 的 `reasoning_tokens` 与 `thinking` 两个字段。两层对照才能定位缺口落在哪一层。 对照组取 `qwen3.7-plus` 与 `deepseek-v4-pro`——同一网关、同一 key,用来区分"MiniMax 这一路变了"与"网关全局变了"。 ## 3. 原始观测 ### 3.1 MiniMax-M3,裸 httpx,非流式 | 变体 | prompt | completion | `completion_tokens_details` | `reasoning_content` | |---|---|---|---|---| | 不注入(基线) | 194 | 3 | **整个容器缺失** | 无 | | `reasoning_effort=medium` | **216** | **48** | 整个容器缺失 | 无 | | `reasoning_effort=high` | **216** | **65** | 整个容器缺失 | 无 | | `reasoning_effort=none` | 194 | 3 | 整个容器缺失 | 无 | | `thinking={"type":"enabled"}` | 194 | 3 | 整个容器缺失 | 无 | | `enable_thinking=true` | 194 | 3 | 整个容器缺失 | 无 | | 非法值 `definitely-not-a-real-level` | 207 | 87 | 整个容器缺失 | 无 | ### 3.2 MiniMax-M3,裸 httpx,流式 | 变体 | delta 的键集合 | `reasoning_content` 累计 | usage | |---|---|---|---| | 不注入 | `content`,`role` | 0 字符 | prompt 194 / completion 3,无 ctd | | `reasoning_effort=medium` | `content`,**`reasoning_content`**,`role` | **124 字符,完整推理过程** | prompt 216 / completion 60,无 ctd | | `reasoning_effort=none` | `content`,`role` | 0 字符 | prompt 194 / completion 3,无 ctd | 流式 medium 档抓到的推理正文(前 120 字符):`We need answer Chinese, only two digits. Chickens x rabbits y. x+y=35,2x+4y=94 => x+y*? 2*35+2y=94 y=12, x=23. Output 23` ### 3.3 对照组(流式) | 模型 | 变体 | `reasoning_content` | `completion_tokens_details.reasoning_tokens` | |---|---|---|---| | deepseek-v4-pro | 不注入 | 135 字符 | **88** | | deepseek-v4-pro | `effort=medium` | 134 字符 | **89** | | deepseek-v4-pro | `effort=none` | 0 | 容器缺失 | | qwen3.7-plus | 不注入 | 350 字符 | **158** | | qwen3.7-plus | `effort=medium` | 606 字符 | **229** | | qwen3.7-plus | `effort=none` | 0 | 容器缺失 | | qwen3.7-plus | 非法值 | — | **HTTP 400** | ### 3.4 用库跑(`LLMResponse` 字段) | 场景 | `reasoning_tokens` | `thinking` 字符数 | completion | |---|---|---|---| | M3 开启,流式 | None | **185** | 69 | | M3 开启,非流式 | None | **0** | 53 | | M3 关闭,流式/非流式 | None | 0 | 3 | | M3 不干预 | None | 0 | 3 | | qwen 开启,流式 | **205** | 484 | 213 | | qwen 关闭,流式 | None | 0 | 5 | ## 4. 五条结论 **① M3 的推理完全正常,issue 的诊断是错的。** 流式 medium 档抓到 124 字符完整推理过程;`prompt_tokens` 194→216(供应商注入推理指令)、`completion_tokens` 3→60(推理段被计费)。三个独立信号一致。 **② 真正变的是 MiniMax 这一路不再返回 `usage.completion_tokens_details`。** 而 qwen 与 deepseek 在同一网关同一 key 上照常返回。所以这不是网关全局改了 usage 处理,是 MiniMax 这一路上游的 usage 形态变了。`reasoning_tokens` 恒 NULL 由此而来。 **③ 库自己已经握有决定性证据,却没有用。** `LLMResponse.thinking` 在 M3 开启档流式路径下是 185 字符的实打实推理正文。e2e 的 `_reasoning_on` 只看 `reasoning_tokens` 与 `completion_tokens` 长度,从不看 `thinking`——四条红是判据的盲区,不是功能的失效。 **④ M3 非流式路径下推理内容整体丢失,且下游在付费。** `completion_tokens` 53 vs 关闭档 3,说明推理段确实产生并计费;而 `message` 的键集合只有 `content`/`role`,`reasoning_content` 不存在。下游用非流式调 M3 开推理 = 付钱买看不见的东西,且当前库不告诉它。这不是库能修的(上游不返回),但库必须让它可见。 **⑤ 三家供应商在"未推理"时都是整个 `completion_tokens_details` 缺失,无人上报 `0`。** 与 2026-08-02 findings §4c 的记录一致。推论:**"容器在不在"不能当作"有没有推理"的判据**——它与真实信号高度混淆,拿它做裁定等于把噪声当信号。 ## 5. 顺带纠正的两处既有认识 **`enable_thinking` / `thinking:{type:enabled}` 对 M3 无效这一条仍然成立**(prompt 恒 194 = 基线),只有 `reasoning_effort` 是真开关。`providers.py` 的 minimax profile 用的正是 `reasoning_effort`,选型至今正确。 **L3b 的"非法值反证"手法只对不校验值的 provider 成立。** minimax 对非法 `reasoning_effort` 返回 200 且照常推理(prompt 207,介于基线 194 与 medium 216 之间,说明走了第三条模板路径);qwen 对同样的非法值直接 **HTTP 400**。这条手法写进测试时只在 minimax 上验过,它不可移植——若哪天把 L3b 套到别的 provider 上会得到假红。 ## 6. `can_disable` 复测 M3 的 `ThinkingCapability(can_disable=True)` 的 evidence 停在 2026-08-02。2026-08-25 复测:`reasoning_effort=none` → prompt 194(= 基线)、completion 3、无 `reasoning_content`。**声明依然成立**,只需刷新 evidence 日期并补记本文新发现的两条限制(非流式不可观测、仅 `reasoning_effort` 有效)。