Claude 的 Extended Thinking——什么时候用,成本值不值
Claude 的 Extended Thinking——什么时候用,成本值不值
上周有个同事跑来问我,说他在用 Claude API 做代码审查,有时候感觉 Claude 的回答挺浅,特别是遇到复杂的并发 Bug 分析时,给出的结论总感觉少了点推理过程。我问他有没有开 Extended Thinking,他一脸懵。
这让我想起自己第一次接触这个特性的时候,也没太当回事。直到有一次在做一个多模块依赖分析的任务,普通模式下 Claude 给出的结论反复横跳,开了 Extended Thinking 之后,整个推理链条一下子清晰了很多——它会先把问题拆解,然后逐步论证,最后给出带有置信度标注的结论。那一刻我才意识到,这不只是一个"让 AI 多想一会儿"的功能,它是一种完全不同的推理机制。
今天这篇文章,我就把自己在工程实践中对 Extended Thinking 的理解系统整理一下:它到底是什么,用 Spring AI 怎么调用,哪些场景开它有用,哪些场景纯属浪费钱,以及真实的成本账怎么算。
Extended Thinking 是什么
简单说,Extended Thinking 是 Anthropic 给 Claude 提供的一种"显式推理"能力。在普通模式下,Claude 接收 prompt 直接生成回答,内部的推理过程是隐式的——你看不到它怎么想的,它自己也不会刻意组织推理步骤。
Extended Thinking 模式下,Claude 会先产生一段"思维链"(thinking tokens),在这段内容里,它会像人类解题一样:
- 分解问题
- 列出可能的方向
- 逐步推导
- 自我纠错和质疑
- 最终得出结论
这段思维链对用户是可见的(API 返回中会包含 thinking 块),但它不算在最终回答的 output tokens 里——它有自己的 token 计费方式,而且单价更贵。
从技术实现上看,Extended Thinking 本质上是让模型在生成最终答案前,先走一遍更深的自回归循环。这不是什么 RAG,也不是外挂的推理框架,是模型本体的能力扩展。
目前支持 Extended Thinking 的模型主要是:
claude-opus-4-5及以上版本claude-sonnet-4-5(部分任务)
工程上怎么调用
Anthropic 原生 SDK(Java)
先看最基础的调用方式,用 Anthropic 官方 Java SDK:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.*;
public class ExtendedThinkingDemo {
private final AnthropicClient client;
public ExtendedThinkingDemo() {
this.client = AnthropicOkHttpClient.builder()
.apiKey(System.getenv("ANTHROPIC_API_KEY"))
.build();
}
public void analyzeComplexCode(String codeSnippet) {
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-4-5")
.maxTokens(16000)
// 开启 Extended Thinking,设置 thinking token 预算
.thinking(ThinkingConfigEnabledParam.builder()
.type(ThinkingConfigEnabledParam.Type.ENABLED)
.budgetTokens(10000) // 给 thinking 分配的最大 token 数
.build())
.addUserMessage("请对以下代码进行深度分析,找出潜在的并发安全问题:\n\n" + codeSnippet)
.build();
Message response = client.messages().create(params);
// 遍历响应内容块
for (ContentBlock block : response.content()) {
if (block instanceof ThinkingBlock thinkingBlock) {
System.out.println("=== 思维过程 ===");
System.out.println(thinkingBlock.thinking());
} else if (block instanceof TextBlock textBlock) {
System.out.println("=== 最终回答 ===");
System.out.println(textBlock.text());
}
}
// 打印 token 使用情况
Usage usage = response.usage();
System.out.printf("Input tokens: %d, Output tokens: %d%n",
usage.inputTokens(), usage.outputTokens());
}
}注意几个关键点:
budgetTokens是给 thinking 分配的 上限,不是固定消耗量。如果问题简单,实际用不了这么多。maxTokens必须大于budgetTokens,因为最终答案的 tokens 是包含在maxTokens里的。- thinking block 和 text block 是分开的,需要分别处理。
Spring AI 集成配置
Spring AI 从 1.0.0 开始支持 Anthropic 的 Extended Thinking,配置方式如下:
首先在 pom.xml 中引入依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>application.yml 配置:
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-opus-4-5
max-tokens: 16000
# Extended Thinking 相关配置
thinking:
type: enabled
budget-tokens: 8000Java 配置类:
import org.springframework.ai.anthropic.AnthropicChatOptions;
import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AIConfig {
@Bean
public AnthropicChatOptions deepThinkingOptions() {
return AnthropicChatOptions.builder()
.withModel("claude-opus-4-5")
.withMaxTokens(16000)
.withThinking(AnthropicApi.ThinkingType.ENABLED, 8000)
.build();
}
@Bean
public AnthropicChatOptions quickResponseOptions() {
// 不开 Extended Thinking 的普通配置
return AnthropicChatOptions.builder()
.withModel("claude-sonnet-4-5")
.withMaxTokens(4096)
.build();
}
}Service 层调用:
import org.springframework.ai.anthropic.AnthropicChatOptions;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CodeAnalysisService {
@Autowired
private ChatModel chatModel;
@Autowired
private AnthropicChatOptions deepThinkingOptions;
@Autowired
private AnthropicChatOptions quickResponseOptions;
/**
* 深度代码分析——使用 Extended Thinking
*/
public String deepCodeAnalysis(String code, String analysisType) {
String systemPrompt = """
你是一位资深Java工程师,专注于代码质量分析。
请对代码进行深度分析,给出详细的问题诊断和改进建议。
""";
String userPrompt = String.format("""
分析类型:%s
代码内容:
```java
%s
```
请从以下维度分析:
1. 线程安全性
2. 内存管理
3. 异常处理完整性
4. 性能瓶颈
5. 设计模式使用合理性
""", analysisType, code);
Prompt prompt = new Prompt(
userPrompt,
deepThinkingOptions // 使用开启了 Extended Thinking 的配置
);
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getContent();
}
/**
* 简单问答——不需要 Extended Thinking
*/
public String quickAnswer(String question) {
Prompt prompt = new Prompt(
new UserMessage(question),
quickResponseOptions
);
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getContent();
}
}动态控制 thinking 预算
实际项目中,我更倾向于根据任务复杂度动态调整 budgetTokens:
@Service
public class AdaptiveThinkingService {
@Autowired
private ChatModel chatModel;
/**
* 根据问题复杂度自动选择推理深度
*/
public String analyzeWithAdaptiveThinking(String problem, ComplexityLevel level) {
int budgetTokens = switch (level) {
case LOW -> 0; // 不开 thinking
case MEDIUM -> 3000;
case HIGH -> 8000;
case EXTREME -> 15000;
};
AnthropicChatOptions options;
if (budgetTokens == 0) {
options = AnthropicChatOptions.builder()
.withModel("claude-sonnet-4-5")
.withMaxTokens(4096)
.build();
} else {
options = AnthropicChatOptions.builder()
.withModel("claude-opus-4-5")
.withMaxTokens(budgetTokens + 4096) // 预留 4096 给最终回答
.withThinking(AnthropicApi.ThinkingType.ENABLED, budgetTokens)
.build();
}
Prompt prompt = new Prompt(problem, options);
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getContent();
}
public enum ComplexityLevel {
LOW, MEDIUM, HIGH, EXTREME
}
}适用场景 vs 不适用场景
这是最关键的判断,也是最容易踩坑的地方。我用下面这张图来梳理:
适用场景——开 Extended Thinking 有明显提升
1. 复杂 Bug 根因分析
普通模式下,Claude 可能会给你一个"看起来合理"的答案,但如果 Bug 涉及多个模块之间的时序问题或状态竞争,它容易遗漏关键链路。Extended Thinking 会强迫它把整个调用链想清楚再回答。
我实测了一个场景:一段有 ABA 问题的无锁队列代码,普通模式 Claude 分析了两处明显的 CAS 操作问题,但漏掉了一个跨方法的隐式状态依赖;开了 thinking 之后,它在思维链里专门花了一段篇幅分析方法边界上的状态变化,最终把这个隐藏的问题也挖出来了。
2. 架构方案对比与取舍
"我们是用 Kafka 还是 RocketMQ"这类问题,如果你给了具体的业务约束(消息量、延迟要求、团队技术栈、运维能力),Extended Thinking 会真正地把每个约束项都代入到两个方案里去权衡,而不是给你一个"各有优劣"的废话结论。
3. 多约束优化
比如"在满足 P99 延迟 < 200ms、成本 < $500/月、支持水平扩展的前提下,设计一套推荐系统缓存架构"。这类问题有多个约束需要同时满足,普通模式很容易顾此失彼。
4. 代码重构方案设计
给一段 1000 行的遗留代码,要求在不改变行为的前提下重构为符合 DDD 原则的结构,这种任务需要先"看懂"原有逻辑再"映射"到新结构,Extended Thinking 在这里的收益非常明显。
不适用场景——开了也是浪费钱
1. 文本翻译和摘要
翻译是确定性任务,不需要深度推理,开了 thinking 只是让模型多走了一圈"我来翻译这段文字……"这种废话步骤,结果质量没有提升,成本直接翻倍。
2. 简单的代码生成
"写一个 Spring Boot 的 CRUD 接口",这种任务模型已经有足够多的训练数据,不需要深度推理,直接生成就好。
3. 格式转换
JSON 转 XML、Markdown 转 HTML,纯机械操作,thinking 完全没用。
4. 创意写作
这是我踩过的坑。有次让 Claude 写一段产品文案,开了 thinking,结果思维链里全是"这段文案需要突出产品特点……考虑到目标用户群……"——完全是过度分析,写出来的文案反而显得刻板。
成本对比——thinking tokens 更贵
这是工程上最核心的决策因素之一。我来把账算清楚。
截至 2025 年,Claude API 的大致定价(以 claude-opus-4-5 为例):
| Token 类型 | 单价(每 100 万 tokens) |
|---|---|
| Input tokens | $15 |
| Output tokens | $75 |
| Thinking tokens | $75(与 output 同价,部分场景更高) |
一次典型的 Extended Thinking 调用:
场景:分析一段 500 行 Java 代码的并发安全性
Input tokens: ~2000(代码 + 提示词)
Thinking tokens: ~6000(实际消耗的思维链)
Output tokens: ~1500(最终回答)
普通模式成本:
2000 × $15/1M + 1500 × $75/1M = $0.03 + $0.1125 = $0.1425
Extended Thinking 成本:
2000 × $15/1M + 6000 × $75/1M + 1500 × $75/1M = $0.03 + $0.45 + $0.1125 = $0.5925一次请求成本从 $0.14 涨到 $0.59,涨了 4 倍多。
但如果这次分析发现了一个生产级的并发 Bug,节省的不只是 $0.45。
成本控制策略:
@Component
public class ThinkingCostController {
private static final double COST_PER_MILLION_THINKING_TOKENS = 75.0;
private static final double MONTHLY_THINKING_BUDGET = 100.0; // $100/月的 thinking 预算
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 检查是否还有 thinking 预算,并在调用后记录消耗
*/
public boolean canUseThinking(String tenantId) {
String key = "thinking:cost:" + tenantId + ":" + YearMonth.now();
String currentCostStr = redisTemplate.opsForValue().get(key);
double currentCost = currentCostStr != null ? Double.parseDouble(currentCostStr) : 0.0;
return currentCost < MONTHLY_THINKING_BUDGET;
}
public void recordThinkingUsage(String tenantId, int thinkingTokens) {
double cost = thinkingTokens * COST_PER_MILLION_THINKING_TOKENS / 1_000_000.0;
String key = "thinking:cost:" + tenantId + ":" + YearMonth.now();
redisTemplate.opsForValue().increment(key, (long)(cost * 10000)); // 存储整数避免浮点精度
redisTemplate.expire(key, 35, TimeUnit.DAYS);
}
}实测结果:哪类问题开 thinking 有明显提升
我整理了一份实测对比,基于真实项目中的典型任务:
提升明显的任务特征:
- 有多个互相影响的变量
- 存在反直觉的边界情况
- 需要先理解再推导,不能靠模式匹配直接输出
提升不明显的任务特征:
- 确定性的转换任务
- 模型已经高度熟悉的标准模式
- 任务本身没有"深度"可挖
工程建议:如何在项目里正确使用
按任务分级,不要全开 thinking。把任务分成三类:简单确定性任务(普通模式)、中等复杂度任务(小 budget thinking,3000 tokens)、高复杂度推理任务(大 budget thinking,8000-15000 tokens)。
把 thinking 结果也存下来。思维链本身就是有价值的信息,可以作为审计日志,也可以用来判断 AI 是否"真的想清楚了"。
监控 thinking token 实际消耗。
budgetTokens是上限,实际消耗由模型决定。如果某类任务的实际 thinking tokens 总是远低于 budget,说明你给的 budget 太高了,可以调低。不要在实时对话场景强开 thinking。用户等待时间会显著增加,这会直接影响体验。把 thinking 用在后台分析、批量处理、非实时的深度任务上。
A/B 测试是判断的基础。不要凭感觉说"开了 thinking 效果更好",要量化。用相同的测试集,分别跑普通模式和 thinking 模式,统计准确率和质量评分的差异。
总结
Extended Thinking 不是银弹,也不是噱头。它是一个针对特定类型问题有真实效果提升的工程工具。
用好它的核心原则只有一条:让 thinking tokens 花在刀刃上。复杂推理、多约束优化、深度代码分析——这些场景值得付出 3-4 倍的成本。翻译、摘要、简单问答——开了只是烧钱。
Spring AI 的集成已经足够简便,配置层面做好任务分级,运行层面做好成本监控,Extended Thinking 就能成为你 AI 工具箱里真正有价值的一个工具。
