跳转至

Thinking Effort 控制 — Adaptive / Level-Switched

更新日期:2026-04-26

2024-2026 的 reasoning model(o1 / o3 / Claude 3.7+ / DeepSeek-R1 / Qwen3-Thinking / Kimi K2-Reasoning)共同特征:模型显式生成思考 token 后再回答。问题是 —— 思考多少?

本文按四个角度过:

  1. 怎么实现 thinking budget 控制(API / 模型层面)
  2. 怎么训练 adaptive thinking(让模型自己决定)
  3. 怎么训练 level-switched(用户给信号控制)
  4. 数据怎么构造、结构怎么改

主要参考:


一、什么是 thinking effort

flowchart LR
    prompt["User<br/>2^17 = ?"]
    think["&lt;think&gt;<br/>多步推理"]
    answer["&lt;answer&gt;<br/>131072"]

    prompt --> think --> answer

    classDef stage fill:#fff,stroke:#cc785c,color:#1a1a1a;
    class prompt,think,answer stage
<think>
2^10 = 1024.   2^7 = 128.   2^17 = 1024 × 128 = 131072.
</think>
<answer>131072</answer>

Thinking effort = 思考阶段的 token 数(或 reasoning depth)。极简任务("Hi")几乎不需要 think,复杂题(IMO 题)可能需要 30k+ token thinking。

控制 effort 的两个维度:

  • Adaptive:模型自动判断难度,动态决定 thinking 长度
  • Level-switched:用户传 low / medium / high 信号,模型按级别 think

二、API 层面控制:当前各家实现

2.1 OpenAI (GPT-5 / o-series)

# 推测的 API 形态(待核实当前 API spec)
response = client.chat.completions.create(
    model="gpt-5",
    messages=[...],
    reasoning_effort="medium",  # low / medium / high / auto
)

OpenAI 把 reasoning effort 暴露成 API 参数。具体每级对应多少 thinking token 不公开,估计:

  • low: < 1k thinking tokens
  • medium: 1k-10k
  • high: 10k-100k
  • auto: 模型决定

2.2 Anthropic (Claude 3.7+ Extended Thinking)

response = client.messages.create(
    model="claude-sonnet-4",
    messages=[...],
    thinking={"type": "enabled", "budget_tokens": 16000},  # 0 = disabled
)

Anthropic 用 budget_tokens 显式给上限。模型可以在 budget 内自由决定用多少。

2.3 DeepSeek (R1 / V3.1)

R1 没有 API 级 effort 参数 —— 模型总是输出 <think>...</think> reasoning。控制 thinking 长度靠 sampling 参数(max_tokens / stop strings)。

V3.1 引入 hybrid mode(reasoning ON/OFF 二态切换),由 system prompt 触发。

2.4 Qwen / Kimi(待核实)

Qwen3-Thinking 公开声明支持 <think>...</think>,effort 控制方式见各家 system prompt 约定。

2.5 Native vs API 实现差异

实现层 例子 优点 缺点
API 参数 OpenAI reasoning_effort 用户简单 模型必须训过这个参数才能 work
Token budget Anthropic budget_tokens 灵活 用户得估 budget
System prompt 触发 DeepSeek V3.1 兼容现有 API 切换不直观
永远 thinking R1, o1(无切换) 不需要参数 简单问题浪费 token

三、Adaptive thinking — 模型自己决定

3.1 什么是 adaptive

输入 prompt,模型根据 difficulty 自动决定 reasoning length:

  • "Hi" → 0 thinking token
  • "What is the capital of France?" → ~50 thinking token (verify)
  • "Solve this PDE..." → 5k+ thinking token

3.2 训练目标设计

Adaptive thinking 的难点:怎么 reward "用最少 token 答对"

朴素 reward:correctness only → 模型学会 "always think 20k tokens" 增加正确率 朴素加 length penalty → 模型学会 "skip thinking" 容易答错的题

3.3 已知方法

A. Length-Aware Reward

R1-style RL 加 length normalization:

