扩展思考为Claude提供了增强的推理能力来处理复杂任务,同时在提供最终答案之前,为其逐步思考过程提供不同程度的透明度。

支持的模型

以下模型支持扩展思考:
  • Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
  • Claude Sonnet 4 (claude-sonnet-4-20250514)
  • Claude Sonnet 3.7 (claude-3-7-sonnet-20250219)
  • Claude Haiku 4.5 (claude-haiku-4-5-20251001)
  • Claude Opus 4.1 (claude-opus-4-1-20250805)
  • Claude Opus 4 (claude-opus-4-20250514)
API行为在Claude Sonnet 3.7和Claude 4模型之间有所不同,但API结构保持完全相同。更多信息,请参阅不同模型版本中思考的差异

扩展思考的工作原理

当扩展思考开启时,Claude会创建thinking内容块,在其中输出内部推理。Claude在制作最终回应之前会融入这种推理的见解。 API响应将包含thinking内容块,然后是text内容块。 以下是默认响应格式的示例:
{
  "content": [
    {
      "type": "thinking",
      "thinking": "让我逐步分析这个问题...",
      "signature": "WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem2dw3URve/op91XWHOEBLLqIOMfFG/UvLEczmEsUjavL...."
    },
    {
      "type": "text",
      "text": "基于我的分析..."
    }
  ]
}
有关扩展思考响应格式的更多信息,请参阅Messages API参考

如何使用扩展思考

以下是在Messages API中使用扩展思考的示例:
curl https://api.anthropic.com/v1/messages \
     --header "x-api-key: $ANTHROPIC_API_KEY" \
     --header "anthropic-version: 2023-06-01" \
     --header "content-type: application/json" \
     --data \
'{
    "model": "claude-sonnet-4-5",
    "max_tokens": 16000,
    "thinking": {
        "type": "enabled",
        "budget_tokens": 10000
    },
    "messages": [
        {
            "role": "user",
            "content": "是否存在无限多个满足n mod 4 == 3的质数?"
        }
    ]
}'
要开启扩展思考,添加一个thinking对象,将type参数设置为enabled,并将budget_tokens设置为扩展思考的指定token预算。 budget_tokens参数决定了Claude在内部推理过程中允许使用的最大token数量。在Claude 4模型中,此限制适用于完整的思考token,而不是总结的输出。更大的预算可以通过为复杂问题启用更彻底的分析来提高响应质量,尽管Claude可能不会使用分配的全部预算,特别是在超过32k的范围内。 budget_tokens必须设置为小于max_tokens的值。但是,当使用交错思考与工具时,您可以超过此限制,因为token限制变成您的整个上下文窗口(200k token)。

总结思考

启用扩展思考后,Claude 4模型的Messages API返回Claude完整思考过程的总结。总结思考提供扩展思考的全部智能优势,同时防止滥用。 以下是总结思考的一些重要考虑因素:
  • 您需要为原始请求生成的完整思考token付费,而不是总结token。
  • 计费的输出token计数将不匹配您在响应中看到的token计数。
  • 思考输出的前几行更加详细,提供特别有助于提示工程目的的详细推理。
  • 随着Anthropic寻求改进扩展思考功能,总结行为可能会发生变化。
  • 总结保留了Claude思考过程的关键思想,延迟最小,实现了可流式传输的用户体验,并便于从Claude Sonnet 3.7迁移到Claude 4模型。
  • 总结由与您在请求中目标模型不同的模型处理。思考模型看不到总结的输出。
Claude Sonnet 3.7继续返回完整的思考输出。在需要访问Claude 4模型完整思考输出的罕见情况下,联系我们的销售团队

流式思考

您可以使用服务器发送事件(SSE)流式传输扩展思考响应。 当为扩展思考启用流式传输时,您通过thinking_delta事件接收思考内容。 有关通过Messages API进行流式传输的更多文档,请参阅流式消息 以下是如何处理带有思考的流式传输:
curl https://api.anthropic.com/v1/messages \
     --header "x-api-key: $ANTHROPIC_API_KEY" \
     --header "anthropic-version: 2023-06-01" \
     --header "content-type: application/json" \
     --data \
