Chapter 07

慢思考的一刻

Extended Thinking 让 Claude 先"写草稿思考"——这段可能几千 tokens,最后才产出精炼答案。代价是更慢更贵,回报是在数学、代码、逻辑推理上显著更准。本章讲清楚什么时候该开,什么时候纯属浪费钱。

什么是 thinking block

开启后,Claude 的 content 数组里会多一类 block:

{
  "content": [
    {
      "type": "thinking",
      "thinking": "让我梳理一下条件... 已知 A,B,C... 假设 X 则...",
      "signature": "ErUBC..."
    },
    {
      "type": "text",
      "text": "最终答案是 42。"
    }
  ]
}

应用层面通常只把 text block 显示给用户,thinking 当做"幕后草稿"——类似 o1 的 reasoning tokens,但 Claude 把原文给你,不是加密的。

开启 Thinking

const msg = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 16000,
  thinking: {
    type: "enabled",
    budget_tokens: 10000,    // thinking 最多花这么多
  },
  messages: [
    { role: "user", content: "证明 √2 是无理数,再证明 √n(n 非完全平方数)也无理。" },
  ],
});

for (const block of msg.content) {
  if (block.type === "thinking") {
    console.log("[thinking]", block.thinking.slice(0, 100), "...");
  } else if (block.type === "text") {
    console.log("[answer]", block.text);
  }
}

支持矩阵

模型Extended Thinking典型 budget
Opus 4.x✅ 原生最佳5000–30000
Sonnet 4.x✅ 支持2000–10000
Haiku 4.x⚠️ 部分版本不推荐

budget_tokens 规则

// ❌ 错误:budget > max_tokens
max_tokens: 5000,
thinking: { budget_tokens: 8000 },   // 400 Error

// ✅ 正确:max_tokens 覆盖 thinking + text
max_tokens: 16000,
thinking: { budget_tokens: 10000 },   // 留 6000 给 text 输出

什么时候该开

经验清单:

✅ 数学 / 逻辑证明
Thinking 显著提升准确率(常见 20%+)
✅ 代码调试 / 架构设计
多约束权衡、反事实分析,thinking 能列枚举
✅ 多步 Agent 规划
决定下一步前先想,避免"做到一半才发现方向错"
✅ 复杂 RAG
需要综合 5+ 段资料、比较冲突信息
❌ 简单分类 / 翻译 / 摘要
直接答就行,thinking 浪费 tokens
❌ 聊天陪伴 / 闲聊
Thinking 让延迟变长,用户体验差
❌ 极低延迟场景
首 token 延迟从 300ms → 5s 以上

Thinking 的成本

Thinking tokens 按 output 单价计费(不是 input)。也就是说开启 10000 budget:

Sonnet 4.x:10000 × $15/M = $0.15  (只是 thinking 那部分)
Opus 4.x: 10000 × $75/M = $0.75

所以 Opus + Thinking 的组合,单次调用很容易 $1 以上——只在真需要高可靠推理时上。

Thinking + 流式响应

流式里 thinking block 会先出:

event: content_block_start   type=thinking
event: content_block_delta   thinking_delta: "让我先..."
event: content_block_delta   thinking_delta: "考虑三种情况..."
...
event: content_block_stop
event: content_block_start   type=text
event: content_block_delta   text_delta: "答案是..."
...

UI 建议:thinking 期间显示 "🧠 正在推理..." 指示,不要直接把草稿怼给用户看(会把他们搞晕)。推理完成后再把 text block 显示在聊天气泡。

Thinking + Tool Use

Agent 在决定调工具前可以先 thinking,然后直接出 tool_use block。回塞 tool_result 后的第二次调用,模型可以再来一次 thinking+tool 循环。

第 1 次:
  [thinking]   "用户要订机票,我需要先查日期和目的地机场"
  [tool_use]   search_flights(date="2026-05-10", dest="PEK")

第 2 次(你回塞 tool_result):
  [thinking]   "有 3 个航班选项,按价格和时段筛,CA1234 最优"
  [text]       "推荐 CA1234,..."

Thinking 上下文的保留

重要细节:把 assistant response 作为多轮历史回塞时,保留 thinking block—— Claude 需要它作为推理连续性参考。Signature 字段用于完整性验证,不能改。

// ✅ 正确:保留整个 content 数组,包括 thinking
messages.push({ role: "assistant", content: resp.content });

// ❌ 错误:只取 text block
messages.push({
  role: "assistant",
  content: resp.content.filter((b) => b.type === "text"),
});

Thinking 不能和这些一起

何时 thinking 没帮助

不是所有任务都受益:

测试方法:同样 prompt 各跑 20 次 thinking on/off,用 LLM-as-judge 打分。差 < 5% → 关掉,省钱。

实战:SQL 生成

const resp = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 6000,
  thinking: { type: "enabled", budget_tokens: 4000 },
  system: "你是 PostgreSQL 专家。",
  messages: [{
    role: "user",
    content: `Schema:
users(id, country, signup_at)
orders(id, user_id, amount, created_at, status)

问题:过去 30 天里,哪些国家的 VIP 用户(月消费 > 10000)增长最快?用窗口函数,避免相关子查询。`,
  }],
});

带 thinking 的 Claude 会先思考"我得定义 VIP → 连接 users/orders → 按国家分月分组 → 同比/环比 → 窗口函数 ORDER BY"——产出更可执行的 SQL。

实战:LeetCode hard

thinking: { type: "enabled", budget_tokens: 15000 },

// "给定 m×n 网格,权值可正可负,求从左上到右下的所有路径中
//   路径和为 0 的路径数,mod 1e9+7"
//
// thinking 里 Claude 会:
// 1. 分析:权值有负,不能简单 DP
// 2. 考虑 meet in the middle
// 3. 评估复杂度 2^(m+n) / 2,45 太大?
// 4. 改用从中点对角线切,哈希合并
// 5. 最后给代码

Thinking 监控

usage 里会多一个字段:

{
  "usage": {
    "input_tokens": 120,
    "cache_read_input_tokens": 0,
    "output_tokens": 500,
    "thinking_tokens": 3842   // ← 新增
  }
}

生产监控应该追踪 thinking_tokens / output_tokens 比例,识别"thinking 但没啥产出"的 case(通常任务选错了)。

本章小结