Atualizamos a interface compatível com OpenAI com otimizações mais profundas especificamente para os modelos da série Claude. Agora você pode controlar o pensamento e o cache de forma mais precisa e conveniente. O pensamento intercalado em conversas de múltiplas turnos agora é mais amigável ao usuário, permitindo uma integração perfeita sem parâmetros adicionais. Também suporta a ativação dos recursos beta oferecidos pela Anthropic.
1. Pensamento do Modelo (Pensamento Estendido)
1.1 Vantagens do Pensamento Intercalado
Quando o pensamento intercalado não está ativado, o modelo realiza o pensamento apenas uma vez no início de uma turnada do assistente; as respostas subsequentes são geradas diretamente após receber os resultados da ferramenta, sem produzir novos blocos de pensamento:
User → [Thinking] → Tool Call → Tool Result → Response
Quando o pensamento intercalado está ativado, o modelo insere um novo bloco de pensamento cada vez que recebe um resultado da ferramenta, formando uma cadeia de raciocínio:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Pensamento Intercalado
Isso permite que o modelo:
- Realize raciocínio secundário com base nos resultados da ferramenta, em vez de simplesmente concatenar saídas.
- Encadeie raciocínios entre múltiplas chamadas de ferramentas, onde cada decisão é baseada na análise do passo anterior.
Referência: Pensamento Intercalado da Anthropic
1.2 Habilitando o Pensamento
Você pode habilitar o pensamento de quatro maneiras, escolhendo qualquer uma delas:
| Método | Exemplo | Descrição |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Parâmetro padrão da OpenAI, colocado no nível superior do corpo da solicitação |
reasoning.effort |
"reasoning": {"effort": "low"} |
Equivalente ao método anterior, colocado dentro do objeto de raciocínio |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Controla precisamente o número máximo de tokens para o pensamento |
Nome do modelo com -think |
"model": "claude-sonnet-4-5-think" |
A maneira mais simples, não requer parâmetros adicionais |
Prioridade (quando múltiplos métodos são usados):reasoning_effort>reasoning.max_tokens>reasoning.effort>-thinksufixo
Valores possíveis para esforço: minimal / low / medium / high / xhigh
1.3 Retorno do Pensamento
A mensagem de resposta incluirá dois novos campos:
reasoning_content: Conteúdo do pensamento (string), para fácil exibição.reasoning_details: Informações estruturadas completas sobre o pensamento, que precisam ser retornadas como estão em conversas de múltiplas turnos; a estrutura interna pode diferir entre os provedores.
Exemplo não streaming (omitindo campos não relacionados):
{
"choices": [{
"message": {
"role": "assistant",
"content": "Olá! Como posso ajudá-lo hoje?",
"reasoning_content": "O usuário está apenas dizendo olá...",
"reasoning_details": {
"type": "thinking",
"thinking": "O usuário está apenas dizendo olá...",
"signature": "Er8CCkYI..."
}
}
}]
}
Em respostas streaming, o conteúdo do pensamento será enviado em partes via delta.reasoning_content e delta.reasoning_details. Para a lógica completa de concatenação streaming, consulte o exemplo completo abaixo.
1.4 Retendo o Pensamento em Conversas de Múltiplas Turnos (O Pensamento Intercalado é embutido, sem parâmetros adicionais necessários)
Para permitir que o modelo continue suas capacidades de raciocínio em conversas de múltiplas turnos, basta colocar o reasoning_details retornado anteriormente como está na mensagem do assistente da próxima rodada:
messages = [
{"role": "user", "content": "Como está o tempo em Boston?"},
{
"role": "assistant",
"content": response.choices[0].message.content,
"tool_calls": response.choices[0].message.tool_calls,
"reasoning_details": response.choices[0].message.reasoning_details,
},
{
"role": "tool",
"tool_call_id": "toolu_xxx",
"content": '{"temperature": 45, "condition": "rainy"}',
}
]
AIHubMix habilitará automaticamente o pensamento intercalado quando detectar informações históricas de pensamento na solicitação, permitindo que o modelo continue o raciocínio profundo após receber os resultados da chamada da ferramenta sem exigir parâmetros adicionais.
1.5 Exemplo Completo
Os seguintes dois exemplos demonstram o processo completo de múltiplas turnos de Chamada de Ferramenta + pensamento intercalado: consulta do usuário → modelo pensa e chama uma ferramenta → injeta resultados da ferramenta (preservando reasoning_details) → modelo pensamento intercalado dá a resposta final.
Não streaming · Pensamento Intercalado
import os
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Definição da ferramenta ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obter o clima atual para um local",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nome da cidade"}},
"required": ["location"]
}
}
}]
# ── Execução simulada da ferramenta ───────────────────────────────────────
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Loop de conversa de múltiplas turnos ─────────────────────────────
messages = [
{"role": "user", "content": "Como está o tempo em Boston? Então recomende o que vestir."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turno {turn} ──")
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
msg = response.choices[0].message
# Imprimir processo de pensamento
if msg.reasoning_content:
label = "Pensamento Intercalado" if turn > 1 else "Pensamento"
print(f"[{label}] {msg.reasoning_content}")
# Imprimir conteúdo da resposta
if msg.content:
print(f"[Resposta] {msg.content}")
# Imprimir chamadas de ferramentas
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Chamada de Ferramenta: {tc.function.name}] {tc.function.arguments}")
# Construir mensagem do assistente, preservar reasoning_details (crítico!)
assistant_msg = {"role": "assistant", "content": msg.content}
if msg.tool_calls:
assistant_msg["tool_calls"] = msg.tool_calls
if msg.reasoning_details:
assistant_msg["reasoning_details"] = msg.reasoning_details # passar de volta não modificado
messages.append(assistant_msg)
# Sem tool_calls significa que a conversa terminou
if not msg.tool_calls:
break
# Executar ferramentas e anexar resultados às mensagens
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Resultado da Ferramenta: {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
Streaming · Pensamento Intercalado
import os
import sys
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Definição da ferramenta & execução simulada ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obter o clima atual para um local",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nome da cidade"}},
"required": ["location"]
}
}
}]
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Coletor de resposta streaming ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Transmitir resposta, imprimir pensamento/conteúdo em tempo real, acumular reasoning_details/tool_calls."""
rd = {} # detalhes de raciocínio acumulados
content = "" # texto de resposta acumulado
tc_map = {} # chamadas de ferramentas acumuladas (por índice)
cur = "none" # seção de saída atual: none / thinking / content
stream = client.chat.completions.create(stream=True, **kwargs)
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
# ── Lidar com pensamento ──
rd_delta = getattr(delta, "reasoning_details", None)
if rd_delta and isinstance(rd_delta, dict):
for k, v in rd_delta.items():
if k == "type":
rd[k] = v
elif isinstance(v, str):
rd[k] = rd.get(k, "") + v
elif v is not None:
rd[k] = v
# Imprimir pedaços de pensamento em tempo real
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Pensamento Intercalado" if turn > 1 else "Pensamento"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Lidar com conteúdo ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Resposta] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Lidar com tool_calls ──
for tc in delta.tool_calls or []:
i = tc.index
if i not in tc_map:
tc_map[i] = {"id": "", "type": "function",
"function": {"name": "", "arguments": ""}}
if tc.id:
tc_map[i]["id"] = tc.id
if tc.function:
tc_map[i]["function"]["name"] += tc.function.name or ""
tc_map[i]["function"]["arguments"] += tc.function.arguments or ""
# Finalizar a seção de saída atual
if cur in ("thinking", "content"):
sys.stdout.write("\n")
tool_calls = [tc_map[i] for i in sorted(tc_map)] if tc_map else None
return {
"content": content or None,
"reasoning_details": rd or None,
"tool_calls": tool_calls,
}
# ── Loop de conversa de múltiplas turnos ─────────────────────────────
messages = [
{"role": "user", "content": "Como está o tempo em Boston? Então recomende o que vestir."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turno {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Imprimir chamadas de ferramentas
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Chamada de Ferramenta: {tc['function']['name']}] {tc['function']['arguments']}")
# Construir mensagem do assistente, preservar reasoning_details (crítico!)
assistant_msg = {"role": "assistant", "content": result["content"]}
if result["tool_calls"]:
assistant_msg["tool_calls"] = result["tool_calls"]
if result["reasoning_details"]:
assistant_msg["reasoning_details"] = result["reasoning_details"] # passar de volta não modificado
messages.append(assistant_msg)
# Sem tool_calls significa que a conversa terminou
if not result["tool_calls"]:
break
# Executar ferramentas e anexar resultados às mensagens
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Resultado da Ferramenta: {tc['function']['name']}] {tool_result}")
messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})
1.6 Regras de Mapeamento da Intensidade do Pensamento
Modo de Esforço:
- Opus 4.6 / Sonnet 4.6 e acima: mapeia para o nível de esforço Pensamento Adaptativo nativo da Anthropic.
- Outros modelos: calculado usando a fórmula para
budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| esforço | esforço_ratio |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Mapeamento de Esforço de Pensamento Adaptativo:
| Esforço de Entrada | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | máx | alto |
| high | alto | alto |
| medium | médio | médio |
| low | baixo | baixo |
| minimal | baixo | baixo |
Modo max_tokens: Atribuído diretamente como budget_tokens da Anthropic.
-think sufixo: Opus/Sonnet 4.6+ usa pensamento adaptativo (esforço=médio); outros modelos definem budget_tokens = min(10240, max_tokens - 1), com um max_tokens padrão de 4096.
2. Cache de Prompt
Você pode usar o Cache de Prompt ao fazer solicitações ao modelo Claude via a interface de Chat. Ao definir pontos de interrupção cache_control nas mensagens, grandes blocos de texto (como cartões de função, dados RAG, capítulos de livros, etc.) podem ser armazenados em cache para reutilização, permitindo que solicitações subsequentes acessem o cache diretamente e reduzam significativamente os custos.
Documentação Oficial do Claude: Cache de Prompt
2.1 Custos de Cache
| Operação | Multiplicador de Preço (relativo ao preço de entrada original) |
|---|---|
| Gravação de Cache (TTL de 5 minutos) | 1.25x |
| Gravação de Cache (TTL de 1 hora) | 2x |
| Leitura de Cache | 0.1x |
2.2 Modelos Suportados e Comprimento Mínimo do Cache
| Modelo | Contagem Mínima de Tokens de Cache |
|---|---|
| Claude Opus 4.8 | 1024 |
| Claude Opus 4.7 | 2048 |
| Claude Opus 4.6 / Opus 4.5 | 4096 |
| Claude Sonnet 4.6 / Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4 / Sonnet 3.7 (obsoleto) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (obsoleto) / Haiku 3 | 2048 |
Limite de Quantidade de Pontos de Interrupção: Um máximo de 4 cache_control pontos de interrupção por solicitação.2.3 TTL de Cache
| TTL | Sintaxe | Cenários Aplicáveis |
|---|---|---|
| 5 minutos (padrão) | "cache_control": {"type": "ephemeral"} |
Sessões curtas, solicitações rotineiras |
| 1 hora | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Sessões longas, para evitar gravações repetidas de cache |
Os custos de gravação para TTL de 1 hora são mais altos, mas podem economizar despesas totais ao reduzir gravações repetidas em sessões longas. Todos os modelos a partir do Claude 4.5 e posteriores de todos os provedores (incluindo Anthropic, Amazon Bedrock, Google Vertex AI) suportam TTL de 1 hora.
2.4 Uso
Você pode definir pontos de interrupção de cache usando o campo cache_control em system, user (incluindo imagens) e tools. Os seguintes exemplos mostram apenas a estrutura da chave, omitindo grandes blocos de texto.
Cache de Mensagem do Sistema (TTL padrão de 5 minutos):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Você é um assistente de IA"},
{
"type": "text",
"text": "(contexto longo)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Olá"}]
}
]
}
Cache de Mensagem do Usuário (TTL de 1 hora):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "Você é um assistente de IA"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(contexto longo)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Olá"}
]
}
]
}
Cache de Mensagem de Imagem:
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "O que é isso?"}
]
}
Cache de Definição da Ferramenta:
cache_control é colocado no nível superior do objeto da ferramenta (junto com type e function):
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obter o clima atual para um local",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 Visualizando o Status do Cache
O usage da resposta retornará claude_cache_tokens_details, registrando informações detalhadas do cache:
Primeira Solicitação (Criando Cache):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 890,
"total_tokens": 912,
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 6266,
"cache_read_input_tokens": 0,
"cache_write_5_minutes_input_tokens": 6266,
"cache_write_1_hour_input_tokens": 0
}
}
}
Solicitações Subsequentes (Cache Hit):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 810,
"total_tokens": 832,
"prompt_tokens_details": {
"cached_tokens": 6266
},
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 6266,
"cache_write_5_minutes_input_tokens": 0,
"cache_write_1_hour_input_tokens": 0
}
}
}
| Campo | Significado |
|---|---|
cache_creation_input_tokens |
Número de tokens gravados no cache nesta solicitação |
cache_read_input_tokens |
Número de tokens lidos do cache nesta solicitação |
cache_write_5_minutes_input_tokens |
Número de tokens gravados no cache de TTL de 5 minutos |
cache_write_1_hour_input_tokens |
Número de tokens gravados no cache de TTL de 1 hora |
prompt_tokens_details.cached_tokens |
Número de tokens em cache quando o cache é acessado, compatível com o formato da OpenAI |
3. Cabeçalho de Solicitação para anthropic-beta
Você pode habilitar recursos beta do modelo Claude através do Cabeçalho HTTP anthropic-beta, que o AIHubMix passará para a API da Anthropic.
Uso
Adicione anthropic-beta ao cabeçalho da solicitação, com o valor sendo o identificador do recurso beta correspondente:
curl "https://aihubmix.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AIHUBMIX_API_KEY" \
-H "anthropic-beta: context-1m-2025-08-07" \
-d '{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Você é um assistente de IA"},
{
"type": "text",
"text": "(contexto longo)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "olá"}]}
]
}'
Para identificadores beta específicos disponíveis, consulte a Documentação da API da Anthropic.
Última atualização: 2026-06-01