'{
    "model": "claude-sonnet-4-5",
    "max_tokens": 16000,
    "stream": true,
    "thinking": {
        "type": "enabled",
        "budget_tokens": 10000
    },
    "messages": [
        {
            "role": "user",
            "content": "27 * 453等于多少?"
        }
    ]
}'
流式输出示例:
event: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-sonnet-4-5", "stop_reason": null, "stop_sequence": null}}

event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": ""}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "让我逐步解决这个问题:\n\n1. 首先分解27 * 453"}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n2. 453 = 400 + 50 + 3"}}

// 额外的思考增量...

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}

event: content_block_stop
data: {"type": "content_block_stop", "index": 0}

event: content_block_start
data: {"type": "content_block_start", "index": 1, "content_block": {"type": "text", "text": ""}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 1, "delta": {"type": "text_delta", "text": "27 * 453 = 12,231"}}

// 额外的文本增量...

event: content_block_stop
data: {"type": "content_block_stop", "index": 1}

event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}}

event: message_stop
data: {"type": "message_stop"}
当使用启用思考的流式传输时,您可能会注意到文本有时以较大的块到达,与较小的逐token传递交替。这是预期的行为,特别是对于思考内容。流式系统需要批量处理内容以获得最佳性能,这可能导致这种”块状”传递模式,流式事件之间可能有延迟。我们正在持续改进这种体验,未来的更新将专注于使思考内容流式传输更加流畅。

扩展思考与工具使用

扩展思考可以与工具使用一起使用,允许Claude推理工具选择和结果处理。 当使用扩展思考与工具使用时,请注意以下限制:
  1. 工具选择限制:带有思考的工具使用仅支持tool_choice: {"type": "auto"}(默认)或tool_choice: {"type": "none"}。使用tool_choice: {"type": "any"}tool_choice: {"type": "tool", "name": "..."}将导致错误,因为这些选项强制使用工具,这与扩展思考不兼容。
  2. 保留思考块:在工具使用期间,您必须将最后一条助手消息的thinking块传回API。将完整的未修改块包含回API以维持推理连续性。
以下是一个实际示例,展示了在提供工具结果时如何保留思考块:
weather_tool = {
    "name": "get_weather",
    "description": "获取某个位置的当前天气",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {"type": "string"}
        },
        "required": ["location"]
    }
}

# 第一个请求 - Claude用思考和工具请求回应
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[weather_tool],
    messages=[
        {"role": "user", "content": "巴黎的天气如何?"}
    ]
)
API响应将包含思考、文本和tool_use块:
{
    "content": [
        {
            "type": "thinking",
            "thinking": "用户想知道巴黎的当前天气。我可以访问函数`get_weather`...",
            "signature": "BDaL4VrbR2Oj0hO4XpJxT28J5TILnCrrUXoKiiNBZW9P+nr8XSj1zuZzAl4egiCCpQNvfyUuFFJP5CncdYZEQPPmLxYsNrcs...."
        },
        {
            "type": "text",
            "text": "我可以帮您获取巴黎的当前天气信息。让我为您查询一下"
        },
        {
            "type": "tool_use",
            "id": "toolu_01CswdEQBMshySk6Y9DFKrfq",
            "name": "get_weather",
            "input": {
                "location": "巴黎"
            }
        }
    ]
}
现在让我们继续对话并使用工具
# 提取思考块和工具使用块
thinking_block = next((block for block in response.content
                      if block.type == 'thinking'), None)
tool_use_block = next((block for block in response.content
                      if block.type == 'tool_use'), None)

# 调用您的实际天气API,这里是您实际API调用的地方
# 让我们假设这是我们得到的回应
weather_data = {"temperature": 88}

# 第二个请求 - 包含思考块和工具结果
# 响应中不会生成新的思考块
continuation = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[weather_tool],
    messages=[
        {"role": "user", "content": "巴黎的天气如何?"},
        # 注意thinking_block和tool_use_block都被传入
        # 如果不传入,会引发错误
        {"role": "assistant", "content": [thinking_block, tool_use_block]},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use_block.id,
            "content": f"当前温度:{weather_data['temperature']}°F"
        }]}
    ]
)
API响应现在将包含文本
{
    "content": [
        {
            "type": "text",
            "text": "目前在巴黎,温度是88°F(31°C)"
        }
    ]
}

