推理努力度是怎么训出来的
Codex 里选 GPT-5.6 Sol 的时候,Effort 菜单有六档:Light / Medium / High / Extra High / Max / Ultra。同一份权重,换一个档位,Artificial Analysis Coding Agent Index 从 59 分爬到 80 分,API 花费从几百美元涨到三千美元。Sebastian Raschka 在 7 月 18 日的 Controlling Reasoning Effort in LLMs1 里把这个旋钮拆开讲了一遍,我照着他的线索把六家旗舰开源模型的技术报告翻了一遍,补上了博客里省掉的公式和实现细节。
上图右侧是 Codex 的 Effort 菜单,左侧是同一个 GPT-5.6 Sol 在不同档位下的成绩–成本曲线。注意曲线上的标签(None / Low / Medium / High / XHigh / Max)和菜单里的文案(Light…Ultra)并不是一套词,说明面向用户的档位名和 API 层的 reasoning_effort 取值是两层映射。
这件事值得单独看,是因为它处在一个尴尬的位置:推理时它看起来只是一句 system prompt,几乎不像技术;但把这句话加到任意一个模型上并不会生效,它背后必须有一整套 post-training 配合。本文尝试回答几个问题:
- 一个 effort 档位在推理时到底改变了什么,为什么"只是 prompt"这个说法既对又不对
- 训练侧有哪几种把 effort 装进权重的办法,它们的奖励函数长什么样
- 硬性 token 预算(外部截断)为什么是和 effort 档位不同的另一件事,不专门训练会坏在哪
- 六家旗舰开源模型的配方差在哪,哪些只是同一件事的不同包装
Notation
| 符号表示 | 数学含义 |
|---|---|
| $e$ | 请求的 effort 等级,可以是序数标签(low/medium/high)或连续值 |
| $R_{\text{task}}$ | 任务奖励,RLVR 里通常是 0/1 的可验证正确性 |
| $N_{\text{tokens}}$ | 一次 rollout 生成的 token 数 |
| $c(e)$ | 每 token 的成本系数,随 $e$ 变化(Raschka 原文记作 $\lambda(e)$) |
| $B(x)$ | 问题 $x$ 的 token 预算 |
| $\rho$ | 估计 $B(x)$ 时取的分位数 |
| $\lambda$ | Kimi Toggle 里的准确率阈值 |
| $K$ | 每个问题的 rollout 数 |
| $t,m$ | RL 迭代步 / Toggle 的相位切换周期 |
先把两个轴分开
同一个菜单里其实混着两种完全不同的 scaling。
橙色箭头是换模型(Luna → Terra → Sol),蓝色曲线上移动是换 effort。前者是训练侧的事——这三个是不同规模、不同训练算力产出的不同权重;后者是推理侧的事——权重不变,只是允许模型多花或少花 token。
Raschka 在这里补了一句我觉得挺重要的澄清:在菜单里选一个更大的模型,此刻并不是"训练 scaling",训练早就发生完了,菜单只是在几个不同训练规模的产物之间挑一个。
更有意思的是三条曲线是重叠的。小模型开高 effort 可以打到大模型开低 effort 的分数。这意味着"用哪个模型"和"给多少 effort"不是可以独立决策的两个参数,得放在一起看成本–精度–延迟的三维权衡。
think token 是装饰,不是能力
先把一个容易误解的东西挑出来。effort 旋钮调节的是 <think> 和 </think> 之间那段东西的长度,但这对标签本身没有魔力。
图里 <think> 段落中间那句 “Wait, that can’t be right. I only used the ticket price, not the total” 就是所谓 aha moment——模型自己发现算错了并回头改。这个行为是 RLVR 训出来的,不是标签带来的。DeepSeek-R1 的做法是在奖励里加一项格式奖励:
$R_{\text{accuracy}}$ 来自可验证信号(数学用符号计算器校验,代码用编译器和单测),$R_{\text{format}}$ 是一条规则检查,鼓励模型把中间推理放进 <think>...</think>。换成任何别的分隔符效果一样。标签存在的意义是让训练管线和前端能把中间推理从最终答案里切出来、并可选地对用户隐藏——ChatGPT 和 Codex 就是这么干的。
顺带一个和本文主线相关的细节:R1 的中间推理链没有参与训练。奖励只看最终答案和格式。作者试过把中间信息用起来,报告里说没帮助,最后放弃了。所以第一代推理模型对"推理链应该多长"这件事其实完全没有监督信号——它只是被正确率间接地推着变长。这正是后来需要专门做 effort 控制的起点。
左边是常规 LLM 的直接回答,右边是推理模型:先摊开中间步骤,中途自我纠正、回退,最后给结论。问题在于这个行为是无条件的——R1 对"1+1 等于几"也会长篇大论,而且没有内建的关闭开关。
推理侧:effort 确实就是一句 system prompt
OpenAI 没公开 GPT-5.6 的实现,但去年开源的 gpt-oss 把这层露出来了。它的 model card 写得很直接:三个 effort 等级是训出来的,推理时通过在 system prompt 里插入 "Reasoning: low" 这样的关键词来选择,等级越高平均 CoT 越长2。我把 openai/gpt-oss-20b 的 chat template 拉下来看,相关逻辑只有三行:
|
|
这段在渲染 system 消息时执行,位置紧跟在 model_identity、Knowledge cutoff 和 Current date 之后。也就是说用户在界面上选的 High,最终变成 system 消息里一行纯文本 Reasoning: high,之后送进去的是同一份权重。
效果是单调的:
横轴是 CoT + 答案的总 token 数(log 尺度),纵轴是准确率。gpt-oss-120b 在 AIME 2025 上从 low 的约 73% 到 medium 的约 91.5% 再到 high 的约 98%,token 从 1k 量级涨到 14k 量级;GPQA Diamond 上 20b 从 low 58% 到 high 74%,token 从不到 2k 涨到 32k。两件事同时成立:effort 标签几乎线性地控制了输出长度,而长度又和精度正相关。所以 effort 旋钮本质上是把 inference scaling 的开关交给了用户。
各家在 API 层的形状略有不同,但都是同一件事的不同包装:
| 模型 | 推理侧控制点 | 形式 |
|---|---|---|
| gpt-oss | system 消息 | Reasoning: low/medium/high |
| DeepSeek V4 | 请求参数 | reasoning_effort: high/max + thinking: {type: enabled/disabled} |
| Nemotron 3 Ultra | chat template kwargs | enable_thinking、medium_effort、reasoning_budget |
| Qwen3 | chat template / 用户消息 | enable_thinking=False、/think、/no_think |
| GLM-5 | 请求参数 / chat template | thinking: {type: disabled}、clear_thinking |
| Inkling | system 消息 | 连续值,如 Thinking effort level: 0.8 |
DeepSeek 的 API 文档里有个细节挺能说明问题:为了兼容 OpenAI 的接口约定,low 和 medium 会被映射到 high,xhigh 被映射到 max。
也就是说 V4 对外看起来支持五档 reasoning_effort,实际上只训了两个思考档(Think High / Think Max)加一个不思考档。这提醒我们:API 暴露的档位数不等于模型真实学到的模式数,中间那层映射是产品决定而非模型能力。
训练侧:三条把 effort 装进权重的路
推理侧简单,代价是训练侧必须先把这个条件教进去。翻完六份报告,能归成三种机制,而且它们是可以叠加的。
路线一:混合 SFT,Qwen3 的 Thinking Mode Fusion
最简单的版本是二值开关。Qwen33 的 post-training 有四个阶段:long-CoT SFT → Reasoning RL → Thinking Mode Fusion → General RL。
关键是第三阶段。在已经训好的推理模型上继续做 SFT,数据里同时放两种样本:
/think:<think>{reasoning}</think>{answer}/no_think:<think></think>{answer}
thinking 是默认行为,所以 /think 可以省略;报告里还提到会往多轮对话里随机插入多个 /think 和 /no_think,逼模型按最近一次标记走。之后的 General RL 阶段再强化这个模式和格式的遵循。
这里有个软硬开关的区分值得说清。/think 和 /no_think 是写在用户消息里的软开关——模型可以不听。而 enable_thinking=False 是硬开关,它根本不往 query 里加 /no_think,而是直接在 assistant 回复开头把空的 <think></think> 填好。我把 Qwen3-8B 的 chat template 抠出来,就是最后这几行:
|
|
模型看到的是"思考块已经开了又关了"的 token 序列,于是只能直接往下写答案。这也解释了为什么前端界面上看不到那对空标签——它属于输入 prompt,不是生成内容。
左边 thinking=False 直接答"1 + 1 equals 2",右边 thinking=True 的 Qwen3 0.6B 对同一个问题开始纠结"用户是不是在考我什么陷阱"。这张图顺便说明了为什么需要这个开关。
路线二:effort-conditioned RL,让 token 成本随 effort 变
二值开关往多档扩展,最直接的办法是在 RL 阶段就把 effort 标签喂进 prompt,同时让长度惩罚随标签变化。
图里画的是两种可能的实现叠在一起:RLVR 阶段按 system prompt 里的 Reasoning: low/high 施加不同强度的长度惩罚;之后再补一轮 SFT,让同一个问题配上长短不同的目标回复。Raschka 明确标注这是推测的实现,不是 OpenAI 确认的管线。
Inkling 是目前公开材料里最接近这个描述的例子。它的做法在 RL 阶段:
We specified the model’s effort level on different samples by changing the system message and adjusting the per-token cost. This caused the model to use a different amount of tokens in different rollouts and learn the ability to control thinking effort.4
奖励的形状大致是
$$R(e) = R_{\text{task}} - c(e)\, N_{\text{tokens}}$$$R_{\text{task}}$ 是原来的任务奖励,$N_{\text{tokens}}$ 是这次 rollout 的长度,$c(e)$ 是随请求 effort 变化的每 token 成本。低 effort 给大的 $c(e)$,多写一个 token 就多扣一点分,模型学会缩短;高 effort 给小的 $c(e)$,token 几乎免费,模型敢展开。这个减法项就是把"少写"变成一个可优化目标的全部内容——注意它是线性惩罚而不是硬截断,所以模型仍然可以在必要时选择超支,只要任务奖励的增益盖得住成本。
Inkling 和 gpt-oss / GPT-5.6 的区别在于 effort 是 0 到 1 的连续标量而不是序数标签,推理时给一句 Thinking effort level: 0.8 即可。
蓝线是 Inkling 把 effort 从 0.2 扫到 0.99,横轴是平均生成 token 数。三个 benchmark 上都是同一个形状:前段陡,后段平。Terminal Bench 2.1 上从 0.2 到大约中段,token 从不到 5k 涨到 25k,分数从 36% 到 60%;再往上加到 50k token,只多了 1 个点。官方博客给的对照是它在 Terminal Bench 上用大约三分之一的 token 追上 Nemotron 3 Ultra。
顺带一个 Inkling 报告里的观察:RL 过程中还出现了没被奖励要求的行为——CoT 自发变简洁,丢掉语法性的冗余词但仍可读,最终回复不受影响。作者说这纯粹是效率压力驱动的。这一点和 Inkling 走的是超过 3000 万 rollout 的大规模异步 RL 有关(RL Scaling: 异步采样与流水线并行优化),也和它挂在 Tinker 上做微调这条产品线一致(Tinker: 后训练 MaaS)。
路线三:分模式训专家,再蒸馏成一个 checkpoint
DeepSeek V4 走的是第三条:不在一个模型里同时优化多个 effort,而是先训出多个专家,再合并。
三个模式是 Non-think / Think High / Think Max。报告里写得很直接:
For each mode, we apply distinct length penalties and context windows during RL training, which results in varying output token lengths for reasoning.5
也就是每个模式有自己的 context window 和长度惩罚,Think Max 拿到更长的窗口和更小的惩罚。除此之外 Think Max 还会在 system prompt 开头注入一段指令,报告的 Table 3 给了全文:
Reasoning Effort: Absolute maximum with no shortcuts permitted. You MUST be very thorough in your thinking and comprehensively decompose the problem to resolve the root cause, rigorously stress-testing your logic against all potential paths, edge cases, and adversarial scenarios. Explicitly write out your entire deliberation process, documenting every intermediate step, considered alternative, and rejected hypothesis to ensure absolutely no assumption is left unchecked.
单看这段话像是纯 prompt engineering,但它之所以有效,是因为 RL 阶段就是在这个 system prompt 下用更松的长度惩罚训出来的。把同样一段话贴到任意别的模型上不会有同样效果——这是整篇文章里最该记住的一点:effort 的 prompt 是在选择一个 post-training 期间被塑造出来的行为,而不是在下达一条指令。
最后这些模式专家和十多个领域专家一起,通过 on-policy distillation 合并进一个 checkpoint(On Policy Distill),目标是加权 reverse KL:
$$\mathcal{L}_{\text{OPD}}(\theta) = \sum_{i} w_i \cdot D_{\text{KL}}\!\left(\pi_\theta \,\|\, \pi_{E_i}\right)$$$w_i$ 是各专家的权重,reverse KL 要求从 student 采样轨迹以保持 on-policy。V4 相比多数实现的不同是做全词表 logit 蒸馏而不是只算 student 采样到的那个 token,代价靠缓存 teacher 的 hidden state、临时过 teacher 的预测头重建 logits 来规避显存爆炸。
不过这里有个公开材料的缺口:报告分别描述了三个 effort 模式和十多个领域专家,但没说清这两组怎么对应——三个 effort 专家是不是每个领域各有一份,还是先合 effort 再合领域,从报告里重建不出来。
硬预算是另一件事
到这为止讲的都是"学到的模式":模型自己决定写多长。但还有一类控制是从外面掐断的——到了 N 个 token 就强制结束思考。这两者容易混,但机制完全不同,而且硬预算需要单独训练。
Qwen3:截断行为是涌现的
Qwen3 支持 thinking budget,做法是思考长度到阈值时手动停下,插入一句停止指令,然后让模型基于已有的部分推理写答案。报告给了这句话的原文:
Considering the limited time by the user, I have to give the solution based on the thinking directly now.
值得注意的是报告明说这个能力没有被显式训练,它是 Thinking Mode Fusion 的副产品:模型既见过"有完整推理"也见过"完全没推理"的样本,于是自然获得了处理中间态——基于不完整推理作答——的能力。
Nemotron 3 Ultra:把截断样本塞进 SFT
NVIDIA 没有赌它涌现,而是直接为此造数据。Nemotron 3 Ultra6 训了三个模式:reasoning-off、regular、medium-effort。
SFT 里有两块专门服务于效率与控制的数据:
- 用 GPT-OSS-120B 的 medium-effort 模式生成的数学、STEM、指令遵循样本,用来初始化 Ultra 自己的 medium-effort 模式;
- 把正常推理链截断到随机预算、但保留原始答案的样本,且截断样本里的 token 从 SFT loss 里 mask 掉。
第二块是关键。模型因此见过大量"推理被外部切断,现在必须收尾"的情形,于是在真的被掐断时不至于崩掉。第一块则是一个有点讽刺的事实:NVIDIA 的低 effort 模式是拿 OpenAI 开源模型的低 effort 模式蒸出来的。
之后 medium-effort 继续在 RLVR 里优化,约 2.5% 的 RL prompt 用 medium-effort 设置,覆盖数学、STEM、代码,并对这部分做基于长度的奖励调整。报告给了代价的量化,这个数字博客里没有:medium-effort 平均比 regular 模式少用约 2.5 倍 token,代价是精度下降约 7%。
推理时三个模式都走 chat template:
regular 是默认(enable_thinking=True,开头补一个 <think>);medium-effort 是 enable_thinking=True 加 medium_effort=True,后者会往最近一条用户消息后面追加 {reasoning effort: efficient};reasoning-off 是 enable_thinking=False,预填空的 <think></think>,和 Qwen3 一个路子。
学到的模式还能再叠一层硬预算 reasoning_budget。NVIDIA 的 model card 描述了它的实现细节:到了预算之后模型会试着在下一个换行处收尾;如果 500 token 内没有换行,就在 reasoning_budget + 500 处强行截断。这两层控制是正交的——模式决定模型怎么花预算,预算决定还能花多久。
Kimi K2.5:固定预算会把模型练坏
Kimi 的报告点出了硬预算训练的一个真实失败模式,我认为这是这波材料里最有价值的一条负面结果:
we also observe a length-overfitting phenomenon: models trained under rigid budget constraints often fail to generalize to higher compute scales. Consequently, they cannot effectively leverage additional inference-time tokens to solve complex problems, instead defaulting to truncated reasoning patterns.7
在固定预算下训出来的模型确实变短变快了,但它丢掉了从额外推理算力中获益的能力——给它更多 token 也不会用,只会退化成截断式的推理。这是把 token 效率当单目标优化的直接后果。
他们的解法叫 Toggle,每 $m$ 步在两个相位之间切换。报告给的奖励函数是:
$$\tilde{r}(x,y)=\begin{cases} r(x,y)\cdot\mathbb{I}\left\{\frac{1}{K}\sum_{i=1}^{K}r(x,y_{i})<\lambda\ \ \mathrm{or}\ \ |y|\leq \mathrm{budget}(x)\right\} & \text{if } \lfloor t/m\rfloor \bmod 2=0\quad(\text{Phase 0})\\[4pt] r(x,y) & \text{if } \lfloor t/m\rfloor \bmod 2=1\quad(\text{Phase 1}) \end{cases}$$逐项看这个式子在做什么:
- Phase 1 就是原始奖励 $r(x,y)$,最大生成长度放开,模型可以照常靠长推理拿分。这一相位的存在就是为了避免上面那个 length-overfitting。
- Phase 0 在原奖励上乘一个 0/1 指示函数,等价于"不满足条件就把奖励清零"。条件是个或:要么 $\frac{1}{K}\sum_i r(x,y_i)<\lambda$,要么 $|y|\leq \mathrm{budget}(x)$。
- 第一个分支是保护条款。$\frac{1}{K}\sum_i r(x,y_i)$ 是这个问题在 $K$ 次 rollout 上的平均正确率,低于阈值 $\lambda$ 说明模型还没把这题做稳——此时指示函数恒为 1,长度约束不生效。这是为了避免"在模型还不会做的时候就先逼它写短",那样只会两头落空。
- 第二个分支才是真正的预算约束:只有在模型已经能稳定做对的题上,超预算的正确答案奖励才会被清零。
- $\lambda$ 和 $m$ 是超参,$m$ 控制两个相位切换的频率。
预算本身按正确 rollout 的长度分位数估计:
$$\mathrm{budget}(x)=\text{Percentile}\left(\left\{|y_{j}| \;\middle|\; r(x,y_{j})=1,\ j=1,\dots,K\right\},\ \rho\right)$$只统计做对的回答的长度,取第 $\rho$ 分位。这样预算是问题自适应的:难题的预算天然大,简单题天然小,不需要人工分级。报告说这个预算在训练开始时估一次,之后固定不变。
效果是在 K2 Thinking 上输出 token 减少约 25~30%,性能几乎不变。
左边是性能雷达图,7 个 benchmark 里 5 个略升 2 个略降,Overall +0.3%;右边是 token 用量,7 个全降 0 个升,AIME2025 少 6179 token,HMMT25_Nov 少 8127,Overall 少 4791。报告还提到冗余模式(重复验证、机械计算)显著减少,而且只在数学和代码上做 RL,token 缩减能迁移到 GPQA 和 MMLU-Pro。
需要说清 Toggle 的定位:它完全发生在 RL 训练期,两个相位更新的是同一个策略,最终 checkpoint 里没有"budgeted vs unconstrained"这个选择器。所以 Toggle 不是一个 effort 档位,而是一次让策略整体变省的训练技巧。K2.5 在 vLLM / SGLang 上暴露的 thinking / instant 二选一(chat_template_kwargs={"thinking": False})是另一套东西,和 Toggle 无关。
GLM-5:把开关搬到 turn 和 tool call 的粒度
GLM-58 关心的不是档位多少,而是多轮和工具调用场景下思考应该在哪里发生。报告列了三种行为:
- Interleaved thinking:每次回复和每次工具调用之前都插一段推理。默认开启,GLM-5 的报告明确注了这是 Claude 先做的。
- Preserved thinking:跨轮保留之前的思考块,复用已有推理而不是从头重推。同样注明 Claude Opus 4.5 之后采用。在 coding agent 场景收益是减少信息丢失、提升 KV cache 命中率——这里和 KV-Cache 基础 是同一笔账。
- Turn-level thinking:同一个会话里逐请求决定开不开思考。
推理时真正的开关是第三个。开源 chat template 里,开启思考时 assistant 回复以 <|assistant|><think> 开头,关闭时用 <|assistant|></think>——直接把思考块闭掉,生成从答案开始。和 Qwen3 预填空标签是同一个套路的变体。
这些行为在多任务 SFT 阶段随更新的 chat template 一起引入,之后经过 reasoning RL、agentic RL、general RL,最后一步用前面各阶段的 checkpoint 当 teacher 做 on-policy distillation,把顺序 RL 过程中衰减掉的能力捞回来——和 DeepSeek V4 用蒸馏做合并的动机一致。
六个模型放一起看
原文这张表汇总了六份报告里真正披露的内容。把它压成机制维度,我的读法是三个可叠加的成分:
| 成分 | 作用 | 谁在用 |
|---|---|---|
| 混合 SFT + chat template | 把"模式"这个条件教进模型,给出推理时的入口 | Qwen3(think/no_think 混合)、GLM-5(interleaved / preserved / turn-level)、Nemotron(teacher 生成的 medium-effort 数据) |
| mode-conditioned RL | 让 context window 和长度惩罚随请求的 effort 变 | DeepSeek V4(每模式独立配置)、Nemotron(2.5% prompt 做长度调整)、Inkling(连续 effort 调 per-token cost) |
| 抗截断鲁棒性 | 保证推理长度被外部改变甚至切断时答案质量不崩 | Nemotron(随机预算截断样本)、Qwen3(涌现的续写能力)、Kimi(budgeted / unconstrained 交替) |
第一个成分几乎是必需的:没有它,推理时那句 prompt 无处着落。第二个成分决定档位之间的差距有多大、有几档。第三个成分是最容易被忽略但在 agent 场景最要命的——长时间运行的 coding agent 里,剩余预算是动态变化的,模型必须能在任意点被叫停还给出可用答案。
哪种最好这个问题我认为现阶段答不了,而且原文的谨慎是对的:六个模型的 base checkpoint、训练数据、post-training 算力、评测集、服务目标全都不同,报告里也缺足够细节做受控对比。更可能的情况是不存在通解——交互式助手要的(低延迟、宁短勿长)和长跑 coding agent 要的(宁可多想、能被随时打断)本来就是两套偏好。
学术界怎么做这件事
原文的第 6 节说,本来想讲相关论文,但读下来觉得多数只是 proof-of-concept,于是改成讲旗舰模型的配方。这个判断我理解,但顺着这条线翻下去,有几篇是真的补上了工业报告里被省掉的东西——尤其是为什么工业界选序数标签而不是数字预算这个问题,工业报告一句都没解释,学术界有实验。
s1:三种控制方式的对照实验
s19 现在最常被引用的是 budget forcing(超预算就补上结束思考的分隔符强制退出;想让它继续想就压制结束符并追加一个 "Wait")。但对本文更有价值的是它定义的三个指标和那张消融表。给定一组评测点 $\mathcal{A}$ 和精度–思考 token 的分段线性曲线 $f$:
Control 衡量"你要的预算能不能被守住",Scaling 衡量"多给算力能不能换来分数",两者是独立的。AIME24 上各方法的表现:
| 方法 | Control | Scaling | Performance |
|---|---|---|---|
| Budget forcing | 100% | 15 | 56.7 |
| Token-conditional(prompt 里写 token 上限) | 40% | −24 | 40.0 |
| Step-conditional(prompt 里写步数) | 60% | 3 | — |
| Class-conditional(“想久一点/短一点”) | 50% | 25 | 36.7 |
| Rejection sampling | 100% | −35 | — |
这张表基本解释了工业界的选择。token-conditional 的 Scaling 是负的,原因论文写得很直白:模型数不清自己写了多少 token,“even when trained to do so”。step-conditional 会被套利——模型总 token 数几乎不随步数目标变化,只是在"少步长句"和"多步短句"之间换。而 class-conditional,也就是 low/medium/high 这一族,Scaling 斜率是所有方法里最好的 25,但 Control 只有 50%。
翻译成实践语言:告诉模型"多想想"能可靠地提高算力和精度,但你钉不住具体预算。这正是 Reasoning: low/medium/high 继承下来的性质,也是为什么 OpenAI 的文档把 effort 描述成一个自适应的区间而不是固定 token 数,以及为什么需要硬预算时所有引擎都走外部截断而不是靠 prompt。
ThinkDial:把 gpt-oss 的三档复现出来
我原本以为没有论文正面研究序数 effort 标签,翻下来发现有:ThinkDial10 自称是"第一个开放配方端到端复现 gpt-oss 式离散模式控制"的工作,目标定得很具体——Medium 省 50% token 且掉点 <10%,Low 省 75% 且掉点 <15%。
三段式:Budget-Mode SFT → 只在 High 模式上做 RL warm-up(95 步)→ 加 budget-aware reward shaping 再训 40 步。奖励是
$$R_{i}^{(m)}=R_{\text{task}}(o_{i})+\alpha^{(m)}\cdot R_{\text{length}}(o_{i})+R_{\text{leak}}(o_{i})$$$R_{\text{length}}$ 直接沿用 Kimi k1.5 的 group-relative 长度奖励(见下),真正的旋钮是那个 mode-specific 系数:
$$\alpha^{(\text{high})}=0.0,\quad \alpha^{(\text{med})}=0.5,\quad \alpha^{(\text{low})}=1.0$$三个数就是三档。High 模式的长度压力归零,所以性能天花板不受影响;Low 拿满压力。这比我前面写的 $c(e)$ 更具体:它不是连续函数,就是一张查找表。
三个细节值得单独记:
Leak Penalty 是在防 reward hacking。 作者观察到模型会把推理从 <think> 里挤到答案段——thinking token 确实降了,但答案段变长,总 token 反而上升。压缩目标被绕过了,努力只是被重新分配。对策是检测答案段里的元认知词(“Wait”、“Let me think”、“Actually”、“Alternatively”、“However”):
这条对评测的启示很实际:只统计 thinking token 的效率评测会被骗。
机械截断不行,必须训。 他们拿"在性能峰值 checkpoint 上直接截断到目标预算再让模型总结作答"当 baseline,结果是灾难性崩溃,而学出来的压缩是平滑退化。这和 Nemotron 专门造截断样本、Qwen3 依赖 Thinking Mode Fusion 的涌现能力是同一个道理的三种应对。
顺序是承重的。 去掉 Budget-Mode SFT,三个模式在 RL 阶段会互相干扰,把 High 模式拉到比原始峰值还低;去掉 warm-up,一上长度奖励就保不住 High/Medium 的质量。也就是说必须先在 SFT 里把模式的输出分布固定住,RL 才有东西可以精修——这恰好是 Qwen3 的 Thinking Mode Fusion 和 Nemotron 的 medium-effort SFT 在做的事,只是那两份报告没解释为什么非得在 SFT 做。
Kimi k1.5:长度奖励的祖宗
ThinkDial 沿用的那个 $R_{\text{length}}$ 来自 Kimi k1.511:
$$\mathrm{len\_reward}(i)=\begin{cases} \lambda & \text{if } r(x,y_{i},y^{*})=1\\ \min(0,\lambda) & \text{if } r(x,y_{i},y^{*})=0 \end{cases}, \quad \lambda=0.5-\frac{\mathrm{len}(i)-\mathrm{min\_len}}{\mathrm{max\_len}-\mathrm{min\_len}}$$$\mathrm{min\_len}$ 和 $\mathrm{max\_len}$ 是同一个问题的 $k$ 个 rollout 里的最短和最长,所以 $\lambda$ 是组内相对的,取值落在 $[-0.5, 0.5]$:组内最短拿 +0.5,最长拿 −0.5。两处设计要讲清:
- 分母做 min-max 归一化,意味着奖励是对同一道题的兄弟样本比较,不需要知道这题"应该"多长。$\mathrm{max\_len}=\mathrm{min\_len}$ 时整组长度奖励置零。
- 答错时套一个 $\min(0,\lambda)$,短的错答案只能拿 0 拿不到奖励,长的错答案照样吃满负分。模型永远不会因为"快速猜一个"而获利——这是把长度惩罚和正确性解耦时最容易出的漏洞。
还有一条工程经验:长度惩罚要 warm-up,先做一段不带惩罚的常规 RL 再打开,从第 0 步就加会拖慢早期训练。ThinkDial 的两阶段 RL 是同一个思路,Nemotron 只让 2.5% 的 prompt 走 medium-effort 也可以理解成同一类保护。
L1:数字预算其实能训准,但 SFT 训不出来
L1/LCPO12 把目标长度写进 prompt(“Think for $n_{gold}$ tokens."),$n_{gold}$ 每条样本从区间里均匀采样,然后用 GRPO 训。两个变体:
$$r=\mathbb{I}(y=y_{gold})-\alpha\cdot\bigl|n_{gold}-n_{y}\bigr| \qquad \text{(LCPO-Exact)}$$ $$r=\mathbb{I}(y=y_{gold})\cdot\text{clip}\bigl(\alpha\cdot(n_{gold}-n_{y})+\delta,\,0,\,1\bigr) \qquad \text{(LCPO-Max)}$$$\alpha=0.0003$,$\delta=0.5$。Exact 是加法:偏离目标多少扣多少。Max 是乘法:正确性乘一个落在 $[0,1]$ 的预算达成度,$\delta=0.5$ 保证轻微超预算的正确答案仍然稳赢错误答案。
两条结论对工业配方直接有用:
加法形式会 length collapse。 论文的奖励消融里,加法变体"塌缩到极短的推理链,它们平凡地满足了长度约束但严重损害推理质量”。而且各变体的预算违规率差不多——光看违规率检测不出塌缩。这是 length collapse 在论文里的直接证据,和 Kimi 报告的 length-overfitting 是同一现象的两个侧面。
SFT 训不出长度控制。 他们试过把采样到的推理链按实际长度打标再做 SFT,结果模型"完全不遵守长度约束,不管要求多长都生成很长的输出"。在线的长度敏感奖励看起来是必需的。这条正好解释了为什么 DeepSeek V4、Nemotron、Inkling 都把 effort 放进 RL 阶段而不是只做一轮 SFT。
效果上 L1 的长度误差在域内约 3%,比 s1 测到的 token-conditional prompting 的 40% Control 好一个量级——说明数字预算不是不能学,只是不能靠 prompt 白嫖。
TALE:预算给太小,反而更贵
TALE13 也是往 prompt 里写预算,但它发现了一个反直觉现象,叫 token elasticity:预算压到某个范围以下,实际 token 消耗会回升。他们给的例子是同一个问题,预算写 50 → 实际输出 86 token,预算写 10 → 实际输出 157 token,而不写预算的 vanilla CoT 是 258。
机制是模型满足不了这个约束时干脆放弃遵守,退回长推理。所以成本–预算曲线是 U 形的,最省的点不是可行域的最小值。这条正好是 s1 那个 −24 的 Scaling 的微观解释,也是我认为序数标签在产品上更稳的第二个理由:序数标签总能被"某种程度地"满足,数字硬预算可以被整体放弃。
Elastic Reasoning:真正杀死精度的是答案被截断
Elastic Reasoning14 的核心观察很朴素但很有用:把总预算 $c$ 拆成思考预算 $t$ 和答案预算 $s$,$c=t+s$。思考花完 $t$ 就强制结束,答案段始终保有 $s$ 的配额。
结论是即使思考被硬切断,模型通常仍能写出连贯甚至正确的答案——所以紧预算下真正掉分的不是思考被截断,而是答案被截断。这个拆分本身就打赢了朴素截断和 s1 的 budget forcing。而且只在 $(t,s)=(1\text{K},1\text{K})$ 一个配置上做 GRPO 训练,就能泛化到任意未见预算,训练只要 200 步(L1-Exact 要 700 步)。
两个数字值得记:E1-Code-14B 在 Codeforces 上 1987 分、96.0 百分位,论文明确对标 o1-2024-12-17 (Low) 的 1991 / 96.1——一个学术界的 14B 模型在同一档位上追平了产品模型的低 effort 档。另外带预算约束训练还有副作用:不加任何约束时它也变简洁了,LiveCodeBench 上平均 token 从 17815 降到 11145(−37.4%)而精度还升了 0.3%。
这条对 Nemotron 的 reasoning_budget 实现是个有意思的对照:NVIDIA 的做法是到预算后找换行收尾、500 token 内没有就硬切,本质上没有为答案段预留配额。
为什么 RL 天然把输出拉长
前面所有方法都在治"太长"这个症状。Concise Reasoning via RL15 讲的是病因,而且给了证明:在终局奖励 $r\neq 0$、$\gamma=1$、GAE $\lambda<1$、值函数差有界的条件下,PPO 在 $r>0$ 时偏好更短的回复,在 $r<0$ 时偏好更长的回复。因为训练里做不出来的题占大头、持续产生负奖励,这个偏好累积成系统性的长度增长。
他们的实证锚点很干净:拿 4 道模型证明做不出来的 OlympiadBench 题,给恒定的 −0.5 终局奖励,在 20K 上下文里训——policy loss 随着回复变长而单调下降。模型一边越写越长,一边全错。
顺带一个警告:把 $\lambda$ 设成 1 不是解药,它会引入不看正确性的短偏好,并且放大噪声(噪声随回复长度线性增长)。这和 Kimi 的 $\min(0,\lambda)$ clamp、Arora & Zanette 把长度项乘在正确性上,都是在守同一条底线:长度压力必须以正确性为门。
顺着这条线还有一个容易被忽略的反向失败模式:underthinking16。腾讯的这篇把它定义为在多个推理思路之间频繁跳转而不充分探索任何一条,并发现思路切换频率与答错强相关。纯粹压长度会把模型往这个方向推。
自动选档:还没解决
原文结尾说自动 effort 选择是圣杯,GPT-5 的 Auto 模式试过后来消失了。学术界这条线上有三篇值得看,各自踩到不同的坑:
- AdaptThink17 把"要不要思考"写成约束优化,优势函数是 $A(x,y)=\mathbb{1}(\text{首 token 是结束思考符})\cdot\delta+R(x,y)-\bar{R}_{\text{ref}}(x)$——不思考模式的编码方式就是开口第一个 token 直接把思考块闭掉。$\delta$ 的含义极其干净:你愿意为跳过思考付出多少精度。只有当不思考与思考的精度差小于 $\delta$ 时,损失才偏向跳过。1.5B 上平均长度 −53%、精度 +2.4%。它还得处理冷启动——初始策略几乎从不输出不思考模式,于是没有梯度指向它,解法是从一个平衡两种模式的分布做重要性采样。
- AdaCoT18(字节 Seed)把 effort 明确写成 Pareto 前沿:$R=R_{\text{base}}-\alpha_1 P_{\text{miss}}-\alpha_2 P_{\text{over}}-\gamma P_{\text{fmt}}$,扫 $\alpha_1,\alpha_2$ 就扫出前沿。这是我见过对"effort 等级是什么"最贴切的形式化——它是精度–成本前沿上由惩罚比值选定的一个点。它还报告了一个多阶段训练的坑叫 decision boundary collapse:后续某个 CoT 几乎总有用的阶段(比如数学 RL)会把之前学到的自适应触发边界抹掉,对策是把思考标签后那个决策 token 的 loss mask 掉。生产管线里 RL 分好几个阶段跑的话,这个坑会真实踩到。
- Thinkless19 用
<short>/<think>两个控制 token 做首 token 路由,发现 vanilla GRPO 会 mode collapse——每条轨迹只有 1 个控制 token 但有 $T_i$ 个回复 token,$1/(T_i+1)$ 的归一化把控制 token 的梯度压死,而且长轨迹压得比短轨迹更狠。解法 DeGRPO 是把控制 token 的 loss 单独拿出来配一个系数($\alpha=1/1000$)。
连续 effort 目前是空白。 我特意找了一圈:Arora & Zanette 的 $\alpha$ 是训练期超参,一个 $\alpha$ 出一个 checkpoint,得到的是一族模型不是一个旋钮;L1 的 $n_{gold}$ 是连续的推理期参数但它条件在长度上而不是 effort 上;AnytimeReasoner 从预算先验里采样、训一个模型在所有预算下都好,形状对了但接口还是预算。真正做到"一个训好的模型暴露一个连续 effort 标量"的,工业界有 Inkling,学术界我没找到对应工作(找不到不等于不存在)。训练无关的做法有 Fractional Reasoning、SEAL 这类 latent steering,把提示引起的隐层偏移按 $\hat{h}=h+\alpha h_{\text{steer}}$ 缩放回注,连续性有了,但那是激活层的 hack 而不是训出来的接口。
代码实现
一个 API,两套完全不同的机制
最能说明问题的一段代码在 vLLM 的请求协议里。同一个 ChatCompletionRequest 上并排放着两个字段:
|
|
七个取值和 OpenAI Responses API 的 reasoning.effort 完全一致——开源生态把 OpenAI 的词表整套搬了过来,注释里还专门标注 max 是 DeepSeek V4 系列专有、不属于标准规范。这正好印证了前面那个观察:档位名是产品约定,不是模型能力的度量。
关键是这两个字段走的是两条完全不同的路。reasoning_effort 被塞进 chat template:
|
|
也就是走到前面 gpt-oss 那三行 jinja 去,变成 system 消息里的一行文本;顺便还把 effort != "none" 映射成 enable_thinking,兼容那些需要显式 opt-in 的模板。而 thinking_token_budget 进的是 SamplingParams,落到采样阶段的 logits 处理。
effort 是软的 prompt 条件,budget 是硬的 logits 屏蔽。 前者只在模型被训练过的情况下有效,后者对任何有 </think> token 的模型都有效。这是整个话题里最该分清的一件事,而 vLLM 的协议文件把它摆得最明白。
硬预算怎么实现:把整个词表打成 −inf
SGLang 的实现只有二十几行,比 vLLM 的版本好读得多:
|
|
三个细节和前面的讨论对得上。第一,这是硬屏蔽——整个词表置 $-\infty$ 只留一个 token,所以采样温度在这一步完全失效,预算是真的会被守住,对应 s1 表里 budget forcing 的 Control = 100%。第二,它先强制一个换行再强制 </think>,理由是让插入的边界符合模型训练时见过的 token 模式,而不是从半句话中间劈开——Nemotron 的 reasoning_budget 找换行收尾、s1 在 finish_reason == "length" 时补换行,是同一个考虑被三次独立地重新发明。第三,计数从 <think> 起算且包含 prompt 部分,所以预填的部分推理链是要占预算的。
token id 按模型族硬编码在子类里,这也说明这层完全是引擎侧的,和模型学过什么无关:
|
|
vLLM 的对应实现思路一样,但因为要在 speculative decoding 下工作——一步提议多个 token、其中一些会被拒——它得预测预算会在草稿窗口内的哪个位置被跨过,于是膨胀成一个几百行的状态机,还要处理"结束符被拒绝了就退回思考模式"这种情况。想读这个机制的话看 SGLang 那版就够了。
一个我觉得很漂亮的小设计
vLLM 允许配置 reasoning_end_str,而且它是任意字符串而不是单个 token。于是可以让强制终止读起来像是模型自己决定收尾的:
|
|
注意这句话——它几乎就是 Qwen3 技术报告里那句 stop-thinking 指令。也就是说 Qwen3 论文里描述的"手动打断并插入一句话"这个行为,在 vLLM 里被抽象成了一个可配置字符串,任何模型都能用。前面说 Qwen3 这个能力是 Thinking Mode Fusion 涌现出来的、没有专门训练,这里就能看到它被产品化成什么样子。
训练侧:同一个 DAPO 公式,三个框架 clamp 得不一样
DAPO 的 overlong reward shaping 是长度惩罚在开源框架里最常见的形态:在 max_resp_len 前留一段宽度为 overlong_buffer_len 的缓冲区,进入缓冲区后惩罚线性增长。verl 的实现在 DAPO reward manager 里:
|
|
min(..., 0) 保证没超预算的回复拿不到"写得短"的奖励——只罚不奖,这和 L1 发现加法奖励会塌缩是一脉相承的谨慎。但verl 这版没有下界:超过 max_resp_len 之后惩罚继续无限增长。TRL 的同名实现 get_soft_overlong_punishment 在超出后钉死在 −1.0,OpenRLHF 的版本则是在做除法之前先 min(exceed_len, overlong_buffer_len) 把分子截住,效果等于下界 $-$penalty_factor。三个框架实现同一篇论文的同一个公式,在截断行为上三种做法——如果要复现别人的长度惩罚结果,这是个真实的坑。
TRL 里还有一个形状更有意思的 cosine 长度奖励(来自 Demystifying Long CoT20,该文的结论是长度奖励塑形对稳定 CoT 长度增长是必需的,不做塑形长度增长本身就不稳定):
|
|
注意 else 分支把上下界调换了:答对时越短奖励越高,答错时越短惩罚越重。这是刻意保留探索动机——不让模型学会"不会做就赶紧交卷"。默认值答对是 $(0.5, 1.0)$,答错是 $(-1.0, -0.5)$。和 Kimi 的 $\min(0,\lambda)$、DAST 在答错且未超预算时反而鼓励写更长,是同一个直觉的三种写法。
/think 到底是谁在解析
最后一个值得核实的细节。我把 Qwen3-8B 的 chat template 抓下来 grep,no_think 出现 0 次——前面提到的 /think 和 /no_think 完全不在模板里,它们是训练出来的行为,模型自己认这两个标记。Qwen 的 model card 也是这么写的,称之为 soft switch。
对比 NVIDIA 的 Nemotron-Nano-9B-v2,同一件事是在模板里用 jinja 做的:
|
|
扫一遍所有消息、最后一个匹配生效,然后把标记从渲染文本里抹掉,模型根本看不到它。同一个用户可见的语法,一边是模型权重里的行为,一边是模板里的字符串匹配。 这个对比很能说明为什么"effort 控制"这件事不存在统一的实现层次——它可以落在权重里、落在模板里、落在采样器里,甚至落在 agent harness 里。
我的几个判断
“只是改 system prompt"这个说法要分两半看。 推理时确实只是改 prompt,这点从 gpt-oss 的 jinja 模板可以直接确认,三行代码。但这句 prompt 的语义完全来自 post-training——DeepSeek V4 的 Think Max 指令是在更松的长度惩罚下训出来的,Inkling 的 effort 数值是在按值缩放的 per-token cost 下训出来的。所以更准确的说法是:effort prompt 是一个行为选择器,它指向的行为必须事先被塑造出来。这也解释了一个实践问题——为什么把"请你尽量深入思考"写进任意模型的 system prompt,收益远小于调用官方的 effort 参数。
长度惩罚和硬截断是两种不同的约束,不该混用。 线性的 $-c(e)N_{\text{tokens}}$ 保留了模型超支的权利(只要任务奖励盖得住),硬截断则完全剥夺这个权利。Kimi 观察到的 length-overfitting 正是硬约束训练的后果。反过来说,如果部署时一定会有硬截断(agent 里的 token 上限),那就必须像 Nemotron 那样专门训练截断样本,不能只靠软惩罚。
Kimi 的"先做对再变短"是个通用原则。 Toggle 里那个 $\frac{1}{K}\sum_i r < \lambda$ 的保护条款,本质上是把效率优化推迟到能力建立之后。这和 RL 里常见的 curriculum 思路一致,但这里的门槛是逐问题的而不是全局的——同一个 batch 里,简单题已经在受预算约束,难题还在自由探索。我觉得这个 per-problem 自适应门槛比全局 warmup 更值得借鉴。
序数标签打不准但方向可靠,数字预算打得准但会被整体放弃。 这两句是 s1 的消融表和 TALE 的 token elasticity 合起来给出的答案,也是我认为工业界普遍选序数标签的真实原因——不是因为它更精确,恰恰相反,是因为它没法被违背。你说 high,模型总能"更努力一点”;你说 500 token,模型可能直接不理你,还比不给预算写得更长。真要钉住预算,只能靠引擎侧的 logits 屏蔽,而那已经不是模型在配合了。
效率评测很容易被骗。 ThinkDial 的 Leak Penalty 揭示的是:模型会把推理从 <think> 挤到答案段,thinking token 降了但总 token 涨了。任何只统计思考 token 的效率指标都会把这种重新分配读成压缩成功。看效率的时候要看总 token,这一点前面几家报告里只有 ThinkDial 明确处理了。
“effort 控制"不存在统一的实现层次。 同一个用户可见的 /no_think,Qwen3 靠权重认、Nemotron 靠 jinja 匹配;同一个"预算”,Qwen3 靠涌现的续写能力、Nemotron 靠专门造的截断样本、SGLang 靠 logits 屏蔽。这解释了为什么跨模型比较 effort 行为几乎不可能——你不知道自己在测哪一层。
自动 effort 选择目前是空白。 原文提到 GPT-5 的 Auto 模式曾经试过,后来从界面里消失了。Raschka 的判断是短期内 effort 会继续是显式的模型输入,多数通过 system prompt 递送,但 agent harness 或内部 router 会越来越多地根据任务状态和剩余资源自动推断模式和预算,同时保留用户覆盖。我同意这个判断,而且觉得 harness 层比模型层更适合做这件事——它才知道还剩多少时间、多少 token、这一步是探索还是收尾。
还想接着看的
garden 里 RL-LLM 和 veRL 强化学习课:DAPO 还很薄,这篇材料里 DAPO overlong shaping 在 verl / TRL / OpenRLHF 三处实现的差异,正好可以补进 veRL 强化学习课:DAPO。强化学习 RM 方法 目前只列了 ORM/PRM/GRM 几个名词,长度奖励这一类"非正确性奖励项"其实是个独立的分类维度,可以单独展开。另外 DeepSeek V4 的全词表 logit 蒸馏和 On Policy Distill 里记的 TML 只算采样 token 的做法是明确对立的两条路,值得回去补一段对比。
参考资料
- https://magazine.sebastianraschka.com/p/controlling-reasoning-effort-in-llms
- https://thinkingmachines.ai/news/introducing-inkling/
- https://arxiv.org/html/2606.19348
- https://arxiv.org/abs/2602.02276
- https://arxiv.org/abs/2602.15763
- https://arxiv.org/abs/2505.09388
- https://research.nvidia.com/labs/nemotron/files/NVIDIA-Nemotron-3-Ultra-Technical-Report.pdf
- https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b/modelcard
- https://api-docs.deepseek.com/guides/thinking_mode/
- https://huggingface.co/openai/gpt-oss-20b/raw/main/chat_template.jinja
- https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/sampling/custom_logit_processor.py
- https://github.com/vllm-project/vllm/blob/main/vllm/entrypoints/openai/chat_completion/protocol.py
- https://github.com/simplescaling/s1
- https://github.com/cmu-l3/l1
- https://arxiv.org/abs/2503.16419
-
Controlling Reasoning Effort in LLMs, Sebastian Raschka, Jul 2026, https://magazine.sebastianraschka.com/p/controlling-reasoning-effort-in-llms ↩︎
-
gpt-oss-120b & gpt-oss-20b Model Card, OpenAI, https://arxiv.org/abs/2508.10925 ↩︎
-
Qwen3 Technical Report, https://arxiv.org/abs/2505.09388 ↩︎
-
Inkling: Our Open-Weights Model, Thinking Machines Lab, Jul 2026, https://thinkingmachines.ai/news/introducing-inkling/ ↩︎
-
DeepSeek-V4: Towards Highly Efficient Million-Token Context Intelligence, https://arxiv.org/html/2606.19348 ↩︎
-
Nemotron 3 Ultra Technical Report, NVIDIA, https://research.nvidia.com/labs/nemotron/files/NVIDIA-Nemotron-3-Ultra-Technical-Report.pdf ↩︎
-
Kimi K2.5 Technical Report, https://arxiv.org/abs/2602.02276 ↩︎
-
GLM-5: from Vibe Coding to Agentic Engineering, https://arxiv.org/abs/2602.15763 ↩︎
-
s1: Simple test-time scaling, https://arxiv.org/abs/2501.19393 ↩︎
-
ThinkDial: An Open Recipe for Controlling Reasoning Effort in Large Language Models, https://arxiv.org/abs/2508.18773 ↩︎
-
Kimi k1.5: Scaling Reinforcement Learning with LLMs, https://arxiv.org/abs/2501.12599 ↩︎
-
L1: Controlling How Long A Reasoning Model Thinks With Reinforcement Learning, https://arxiv.org/abs/2503.04697 ↩︎
-
Token-Budget-Aware LLM Reasoning, https://arxiv.org/abs/2412.18547 ↩︎
-
Scalable Chain of Thoughts via Elastic Reasoning, https://arxiv.org/abs/2505.05315 ↩︎
-
Concise Reasoning via Reinforcement Learning, https://arxiv.org/abs/2504.05185 ↩︎
-
Thoughts Are All Over the Place: On the Underthinking of o1-Like LLMs, https://arxiv.org/abs/2501.18585 ↩︎
-
AdaptThink: Reasoning Models Can Learn When to Think, https://arxiv.org/abs/2505.13417 ↩︎
-
AdaCoT: Pareto-Optimal Adaptive Chain-of-Thought Triggering via Reinforcement Learning, https://arxiv.org/abs/2505.11896 ↩︎
-
Thinkless: LLM Learns When to Think, https://arxiv.org/abs/2505.13379 ↩︎
-
Demystifying Long Chain-of-Thought Reasoning in LLMs, https://arxiv.org/abs/2502.03373 ↩︎
Author houmin
Publish July 23, 2026
LastMod July 27, 2026
License 本作品采用 CC BY-NC-ND 4.0 许可协议进行许可,转载时请注明原文链接
如果你在浏览博客的过程中发现了任何问题,欢迎在对应文章下评论。如果你有其他事情想要咨询,可以通过邮件联系我。