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 com múltiplos turnos ficou mais fácil de usar, permitindo uma integração perfeita sem parâmetros adicionais. Também é possível ativar os recursos beta oferecidos pela Anthropic.
1. Pensamento do Modelo (Extended Thinking)
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 um turno do assistente; as respostas seguintes são geradas diretamente após o recebimento dos resultados das ferramentas, 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 a cada vez que recebe um resultado de ferramenta, formando uma cadeia de raciocínio:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Isso permite que o modelo:
- Realize raciocínio secundário com base nos resultados das ferramentas, em vez de simplesmente concatenar as saídas.
- Encadeie o raciocínio entre múltiplas chamadas de ferramentas, em que cada decisão se baseia na análise do passo anterior.
Referência: Anthropic Interleaved Thinking
1.2 Ativando o Pensamento
Você pode ativar o pensamento de quatro maneiras, escolhendo qualquer uma delas:
| Método | Exemplo | Descrição |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Parâmetro padrão do OpenAI, colocado no nível superior do corpo da requisição |
reasoning.effort |
"reasoning": {"effort": "low"} |
Equivalente ao método anterior, colocado dentro do objeto reasoning |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Controla com precisão o número máximo de tokens para o pensamento |
Nome do modelo com -think |
"model": "claude-sonnet-4-5-think" |
A forma mais simples, não exige parâmetros adicionais |
Prioridade (quando vários métodos são usados):reasoning_effort>reasoning.max_tokens>reasoning.effort> sufixo-think
Valores possíveis para effort: 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 exibição fácil.reasoning_details: Informações estruturadas completas sobre o pensamento, que precisam ser devolvidas exatamente como estão em conversas com múltiplos turnos; a estrutura interna pode variar entre provedores.
Exemplo de resposta sem streaming (omitindo campos não relacionados):
{
"choices": [{
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"reasoning_content": "The user is just saying hello...",
"reasoning_details": {
"type": "thinking",
"thinking": "The user is just saying hello...",
"signature": "Er8CCkYI..."
}
}
}]
}
Em respostas em streaming, o conteúdo do pensamento será enviado em partes por meio de delta.reasoning_content e delta.reasoning_details. Para a lógica completa de concatenação em streaming, consulte o exemplo completo abaixo.
1.4 Mantendo o Pensamento em Conversas com Múltiplos Turnos (O pensamento intercalado já está integrado, sem parâmetros adicionais)
Para que o modelo continue usando suas capacidades de raciocínio em conversas com múltiplos turnos, basta incluir o reasoning_details retornado anteriormente exatamente como está na mensagem do assistente do turno seguinte:
messages = [
{"role": "user", "content": "What's the weather like in 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"}',
}
]
A AIHubMix ativa automaticamente o pensamento intercalado quando detecta informações de pensamento anteriores na requisição, permitindo que o modelo continue o raciocínio profundo após receber resultados de chamadas de ferramentas, sem exigir parâmetros adicionais.
1.5 Exemplo Completo
Os dois exemplos a seguir demonstram o processo completo de chamada de ferramenta em múltiplos turnos com pensamento intercalado: consulta do usuário → o modelo pensa e chama uma ferramenta → inserção dos resultados da ferramenta (preservando reasoning_details) → o modelo pensa de forma intercalada e dá a resposta final.
Sem 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-***"),
)
# ── Tool definition ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"required": ["location"]
}
}
}]
# ── Mock tool execution ───────────────────────────────────────
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 "{}"
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {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
# Print thinking process
if msg.reasoning_content:
label = "Interleaved Thinking" if turn > 1 else "Thinking"
print(f"[{label}] {msg.reasoning_content}")
# Print response content
if msg.content:
print(f"[Response] {msg.content}")
# Print tool calls
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Tool Call: {tc.function.name}] {tc.function.arguments}")
# Build assistant message, preserve reasoning_details (critical!)
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 # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not msg.tool_calls:
break
# Execute tools and append results to messages
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Tool Result: {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
Com 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-***"),
)
# ── Tool definition & mock execution ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"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 "{}"
# ── Stream response collector ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Stream response, print thinking/content in real-time, accumulate reasoning_details/tool_calls."""
rd = {} # accumulated reasoning_details
content = "" # accumulated response text
tc_map = {} # accumulated tool_calls (by index)
cur = "none" # current output section: 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
# ── Handle thinking ──
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
# Print thinking chunks in real-time
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Interleaved Thinking" if turn > 1 else "Thinking"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Handle content ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Response] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Handle 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 ""
# End current output section
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,
}
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Print tool calls
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Tool Call: {tc['function']['name']}] {tc['function']['arguments']}")
# Build assistant message, preserve reasoning_details (critical!)
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"] # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not result["tool_calls"]:
break
# Execute tools and append results to messages
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Tool Result: {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 Effort:
- Opus 4.6 / Sonnet 4.6 e superiores: mapeia para o nível de effort nativo do Adaptive Thinking da Anthropic.
- Outros modelos: calculado pela fórmula de
budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| effort | effort_ratio |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Mapeamento de Effort do Adaptive Thinking:
| Effort recebido | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Modo max_tokens: atribuído diretamente como budget_tokens da Anthropic.
Sufixo -think Opus/Sonnet 4.6+ usa adaptive thinking (effort=medium); os demais modelos definem budget_tokens = min(10240, max_tokens - 1), com max_tokens padrão de 4096.
2. Cache de Prompts
Você pode usar o Prompt Caching ao fazer requisições ao modelo Claude pela interface de Chat. Ao definir pontos de interrupção cache_control nas mensagens, blocos grandes de texto (como cartões de personagem, dados de RAG, capítulos de livros etc.) podem ser armazenados em cache para reutilização, permitindo que as requisições seguintes acessem o cache diretamente e reduzam significativamente os custos.
Documentação Oficial do Claude: Prompt Caching
2.1 Custos de Cache
| Operação | Multiplicador de preço (em relação ao preço original de entrada) |
|---|---|
| Escrita em cache (TTL de 5 minutos) | 1.25x |
| Escrita em cache (TTL de 1 hora) | 2x |
| Leitura do cache | 0.1x |
2.2 Modelos Suportados e Tamanho Mínimo do Cache
| Modelo | Quantidade mínima de tokens em 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 (descontinuado) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (descontinuado) / Haiku 3 | 2048 |
Limite de quantidade de breakpoints: no máximo 4 breakpoints cache_control por requisição.2.3 TTL do Cache
| TTL | Sintaxe | Cenários aplicáveis |
|---|---|---|
| 5 minutos (padrão) | "cache_control": {"type": "ephemeral"} |
Sessões curtas e requisições rotineiras |
| 1 hora | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Sessões longas, para evitar escritas repetidas no cache |
Os custos de escrita para o TTL de 1 hora são mais altos, mas podem reduzir o gasto total ao diminuir as escritas repetidas em sessões longas. Todos os modelos do Claude 4.5 em diante, de todos os provedores (incluindo Anthropic, Amazon Bedrock e Google Vertex AI), suportam TTL de 1 hora.
2.4 Uso
Você pode definir breakpoints de cache usando o campo cache_control em system, user (incluindo imagens) e tools. Os exemplos a seguir mostram apenas a estrutura principal, omitindo blocos grandes de texto.
Cache de mensagem de sistema (TTL padrão de 5 minutos):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Hello"}]
}
]
}
Cache de mensagem do usuário (TTL de 1 hora):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "You are an AI assistant"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Hello"}
]
}
]
}
Cache de mensagem com 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": "What's this?"}
]
}
Cache de definição de ferramenta:
cache_control é colocado no nível superior do objeto da ferramenta (junto de type e function):
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 Verificando o Status do Cache
O campo usage da resposta retornará claude_cache_tokens_details, com informações detalhadas do cache:
Primeira requisição (criando o 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
}
}
}
Requisições seguintes (cache atingido):
{
"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 |
Quantidade de tokens gravados no cache nesta requisição |
cache_read_input_tokens |
Quantidade de tokens lidos do cache nesta requisição |
cache_write_5_minutes_input_tokens |
Quantidade de tokens gravados no cache com TTL de 5 minutos |
cache_write_1_hour_input_tokens |
Quantidade de tokens gravados no cache com TTL de 1 hora |
prompt_tokens_details.cached_tokens |
Quantidade de tokens em cache quando o cache é atingido, compatível com o formato da OpenAI |
3. Cabeçalho de Requisição para anthropic-beta
Você pode ativar recursos beta do modelo Claude pelo cabeçalho HTTP anthropic-beta, que a AIHubMix repassa para a API da Anthropic.
Uso
Adicione anthropic-beta ao cabeçalho da requisiçã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": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "hello"}]}
]
}'
Para os identificadores beta disponíveis, consulte a Documentação da API da Anthropic.
Última atualização: 2026-06-01