保留思考块

在工具使用期间,您必须将thinking块传回API,并且必须将完整的未修改块包含回API。这对于维持模型的推理流程和对话完整性至关重要。
虽然您可以省略先前assistant角色轮次的thinking块,但我们建议在任何多轮对话中始终将所有思考块传回API。API将:
  • 自动过滤提供的思考块
  • 使用保持模型推理所需的相关思考块
  • 仅对显示给Claude的块的输入token计费
当Claude调用工具时,它正在暂停构建响应以等待外部信息。当工具结果返回时,Claude将继续构建现有响应。这需要在工具使用期间保留思考块,原因如下:
  1. 推理连续性:思考块捕获了Claude导致工具请求的逐步推理。当您发布工具结果时,包含原始思考确保Claude可以从中断的地方继续其推理。
  2. 上下文维护:虽然工具结果在API结构中显示为用户消息,但它们是连续推理流程的一部分。保留思考块在多个API调用中维持这种概念流程。有关上下文管理的更多信息,请参阅我们的上下文窗口指南
重要:当提供thinking块时,连续thinking块的整个序列必须与模型在原始请求期间生成的输出匹配;您不能重新排列或修改这些块的序列。

交错思考

Claude 4模型中的扩展思考与工具使用支持交错思考,这使Claude能够在工具调用之间思考,并在接收工具结果后进行更复杂的推理。 通过交错思考,Claude可以:
  • 在决定下一步做什么之前推理工具调用的结果
  • 在推理步骤之间链接多个工具调用
  • 基于中间结果做出更细致的决策
要启用交错思考,请在您的API请求中添加beta头 interleaved-thinking-2025-05-14 以下是交错思考的一些重要考虑因素:
  • 使用交错思考时,budget_tokens可以超过max_tokens参数,因为它代表一个助手轮次内所有思考块的总预算。
  • 交错思考仅支持通过Messages API使用的工具
  • 交错思考仅支持Claude 4模型,使用beta头interleaved-thinking-2025-05-14
  • 直接调用Claude API允许您在对任何模型的请求中传递interleaved-thinking-2025-05-14,没有效果。
  • 在第三方平台上(例如,Amazon BedrockVertex AI),如果您将interleaved-thinking-2025-05-14传递给除Claude Opus 4.1、Opus 4或Sonnet 4之外的任何模型,您的请求将失败。
import anthropic

client = anthropic.Anthropic()

# 定义工具
calculator_tool = {
    "name": "calculator",
    "description": "执行数学计算",
    "input_schema": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "要计算的数学表达式"
            }
        },
        "required": ["expression"]
    }
}

database_tool = {
    "name": "database_query",
    "description": "查询产品数据库",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "要执行的SQL查询"
            }
        },
        "required": ["query"]
    }
}

# 第一个请求 - Claude在所有工具调用之前思考一次
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    messages=[{
        "role": "user",
        "content": "如果我们以每个50美元的价格销售150个产品A,总收入是多少,这与我们从数据库中的平均月收入相比如何?"
    }]
)

# 响应包括思考后跟工具使用
# 注意:Claude在开始时思考一次,然后做出所有工具决策
print("第一个响应:")
for block in response.content:
    if block.type == "thinking":
        print(f"思考(总结):{block.thinking}")
    elif block.type == "tool_use":
        print(f"工具使用:{block.name},输入{block.input}")
    elif block.type == "text":
        print(f"文本:{block.text}")

# 您将执行工具并返回结果...
# 获得两个工具结果后,Claude直接响应而不进行额外思考
在这个不使用交错思考的示例中:
  1. Claude在开始时思考一次以理解任务
  2. 预先做出所有工具使用决策
  3. 当工具结果返回时,Claude立即提供响应而不进行额外思考
import anthropic

client = anthropic.Anthropic()