def length_aware_reward(output, ground_truth, max_useful_length=10000):
    correctness = check_correctness(output, ground_truth)  # 0 or 1
    length = len(extract_thinking(output))
    # 正确时奖励短,错误时不惩罚长(让难题继续 think)
    if correctness:
        length_bonus = max(0, 1 - length / max_useful_length)
        return 1.0 + 0.2 * length_bonus
    else:
        return 0.0

实际 R1 paper Section 2.3.4 提到尝试了 length penalty 但对 reasoning 能力有害,最终不用。OpenAI o1 / Anthropic 怎么做不公开。

B. Difficulty-conditioned curriculum

Anthropic / OpenAI 推测路线:

  1. 训练数据按难度分级(easy / medium / hard)
  2. 每个难度对应不同 thinking length 标签
  3. 训练时模型隐式学到 "看到难题就 think 长"

C. Self-evaluation reward

让模型自己判断"我需要再想一下吗":

# 推理时
think_step = generate_one_thinking_step()
confidence = model.estimate_confidence(prompt, think_so_far + think_step)
if confidence > THRESHOLD:
    break  # 模型觉得想够了

训练时奖励 confidence calibration —— 自评准的模型。

3.4 测 adaptive 是否 work

  • Easy / hard 题对照:同模型,easy 题 thinking 短、hard 题 thinking 长 → adaptive
  • Token efficiency:达到给定准确率所用 thinking token 数(越少越好)
  • Calibration:模型对自己 confidence 的预测准不准

实际 frontier model(o1 / Claude 3.7)观察上确实 adaptive —— prompt 一句话回 200 tokens、prompt 一道竞赛题回 30k tokens。但具体训练方法不公开。


四、Level-switched thinking — 用户控制

4.1 高 / 中 / 低三档怎么训

Low / Medium / High 信号通常通过两种方式传进 model:

A. System prompt 编码

[System] Reasoning level: low. Provide a direct answer with minimal thinking.
[User] {prompt}

或:

[System] You are a model with thinking_effort=high. Use detailed reasoning.

训练时数据形如:

{
  "system": "Reasoning level: low",
  "user": "What's 2+3?",
  "thinking": "5",
  "answer": "5"
}
{
  "system": "Reasoning level: high",
  "user": "What's 2+3?",
  "thinking": "Let me verify: 2+3 = 5. Indeed, 2 plus 3 is 5.",
  "answer": "5"
}

模型学到 system prompt 里的 level → 控制 thinking 长度。

B. Special control token

# 在 tokenizer 里加 <|reasoning_low|>, <|reasoning_med|>, <|reasoning_high|>
input_ids = tokenizer.encode(
    f"<|reasoning_high|>{prompt}"
)

模型在训练时看到 control token 时会 condition thinking length。比 system prompt 更确定(不依赖自然语言理解)。

C. Prefix tuning

每个 effort level 学一组 prefix embedding,inject 到 input 前段。轻量但需要训练时显式设计。

4.2 数据构造

训 level-switched 模型需要同 prompt 多种 effort 的数据

def build_multi_effort_dataset(prompts, model_high_effort):
    """
    针对每个 prompt,生成 low/med/high 三个版本的 (thinking, answer)
    """
    dataset = []
    for p in prompts:
        # high effort: 完整 reasoning chain(用强模型 R1 / o1 生成)
        high = model_high_effort.generate(p, reasoning="full")

        # low effort: 直接 answer,最小 thinking
        low_thinking = "Direct calculation."
        low_answer = high.answer  # 同样答案

        # medium: high 的 reasoning 砍掉 50%(关键步骤保留)
        med_thinking = condense_reasoning(high.thinking, ratio=0.5)
        med_answer = high.answer

        dataset.extend([
            {"system": "level=low", "user": p, "thinking": low_thinking, "answer": low_answer},
            {"system": "level=med", "user": p, "thinking": med_thinking, "answer": med_answer},
            {"system": "level=high", "user": p, "thinking": high.thinking, "answer": high.answer},
        ])
    return dataset

关键 trick

  • 三档的 answer 必须相同(不然模型学到 "low 等于错")
  • thinking 的层次不是一刀切,要"按推理 step 截断"(保留最关键的 1-3 步)
  • 难题在 low 级别可能答错 —— 这是符合设计的(low 速度优先,准确率次要)

4.3 Level vs token budget 的取舍

