Extended Thinking 的核心特性
thinking: {type: "enabled", budget_tokens: N} 启用。启用后,Claude 会在生成最终答案前产生一段内部推理过程(thinking block),这个过程对开发者可见。基本使用:最简示例
import anthropic
client = anthropic.Anthropic()
# 最简单的扩展思考调用
response = client.messages.create(
model="claude-sonnet-4-6", # 支持思考的模型
max_tokens=16000, # max_tokens 必须 > budget_tokens(容纳思考+回答)
thinking={
"type": "enabled",
"budget_tokens": 10000 # 最多允许思考 10000 个 token
},
messages=[{
"role": "user",
"content": "证明:√2 是无理数"
}]
)
# 遍历响应中的所有 content block
for block in response.content:
if block.type == "thinking":
# thinking 包含 Claude 的完整推理过程(草稿)
print("[思考过程(前200字)]")
print(block.thinking[:200] + "...")
print(f"[思考共 {len(block.thinking)} 字符]")
elif block.type == "text":
# text 是最终用户可见的答案
print("\n[最终答案]")
print(block.text)
# 查看 token 使用量
print(f"\n输入 Token: {response.usage.input_tokens}")
print(f"输出 Token(含思考): {response.usage.output_tokens}")
响应结构完整解析
# 完整响应结构(JSON 示意)
{
"id": "msg_01Xfn...",
"type": "message",
"role": "assistant",
"content": [
{
"type": "thinking",
# thinking 字段是 Claude 的"草稿纸"内容
# 注意:内容可能包含错误的中间步骤(这是正常的!)
# Claude 可能探索多条路径,最终只采用最优路径的结论
"thinking": "我需要证明 √2 是无理数...\n假设 √2 = p/q(最简分数)...\n则 2 = p²/q²...\n所以 p² = 2q²,p² 是偶数,所以 p 是偶数...\n设 p = 2k...\n则 4k² = 2q²,q² = 2k²...\nq 也是偶数!\n但 p/q 是最简分数,p 和 q 不能都是偶数,矛盾!\n所以假设错误,√2 是无理数。"
},
{
"type": "text",
"text": "**证明 √2 是无理数(反证法)**\n\n**假设** √2 是有理数,则可以写成最简分数 p/q..."
}
],
"usage": {
"input_tokens": 30, # 用户输入的 token 数
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"output_tokens": 8420 # 包含思考 token + 文本 token
}
}
budget_tokens 的影响与选择
budget_tokens 是最重要的参数,直接影响答案质量和成本:
| budget_tokens | 适用场景 | 平均实际思考量 | 相对成本 |
|---|---|---|---|
| 0(禁用) | 不需要推理的任务(翻译、摘要) | 0 | 基准 |
| 1,000 – 2,000 | 简单多步问题、基本验证 | 500-1500 | 3-6x |
| 5,000 – 8,000 | 中等复杂度(日常推理,推荐默认值) | 2000-6000 | 10-20x |
| 10,000 – 16,000 | 数学竞赛、复杂代码分析 | 5000-12000 | 20-40x |
| 32,000+ | 极复杂研究问题、多步骤规划 | 10000-30000 | 40-100x |
设置 budget_tokens=10000 不代表模型一定会思考 10000 个 token。Claude 会根据问题复杂度自主决定实际使用多少。对简单问题设置很高的预算只会浪费"等待时间",不会提高答案质量(但不会额外收费)。
另外,max_tokens 必须设置为大于 budget_tokens 的值(因为 thinking + text 都计入 max_tokens)。推荐设置:max_tokens = budget_tokens + 4000。
流式输出:实时显示思考过程
def stream_with_thinking(prompt: str, budget: int = 8000) -> tuple[str, str]:
"""流式输出,实时展示思考进度,返回 (thinking, answer)"""
thinking_parts = []
answer_parts = []
current_block_type = None
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=budget + 4000,
thinking={"type": "enabled", "budget_tokens": budget},
messages=[{"role": "user", "content": prompt}]
) as stream:
for event in stream:
event_type = getattr(event, 'type', None)
if event_type == 'content_block_start':
# 新 block 开始,记录类型
current_block_type = event.content_block.type
if current_block_type == 'thinking':
print("\n[思考中]", end="", flush=True)
elif current_block_type == 'text':
print("\n\n[回答]\n", flush=True)
elif event_type == 'content_block_delta':
# 内容增量,区分 thinking 和 text
if current_block_type == 'thinking':
# 思考时只显示进度点,不显示原始推理(可选择显示)
print(".", end="", flush=True)
thinking_parts.append(event.delta.thinking)
elif current_block_type == 'text':
# 最终答案实时流式输出
print(event.delta.text, end="", flush=True)
answer_parts.append(event.delta.text)
elif event_type == 'message_stop':
print() # 换行
return "".join(thinking_parts), "".join(answer_parts)
多轮对话:如何保留思考上下文
这是 Extended Thinking 最容易出错的地方。在多轮对话中,必须将上一轮的完整 content(包含 thinking block)传回给 API——Claude 依赖 thinking block 中的推理来保持对话连贯性。
class ThinkingConversation:
"""多轮对话管理器,正确处理 thinking block 的历史传递"""
def __init__(self, budget: int = 5000):
self.history = [] # 完整的对话历史
self.budget = budget
def chat(self, user_message: str) -> str:
"""发送消息并获取回复,自动管理 thinking block"""
self.history.append({
"role": "user",
"content": user_message
})
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=self.budget + 4000,
thinking={"type": "enabled", "budget_tokens": self.budget},
messages=self.history
)
# 关键:将完整响应(含 thinking block)加入历史
# 不能只保存 text block!Claude 需要 thinking 来理解上下文
self.history.append({
"role": "assistant",
"content": response.content # 传入 list,包含 thinking+text blocks
})
# 只返回 text block 给用户显示
text_blocks = [b for b in response.content if b.type == "text"]
return text_blocks[0].text if text_blocks else ""
def get_thinking_history(self) -> list[str]:
"""获取所有轮次的推理过程(用于调试)"""
thinking_list = []
for msg in self.history:
if msg["role"] == "assistant" and isinstance(msg["content"], list):
for block in msg["content"]:
if hasattr(block, 'type') and block.type == "thinking":
thinking_list.append(block.thinking)
return thinking_list
# 使用示例
conv = ThinkingConversation(budget=5000)
r1 = conv.chat("请解释什么是 P vs NP 问题")
r2 = conv.chat("如果 P=NP 被证明,会有什么影响?") # 基于上下文继续
r3 = conv.chat("给出一个具体的密码学影响案例") # 继续深入
Prompt Caching + Extended Thinking 组合
对于需要固定长系统提示的应用(如专业知识库、代码审查规范),Prompt Caching 可以大幅降低重复输入成本:
# 组合使用:Prompt Caching + Extended Thinking
# 适合:固定系统提示 + 多个用户查询的场景
SYSTEM_PROMPT = """你是一位资深数学导师,专注于帮助学生理解高等数学。
你会用清晰的步骤解释每个概念,并检查推理过程的严密性。
对于证明题,你会:
1. 先分析证明思路
2. 选择合适的证明方法(直接证明/反证法/数学归纳法)
3. 逐步写出严格的证明步骤
4. 最后检验证明的完整性
""" # 这个 prompt 超过 1024 tokens 时缓存最有价值
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=14000,
thinking={"type": "enabled", "budget_tokens": 8000},
# System prompt 使用列表格式以启用缓存
system=[{
"type": "text",
"text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"} # 标记为可缓存
}],
messages=[{"role": "user", "content": question}]
)
# 检查缓存效果
usage = response.usage
print(f"缓存写入: {usage.cache_creation_input_tokens} tokens(首次调用)")
print(f"缓存命中: {usage.cache_read_input_tokens} tokens(后续调用)")
# 缓存命中时,这些 token 费率约为普通输入的 10%!
# 对于 2000 token 的系统提示,每次节省 ~90% 的输入费用
o1 vs Claude Extended Thinking 对比
| 特性 | OpenAI o1/o3 | Claude Extended Thinking |
|---|---|---|
| 思维链可见性 | 完全隐藏(安全考虑) | 完全暴露给开发者 |
| 思考预算控制 | 不支持(自动决定) | 支持 budget_tokens 精确控制 |
| 结构化输出 | 部分支持 | 需要 Two-Stage 方案(见第7章) |
| 多轮对话 | 标准 API | 需要传回完整 content(含 thinking) |
| Prompt Caching | 不支持 | 支持,可大幅降低重复调用成本 |
| 流式输出 | 支持 | 支持,thinking 和 text 分别流式 |
| 调试友好性 | 低(黑盒) | 高(可查看完整推理过程) |
如果你的应用需要:(1) 调试和优化推理质量,(2) 向用户展示推理过程(提高可信度),(3) 精确控制思考预算,(4) 结合 Prompt Caching 降低成本——那么 Claude Extended Thinking 是更好的选择。如果你只需要"结果"而不关心推理过程,o1 的隐式推理也同样有效。
Extended Thinking API 通过 budget_tokens 控制思考深度(上限而非保证),响应包含 thinking(推理草稿)和 text(最终答案)两种 block。多轮对话必须将完整 content 传回 API。Prompt Caching 与 Extended Thinking 可以组合使用,降低重复调用成本。Claude 相比 o1 的独特优势是思维链对开发者可见,便于调试和优化。下一章进入推理模型的提示工程技巧——很多普通模型的最佳实践在推理模型上适得其反。