# 与之前相同的工具定义
calculator_tool = {
    "name": "calculator",
    "description": "执行数学计算",
    "input_schema": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "要计算的数学表达式"
            }
        },
        "required": ["expression"]
    }
}

database_tool = {
    "name": "database_query",
    "description": "查询产品数据库",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "要执行的SQL查询"
            }
        },
        "required": ["query"]
    }
}

# 启用交错思考的第一个请求
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[{
        "role": "user",
        "content": "如果我们以每个50美元的价格销售150个产品A,总收入是多少,这与我们从数据库中的平均月收入相比如何?"
    }]
)

print("初始响应:")
thinking_blocks = []
tool_use_blocks = []

for block in response.content:
    if block.type == "thinking":
        thinking_blocks.append(block)
        print(f"思考:{block.thinking}")
    elif block.type == "tool_use":
        tool_use_blocks.append(block)
        print(f"工具使用:{block.name},输入{block.input}")
    elif block.type == "text":
        print(f"文本:{block.text}")

# 第一个工具结果(计算器)
calculator_result = "7500"  # 150 * 50

# 继续第一个工具结果
response2 = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[
        {
            "role": "user",
            "content": "如果我们以每个50美元的价格销售150个产品A,总收入是多少,这与我们从数据库中的平均月收入相比如何?"
        },
        {
            "role": "assistant",
            "content": [thinking_blocks[0], tool_use_blocks[0]]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[0].id,
                "content": calculator_result
            }]
        }
    ]
)

print("\n计算器结果后:")
# 使用交错思考,Claude可以在决定查询数据库之前思考计算器结果
for block in response2.content:
    if block.type == "thinking":
        thinking_blocks.append(block)
        print(f"交错思考:{block.thinking}")
    elif block.type == "tool_use":
        tool_use_blocks.append(block)
        print(f"工具使用:{block.name},输入{block.input}")

# 第二个工具结果(数据库)
database_result = "5200"  # 示例平均月收入

# 继续第二个工具结果
response3 = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[
        {
            "role": "user",
            "content": "如果我们以每个50美元的价格销售150个产品A,总收入是多少,这与我们从数据库中的平均月收入相比如何?"
        },
        {
            "role": "assistant",
            "content": [thinking_blocks[0], tool_use_blocks[0]]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[0].id,
                "content": calculator_result
            }]
        },
        {
            "role": "assistant",
            "content": thinking_blocks[1:] + tool_use_blocks[1:]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[1].id,
                "content": database_result
            }]
        }
    ]
)

print("\n数据库结果后:")
# 使用交错思考,Claude可以在制定最终响应之前思考两个结果
for block in response3.content:
    if block.type == "thinking":
        print(f"最终思考:{block.thinking}")
    elif block.type == "text":
        print(f"最终响应:{block.text}")
在这个使用交错思考的示例中:
  1. Claude最初思考任务
  2. 收到计算器结果后,Claude可以再次思考该结果的含义
  3. 然后Claude根据第一个结果决定如何查询数据库
  4. 收到数据库结果后,Claude在制定最终响应之前再次思考两个结果
  5. 思考预算分布在轮次内的所有思考块中
这种模式允许更复杂的推理链,其中每个工具的输出都会影响下一个决策。

扩展思考与提示缓存

带有思考的提示缓存有几个重要考虑因素:
扩展思考任务通常需要超过5分钟才能完成。考虑使用1小时缓存持续时间来维持跨越更长思考会话和多步骤工作流程的缓存命中。
思考块上下文移除
  • 来自先前轮次的思考块被移除,这可能影响缓存断点
  • 当继续使用工具使用的对话时,思考块被缓存并在从缓存读取时计为输入token
  • 这创建了一个权衡:虽然思考块在视觉上不消耗上下文窗口空间,但在缓存时仍计入您的输入token使用量
  • 如果思考被禁用,如果您在当前工具使用轮次中传递思考内容,请求将失败。在其他上下文中,传递给API的思考内容被简单忽略
缓存失效模式
  • 思考参数的更改(启用/禁用或预算分配)会使消息缓存断点失效
  • 交错思考放大缓存失效,因为思考块可能出现在多个工具调用之间
  • 系统提示和工具尽管思考参数更改或块移除仍保持缓存