方式 训练复杂度 推理控制粒度 用户体验
Level (low/med/high) 中(需要分级数据) 粗(3 档) 简单,快速选
Token budget 简单(不需要分级) 细(任意 token 数) 用户得猜 budget
Auto (adaptive) 高(需要 difficulty data) 自动 最简单
Hybrid (auto + override) 自动 + 强制 最强

OpenAI 走 level(low/med/high/auto),Anthropic 走 budget,DeepSeek V3.1 走 binary on/off。当前没有"标准答案"。


五、结构怎么改

5.1 Tokenizer / Special tokens

加 reasoning control tokens:

<|think_start|> ... <|think_end|>     # thinking 区间
<|reasoning_low|> / <|med|> / <|high|> # level 控制
<|stop_thinking|>                       # 强制结束 thinking

DeepSeek-R1 用 <think>...</think> (XML-like) 而不是 special token。两种方式都 work,trade-off:

  • Special token:训练时 attention 容易识别,但加 vocab size
  • XML-like:兼容现有 tokenizer,但模型需更大学习量

5.2 Position embedding 注意

Thinking 段经常很长(10k+ token)。如果 base model 训的 context 是 4k,YaRN 扩展到 32k+ 可能在 thinking 阶段失效。

实战经验:reasoning model 必须在长 context 训练(至少 32k),否则 thinking 长度受限。

5.3 Sampling parameter 调整

Reasoning model 在 thinking 阶段需要多样性(探索不同 reasoning path);answer 阶段需要确定性

  • Thinking: temperature ~0.6-0.8, top-p ~0.95
  • Answer: temperature ~0.0-0.2, top-p ~0.5

实现上:在 <think> token 时切换 sampling param。vLLM / SGLang 有相关支持(待核实)。

5.4 KV Cache 处理

长 thinking → 大 KV cache。优化:

  • Thinking KV discard:answer 生成完后 thinking 的 KV 不再需要,可释放
  • Compressed thinking memory:长 thinking 段压缩到 latent vector(类似 Activation Beacon)
  • Hierarchical thinking:先生成 high-level plan,每个 sub-step 独立 generate(树形 thinking)

六、如何训 adaptive 模型(伪代码 pipeline)

flowchart LR
    base["Base LLM"]
    s1["S1<br/>分级 SFT"]
    s2["S2<br/>Adaptive RL"]
    s3["S3<br/>Eval + 迭代"]
    final["Adaptive<br/>Reasoning Model"]

    base --> s1 --> s2 --> s3 --> final

    classDef stage fill:#fff,stroke:#cc785c,color:#1a1a1a;
    class base,s1,s2,s3,final stage

S1: prompt 含 low/med/high 三档 + adaptive 标记;S2: reward = correctness × token efficiency + KL 到 ref;S3: 检查 calibration + token efficiency。

6.1 Stage 1: 分级 SFT

sft_data = build_multi_effort_dataset(
    prompts=collect_diverse_prompts(),
    model_high_effort=existing_reasoning_model,  # R1 / o1
)
# train: input = (system + user), target = (thinking + answer)
sft_model = sft(base_model, sft_data, epochs=2)

6.2 Stage 2: Adaptive RL

def adaptive_reward(output, ground_truth, prompt):
    correctness = verify(output.answer, ground_truth)
    thinking_len = len(output.thinking_tokens)

    # 难题阈值:用 baseline correct rate 估计
    difficulty = estimate_difficulty(prompt)
    expected_len = difficulty * 1000  # 简单 → 100, 难 → 5000

    # length 偏离 expected 越远越扣分
    length_penalty = -abs(thinking_len - expected_len) / expected_len

    return correctness + 0.1 * length_penalty

# GRPO 训练
adaptive_model = grpo(sft_model, adaptive_reward, **rl_config)

6.3 Stage 3: 评测

  • Token efficiency curve:(accuracy, avg thinking tokens) 在 easy/med/hard 上
  • Calibration:模型 self-confidence 跟 actual correctness 的相关性
  • User study:实际用户感觉模型 "thinking too much / too little / 合适"

七、具体数据来源 — 怎么造分级数据

