Abbiamo aggiornato l'interfaccia compatibile con OpenAI con ottimizzazioni più approfondite specificamente per i modelli della serie Claude. Ora puoi controllare il thinking e il caching in modo più preciso e comodo. Il thinking intercalato nelle conversazioni multi-turno è ora più semplice da usare e consente un'integrazione senza interruzioni senza parametri aggiuntivi. Supporta inoltre l'attivazione delle funzionalità beta offerte da Anthropic.
1. Thinking del modello (Extended Thinking)
1.1 Vantaggi del thinking intercalato
Quando il thinking intercalato non è attivo, il modello esegue il thinking una sola volta all'inizio del turno dell'assistente; le risposte successive vengono generate direttamente dopo la ricezione dei risultati degli strumenti, senza produrre nuovi blocchi di thinking:
User → [Thinking] → Tool Call → Tool Result → Response
Quando il thinking intercalato è attivo, il modello inserisce un nuovo blocco di thinking ogni volta che riceve un risultato di uno strumento, formando una catena di ragionamento:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Questo consente al modello di:
- eseguire un ragionamento secondario basato sui risultati degli strumenti, anziché limitarsi a concatenare gli output.
- concatenare il ragionamento tra più chiamate di strumenti, dove ogni decisione si basa sull'analisi del passaggio precedente.
Riferimento: Anthropic Interleaved Thinking
1.2 Attivazione del thinking
Puoi attivare il thinking in quattro modi, scegliendone uno qualsiasi:
| Metodo | Esempio | Descrizione |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Parametro standard di OpenAI, posizionato al primo livello del corpo della richiesta |
reasoning.effort |
"reasoning": {"effort": "low"} |
Equivalente al metodo precedente, posizionato all'interno dell'oggetto reasoning |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Controlla con precisione il numero massimo di token per il thinking |
Nome del modello con -think |
"model": "claude-sonnet-4-5-think" |
Il modo più semplice, non richiede parametri aggiuntivi |
Priorità (quando si usano più metodi):reasoning_effort>reasoning.max_tokens>reasoning.effort> suffisso-think
Valori possibili per effort: minimal / low / medium / high / xhigh
1.3 Restituzione del thinking
Il messaggio di risposta include due nuovi campi:
reasoning_content: contenuto del thinking (stringa), per una facile visualizzazione.reasoning_details: informazioni strutturate complete sul thinking, che devono essere restituite così come sono nelle conversazioni multi-turno; la struttura interna può variare tra i provider.
Esempio di risposta non in streaming (campi non pertinenti omessi):
{
"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..."
}
}
}]
}
Nelle risposte in streaming, il contenuto del thinking viene inviato a blocchi tramite delta.reasoning_content e delta.reasoning_details. Per la logica completa di concatenazione in streaming, consulta l'esempio completo sotto.
1.4 Conservazione del thinking nelle conversazioni multi-turno (il thinking intercalato è integrato, non servono parametri aggiuntivi)
Per consentire al modello di continuare le proprie capacità di ragionamento nelle conversazioni multi-turno, inserisci semplicemente i reasoning_details restituiti in precedenza così come sono nel messaggio dell'assistente del turno successivo:
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"}',
}
]
AIHubMix attiva automaticamente il thinking intercalato quando rileva informazioni di thinking storiche nella richiesta, consentendo al modello di continuare il ragionamento approfondito dopo aver ricevuto i risultati delle chiamate di strumenti, senza parametri aggiuntivi.
1.5 Esempio completo
I due esempi seguenti mostrano il processo completo multi-turno di Tool Call + thinking intercalato: richiesta dell'utente → il modello ragiona e chiama uno strumento → inserimento dei risultati dello strumento (conservando i reasoning_details) → il modello, con thinking intercalato, fornisce la risposta finale.
Non in streaming · Thinking intercalato
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})
In streaming · Thinking intercalato
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 Regole di mappatura dell'intensità del thinking
Modalità Effort:
- Opus 4.6 / Sonnet 4.6 e successivi: viene mappato al livello di effort nativo di Anthropic Adaptive Thinking.
- Altri modelli: calcolato con la formula per
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 |
Mappatura dell'effort per Adaptive Thinking:
| Effort in ingresso | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Modalità max_tokens: assegnato direttamente come budget_tokens di Anthropic.
Suffisso -think: Opus/Sonnet 4.6+ usa adaptive thinking (effort=medium); gli altri modelli impostano budget_tokens = min(10240, max_tokens - 1), con un max_tokens predefinito di 4096.
2. Prompt Caching
Puoi usare il Prompt Caching quando effettui richieste ai modelli Claude tramite l'interfaccia Chat. Impostando i punti di interruzione cache_control nei messaggi, grandi blocchi di testo (come schede di ruolo, dati RAG, capitoli di libri, ecc.) possono essere memorizzati nella cache per il riutilizzo, consentendo alle richieste successive di sfruttare direttamente la cache e ridurre significativamente i costi.
Documentazione ufficiale di Claude: Prompt Caching
2.1 Costi della cache
| Operazione | Moltiplicatore di prezzo (rispetto al prezzo di input originale) |
|---|---|
| Scrittura in cache (TTL di 5 minuti) | 1.25x |
| Scrittura in cache (TTL di 1 ora) | 2x |
| Lettura dalla cache | 0.1x |
2.2 Modelli supportati e lunghezza minima della cache
| Modello | Numero minimo di token in 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 (deprecato) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (deprecato) / Haiku 3 | 2048 |
Limite al numero di punti di interruzione: un massimo di 4 punti di interruzione cache_control per richiesta.2.3 TTL della cache
| TTL | Sintassi | Scenari applicabili |
|---|---|---|
| 5 minuti (predefinito) | "cache_control": {"type": "ephemeral"} |
Sessioni brevi, richieste di routine |
| 1 ora | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Sessioni lunghe, per evitare scritture ripetute in cache |
I costi di scrittura per il TTL di 1 ora sono più alti, ma possono far risparmiare la spesa complessiva riducendo le scritture ripetute nelle sessioni lunghe. Tutti i modelli Claude dalla versione 4.5 in poi, di tutti i provider (inclusi Anthropic, Amazon Bedrock, Google Vertex AI), supportano il TTL di 1 ora.
2.4 Utilizzo
Puoi impostare i punti di interruzione della cache usando il campo cache_control in system, user (incluse le immagini) e tools. Gli esempi seguenti mostrano solo la struttura principale, omettendo i grandi blocchi di testo.
Cache del messaggio di sistema (TTL predefinito di 5 minuti):
{
"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 del messaggio utente (TTL di 1 ora):
{
"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 del messaggio con immagini:
{
"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 della definizione degli strumenti:
cache_control è posizionato al primo livello dell'oggetto tool (accanto a 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 Visualizzazione dello stato della cache
Il campo usage della risposta restituisce claude_cache_tokens_details, che registra le informazioni dettagliate sulla cache:
Prima richiesta (creazione della 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
}
}
}
Richieste successive (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 | Significato |
|---|---|
cache_creation_input_tokens |
Numero di token scritti in cache in questa richiesta |
cache_read_input_tokens |
Numero di token letti dalla cache in questa richiesta |
cache_write_5_minutes_input_tokens |
Numero di token scritti nella cache con TTL di 5 minuti |
cache_write_1_hour_input_tokens |
Numero di token scritti nella cache con TTL di 1 ora |
prompt_tokens_details.cached_tokens |
Numero di token in cache quando la cache viene utilizzata, compatibile con il formato OpenAI |
3. Header della richiesta anthropic-beta
Puoi attivare le funzionalità beta del modello Claude tramite l'header HTTP anthropic-beta, che AIHubMix inoltra all'API di Anthropic.
Utilizzo
Aggiungi anthropic-beta all'header della richiesta, con come valore l'identificatore della funzionalità beta corrispondente:
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"}]}
]
}'
Per gli identificatori beta disponibili, consulta la documentazione dell'API di Anthropic.
Ultimo aggiornamento: 2026-06-01