虽然思考块被移除用于缓存和上下文计算,但在继续使用工具使用的对话时必须保留它们,特别是使用交错思考时。

理解思考块缓存行为

当使用扩展思考与工具使用时,思考块表现出影响token计数的特定缓存行为: 工作原理:
  1. 缓存仅在您进行包含工具结果的后续请求时发生
  2. 当进行后续请求时,先前的对话历史(包括思考块)可以被缓存
  3. 这些缓存的思考块在从缓存读取时在您的使用指标中计为输入token
  4. 当包含非工具结果用户块时,所有先前的思考块被忽略并从上下文中剥离
详细示例流程: 请求1:
用户:"巴黎的天气如何?"
响应1:
[thinking_block_1] + [tool_use block 1]
请求2:
用户:["巴黎的天气如何?"], 
助手:[thinking_block_1] + [tool_use block 1], 
用户:[tool_result_1, cache=True]
响应2:
[thinking_block_2] + [text block 2]
请求2写入请求内容的缓存(不是响应)。缓存包括原始用户消息、第一个思考块、工具使用块和工具结果。 请求3:
用户:["巴黎的天气如何?"], 
助手:[thinking_block_1] + [tool_use block 1], 
用户:[tool_result_1, cache=True], 
助手:[thinking_block_2] + [text block 2], 
用户:[文本响应, cache=True]
因为包含了非工具结果用户块,所有先前的思考块被忽略。此请求将被处理为:
用户:["巴黎的天气如何?"], 
助手:[tool_use block 1], 
用户:[tool_result_1, cache=True], 
助手:[text block 2], 
用户:[文本响应, cache=True]
要点:
  • 这种缓存行为自动发生,即使没有显式的cache_control标记
  • 无论使用常规思考还是交错思考,此行为都是一致的
from anthropic import Anthropic
import requests
from bs4 import BeautifulSoup

client = Anthropic()

def fetch_article_content(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    # 移除脚本和样式元素
    for script in soup(["script", "style"]):
        script.decompose()

    # 获取文本
    text = soup.get_text()

    # 分解为行并移除每行的前导和尾随空格
    lines = (line.strip() for line in text.splitlines())
    # 将多标题分解为每行一个
    chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
    # 删除空行
    text = '\n'.join(chunk for chunk in chunks if chunk)

    return text

# 获取文章内容
book_url = "https://www.gutenberg.org/cache/epub/1342/pg1342.txt"
book_content = fetch_article_content(book_url)
# 仅使用足够的文本进行缓存(前几章)
LARGE_TEXT = book_content[:5000]

SYSTEM_PROMPT=[
    {
        "type": "text",
        "text": "您是一个负责文学分析的AI助手。请仔细分析以下文本。",
    },
    {
        "type": "text",
        "text": LARGE_TEXT,
        "cache_control": {"type": "ephemeral"}
    }
]

MESSAGES = [
    {
        "role": "user",
        "content": "分析这段文字的语调。"
    }
]

# 第一个请求 - 建立缓存
print("第一个请求 - 建立缓存")
response1 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    system=SYSTEM_PROMPT,
    messages=MESSAGES
)

print(f"第一个响应使用量:{response1.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response1.content
})
MESSAGES.append({
    "role": "user",
    "content": "分析这段文字中的人物。"
})
# 第二个请求 - 相同的思考参数(预期缓存命中)
print("\n第二个请求 - 相同的思考参数(预期缓存命中)")
response2 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    system=SYSTEM_PROMPT,
    messages=MESSAGES
)

print(f"第二个响应使用量:{response2.usage}")

# 第三个请求 - 不同的思考参数(消息缓存未命中)
print("\n第三个请求 - 不同的思考参数(消息缓存未命中)")
response3 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 8000  # 更改了思考预算
    },
    system=SYSTEM_PROMPT,  # 系统提示保持缓存
    messages=MESSAGES  # 消息缓存失效
)

print(f"第三个响应使用量:{response3.usage}")
from anthropic import Anthropic
import requests
from bs4 import BeautifulSoup