7.1 Easy 数据来源

  • GSM8K easy subset(小学数学)—— 通常 1-3 step,thinking 短
  • TriviaQA / NQ(事实 QA)—— 单 fact 检索
  • Conversational data("hi", "thanks")—— 几乎不需要 thinking
  • Translation 短句

构造:直接 SFT,thinking 段简短("Direct: ..." or 空)。

7.2 Medium 数据来源

  • MATH 中难度题(高中数学)
  • HumanEval / MBPP(标准编程)
  • Multi-fact QA(需要 2-3 step)
  • General knowledge with verification

构造:thinking 中等(200-1000 token),答案后简单 verify step。

7.3 Hard 数据来源

  • AIME / IMO / Putnam 数学题
  • Codeforces Div1 / LeetCode Hard
  • GPQA Diamond 物理 / 化学专业题
  • 专业 benchmark:MathOlympics, FrontierMath, ARC-AGI

构造:thinking 长(5k-30k token),含 multiple paths + dead-ends + self-correction。

7.4 难度自动分级

不能手工标几百万条数据。自动分级:

def auto_grade_difficulty(prompt, sample_model, n_attempts=10):
    """
    用一个中等强度模型多次尝试,按通过率估计难度
    """
    successes = 0
    for _ in range(n_attempts):
        out = sample_model.generate(prompt)
        if verify(out, ground_truth):
            successes += 1
    pass_rate = successes / n_attempts
    if pass_rate > 0.8:
        return "easy"
    elif pass_rate > 0.3:
        return "medium"
    else:
        return "hard"

这是 R1 / Qwen3 / Kimi 等大概率用的自动 grading 方法(具体细节不公开)。


八、实操建议

如果在 Kimi K2 / 自家模型上加 thinking effort 控制:

  1. 第一版做 binary on/off(DeepSeek V3.1 路线)—— 最容易,system prompt 触发 + SFT 即可
  2. 第二版做 3 级(low/med/high)
  3. 收集 100k 多样 prompt
  4. 自动分级(pass-rate 法)
  5. 每 prompt 用 R1-style 模型生成 high-effort answer
  6. 用 LLM truncate 成 medium / low 版本
  7. SFT on 3-level data
  8. 第三版做 adaptive(最难):
  9. 加 length-aware reward 的 RL
  10. 配 calibration eval
  11. 调 reward weight 是核心难点

最大的坑:

  • 三级数据的 answer 必须一致 —— 不然模型学到 "low = 简化但错",废
  • Thinking 必须真的有意义 —— low 不要简化成 "Direct: 5",要有最小 verification
  • Curriculum 别跳级 —— 先 easy/medium 训稳,再加 hard

九、未公开 / 待核实

各家 thinking control 实现细节几乎都不公开:

  • OpenAI 怎么训 reasoning_effort 4 级(low/med/high/auto)?
  • Anthropic budget_tokens 是 hard limit 还是 soft hint?
  • DeepSeek V3.1 怎么从 V3 加 reasoning ON/OFF 切换 —— 是新训还是 adapter?
  • Qwen3-Thinking 的 thinking detection 机制
  • Kimi K2-Reasoning thinking budget 控制方法

这些是各家 moat。学术界(Adaptive Reasoning、[Self-Adaptive Cognitive Debate])有相关工作但没规模化复现。


参考文献

  1. DeepSeek-AI. DeepSeek-R1. 2025. arXiv:2501.12948
  2. Anthropic. Claude 3.7 Sonnet — Extended Thinking. 2025. anthropic.com/news/claude-3-7-sonnet
  3. OpenAI. Learning to Reason with LLMs (o1). 2024. openai.com/index/learning-to-reason-with-llms
  4. Kimi Team. Kimi K2: Open Agentic Intelligence. 2025. arXiv:2507.20534
  5. Qwen Team. Qwen3 Technical Report. 2025. arXiv:2505.09388(待核实)
  6. Wei et al. Chain-of-Thought Prompting. 2022. arXiv:2201.11903
  7. Kojima et al. Large Language Models are Zero-Shot Reasoners. 2022. arXiv:2205.11916
  8. Lightman et al. Let's Verify Step by Step (PRM). 2023. arXiv:2305.20050

上级 · J. 推理行为与失败模式