client = Anthropic()

def fetch_article_content(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    # 移除脚本和样式元素
    for script in soup(["script", "style"]):
        script.decompose()

    # 获取文本
    text = soup.get_text()

    # 分解为行并移除每行的前导和尾随空格
    lines = (line.strip() for line in text.splitlines())
    # 将多标题分解为每行一个
    chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
    # 删除空行
    text = '\n'.join(chunk for chunk in chunks if chunk)

    return text

# 获取文章内容
book_url = "https://www.gutenberg.org/cache/epub/1342/pg1342.txt"
book_content = fetch_article_content(book_url)
# 仅使用足够的文本进行缓存(前几章)
LARGE_TEXT = book_content[:5000]

# 没有系统提示 - 在消息中缓存
MESSAGES = [
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": LARGE_TEXT,
                "cache_control": {"type": "ephemeral"},
            },
            {
                "type": "text",
                "text": "分析这段文字的语调。"
            }
        ]
    }
]

# 第一个请求 - 建立缓存
print("第一个请求 - 建立缓存")
response1 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    messages=MESSAGES
)

print(f"第一个响应使用量:{response1.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response1.content
})
MESSAGES.append({
    "role": "user",
    "content": "分析这段文字中的人物。"
})
# 第二个请求 - 相同的思考参数(预期缓存命中)
print("\n第二个请求 - 相同的思考参数(预期缓存命中)")
response2 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000  # 相同的思考预算
    },
    messages=MESSAGES
)

print(f"第二个响应使用量:{response2.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response2.content
})
MESSAGES.append({
    "role": "user",
    "content": "分析这段文字中的背景。"
})

# 第三个请求 - 不同的思考预算(预期缓存未命中)
print("\n第三个请求 - 不同的思考预算(预期缓存未命中)")
response3 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 8000  # 不同的思考预算破坏缓存
    },
    messages=MESSAGES
)

print(f"第三个响应使用量:{response3.usage}")
以下是脚本的输出(您可能会看到略有不同的数字)
第一个请求 - 建立缓存
第一个响应使用量:{ cache_creation_input_tokens: 1370, cache_read_input_tokens: 0, input_tokens: 17, output_tokens: 700 }

第二个请求 - 相同的思考参数(预期缓存命中)

第二个响应使用量:{ cache_creation_input_tokens: 0, cache_read_input_tokens: 1370, input_tokens: 303, output_tokens: 874 }

第三个请求 - 不同的思考预算(预期缓存未命中)
第三个响应使用量:{ cache_creation_input_tokens: 1370, cache_read_input_tokens: 0, input_tokens: 747, output_tokens: 619 }
此示例演示了当在消息数组中设置缓存时,更改思考参数(budget_tokens从4000增加到8000)会使缓存失效。第三个请求显示没有缓存命中,cache_creation_input_tokens=1370cache_read_input_tokens=0,证明当思考参数更改时基于消息的缓存失效。

扩展思考的最大token和上下文窗口大小

在较旧的Claude模型(Claude Sonnet 3.7之前)中,如果提示token和max_tokens的总和超过了模型的上下文窗口,系统会自动调整max_tokens以适应上下文限制。这意味着您可以设置一个大的max_tokens值,系统会根据需要静默减少它。 对于Claude 3.7和4模型,max_tokens(当启用思考时包括您的思考预算)被强制执行为严格限制。如果提示token + max_tokens超过上下文窗口大小,系统现在将返回验证错误。
您可以阅读我们的上下文窗口指南以获得更彻底的深入了解。

扩展思考的上下文窗口

当计算启用思考的上下文窗口使用量时,有一些需要注意的考虑因素:
  • 来自先前轮次的思考块被剥离,不计入您的上下文窗口
  • 当前轮次思考计入该轮次的max_tokens限制
下图演示了启用扩展思考时的专门token管理: 扩展思考的上下文窗口图 有效上下文窗口计算为:
上下文窗口 =
  (当前输入token - 先前思考token) +
  (思考token + 加密思考token + 文本输出token)
我们建议使用token计数API来获得您特定用例的准确token计数,特别是在处理包含思考的多轮对话时。

扩展思考与工具使用的上下文窗口

当使用扩展思考与工具使用时,思考块必须明确保留并与工具结果一起返回。 扩展思考与工具使用的有效上下文窗口计算变为:
上下文窗口 =
  (当前输入token + 先前思考token + 工具使用token) +
  (思考token + 加密思考token + 文本输出token)
下图说明了扩展思考与工具使用的token管理: 扩展思考与工具使用的上下文窗口图

管理扩展思考的token

鉴于扩展思考Claude 3.7和4模型的上下文窗口和max_tokens行为,您可能需要:
  • 更积极地监控和管理您的token使用
  • 随着提示长度的变化调整max_tokens
  • 可能更频繁地使用token计数端点
  • 注意先前的思考块不会在您的上下文窗口中累积
这种更改是为了提供更可预测和透明的行为,特别是随着最大token限制显著增加。

思考加密

完整的思考内容被加密并在signature字段中返回。此字段用于验证思考块是由Claude生成的,当传回API时。
只有在使用扩展思考的工具时才严格需要发送回思考块。否则,您可以省略先前轮次的思考块,或者如果您传回它们,让API为您剥离它们。如果发送回思考块,我们建议按照您收到的方式传回所有内容,以保持一致性并避免潜在问题。
以下是思考加密的一些重要考虑因素:
  • 流式响应时,签名通过content_block_delta事件内的signature_delta添加,就在content_block_stop事件之前。
  • Claude 4模型中的signature值比先前模型中的显著更长。
  • signature字段是一个不透明字段,不应被解释或解析 - 它仅用于验证目的。
  • signature值在平台间兼容(Claude API、Amazon BedrockVertex AI)。在一个平台上生成的值将与另一个平台兼容。

思考编辑

偶尔Claude的内部推理会被我们的安全系统标记。当这种情况发生时,我们加密部分或全部thinking块并将其作为redacted_thinking块返回给您。redacted_thinking块在传回API时被解密,允许Claude继续其响应而不失去上下文。 当构建使用扩展思考的面向客户的应用程序时:
  • 注意编辑的思考块包含不可读的加密内容
  • 考虑提供简单的解释,如:“Claude的一些内部推理已因安全原因自动加密。这不会影响响应的质量。”
  • 如果向用户显示思考块,您可以过滤掉编辑的块,同时保留正常的思考块
  • 透明地说明使用扩展思考功能可能偶尔导致一些推理被加密
  • 实施适当的错误处理,以优雅地管理编辑的思考而不破坏您的UI
以下是显示正常和编辑思考块的示例:
{
  "content": [
    {
      "type": "thinking",
      "thinking": "让我逐步分析这个问题...",
      "signature": "WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem2dw3URve/op91XWHOEBLLqIOMfFG/UvLEczmEsUjavL...."
    },
    {
      "type": "redacted_thinking",
      "data": "EmwKAhgBEgy3va3pzix/LafPsn4aDFIT2Xlxh0L5L8rLVyIwxtE3rAFBa8cr3qpPkNRj2YfWXGmKDxH4mPnZ5sQ7vB9URj2pLmN3kF8/dW5hR7xJ0aP1oLs9yTcMnKVf2wRpEGjH9XZaBt4UvDcPrQ..."
    },
    {
      "type": "text",
      "text": "基于我的分析..."
    }
  ]
}
在您的输出中看到编辑的思考块是预期行为。模型仍然可以使用这种编辑的推理来告知其响应,同时维持安全护栏。如果您需要在应用程序中测试编辑思考处理,您可以使用这个特殊测试字符串作为您的提示:ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB
在多轮对话中将thinkingredacted_thinking块传回API时,您必须为最后一个助手轮次将完整的未修改块包含回API。这对于维持模型的推理流程至关重要。我们建议始终将所有思考块传回API。有关更多详细信息,请参阅上面的保留思考块部分。
此示例演示了如何处理当Claude的内部推理包含被安全系统标记的内容时可能出现在响应中的redacted_thinking块:
import anthropic

client = anthropic.Anthropic()

# 使用触发编辑思考的特殊提示(仅用于演示目的)
response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    messages=[{
        "role": "user",
        "content": "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB"
    }]
)

# 识别编辑的思考块
has_redacted_thinking = any(
    block.type == "redacted_thinking" for block in response.content
)

if has_redacted_thinking:
    print("响应包含编辑的思考块")
    # 这些块在后续请求中仍然可用

    # 提取所有块(编辑和非编辑的)
    all_thinking_blocks = [
        block for block in response.content
        if block.type in ["thinking", "redacted_thinking"]
    ]

    # 当传递到后续请求时,包含所有块而不修改
    # 这保持了Claude推理的完整性

    print(f"总共找到{len(all_thinking_blocks)}个思考块")
    print(f"这些块仍然作为输出token计费")

不同模型版本中思考的差异

Messages API在Claude Sonnet 3.7和Claude 4模型中处理思考的方式不同,主要在编辑和总结行为方面。 请参阅下表进行简要比较:
功能Claude Sonnet 3.7Claude 4模型
思考输出返回完整思考输出返回总结思考
交错思考不支持支持interleaved-thinking-2025-05-14 beta头

定价

扩展思考使用标准token定价方案:
模型基础输入Token缓存写入缓存命中输出Token
Claude Opus 4.1$15 / MTok$18.75 / MTok$1.50 / MTok$75 / MTok
Claude Opus 4$15 / MTok$18.75 / MTok$1.50 / MTok$75 / MTok
Claude Sonnet 4.5$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
Claude Sonnet 4$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
Claude Sonnet 3.7$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
思考过程产生的费用包括:
  • 思考期间使用的token(输出token)
  • 来自最后一个助手轮次的思考块包含在后续请求中(输入token)
  • 标准文本输出token
当启用扩展思考时,会自动包含专门的系统提示以支持此功能。
当使用总结思考时:
  • 输入token:您原始请求中的token(不包括先前轮次的思考token)
  • 输出token(计费):Claude内部生成的原始思考token
  • 输出token(可见):您在响应中看到的总结思考token
  • 无费用:用于生成总结的token
计费的输出token计数将不匹配响应中可见的token计数。您为完整的思考过程付费,而不是您看到的总结。

扩展思考的最佳实践和考虑因素

使用思考预算

  • 预算优化:最小预算是1,024个token。我们建议从最小值开始,逐步增加思考预算以找到您用例的最佳范围。更高的token计数能够进行更全面的推理,但根据任务的不同,收益递减。增加预算可以以增加延迟为代价提高响应质量。对于关键任务,测试不同设置以找到最佳平衡。请注意,思考预算是目标而不是严格限制——实际token使用可能根据任务而变化。
  • 起点:对于复杂任务,从较大的思考预算(16k+ token)开始,并根据您的需要进行调整。
  • 大预算:对于超过32k的思考预算,我们建议使用批处理以避免网络问题。推动模型思考超过32k token的请求会导致长时间运行的请求,可能遇到系统超时和开放连接限制。
  • Token使用跟踪:监控思考token使用以优化成本和性能。

性能考虑

  • 响应时间:由于推理过程需要额外处理,准备好可能更长的响应时间。考虑到生成思考块可能增加整体响应时间。
  • 流式要求:当max_tokens大于21,333时需要流式传输。流式传输时,准备好处理到达的思考和文本内容块。

功能兼容性

  • 思考与temperaturetop_k修改以及强制工具使用不兼容。
  • 当启用思考时,您可以将top_p设置为1到0.95之间的值。
  • 当启用思考时,您不能预填充响应。
  • 思考预算的更改会使包含消息的缓存提示前缀失效。但是,当思考参数更改时,缓存的系统提示和工具定义将继续工作。

使用指南

  • 任务选择:对特别复杂的任务使用扩展思考,这些任务受益于逐步推理,如数学、编码和分析。
  • 上下文处理:您不需要自己移除先前的思考块。Claude API自动忽略先前轮次的思考块,它们在计算上下文使用时不包括在内。
  • 提示工程:如果您想最大化Claude的思考能力,请查看我们的扩展思考提示技巧

下一步