We hebben de OpenAI-compatibele interface geüpgraded met diepere optimalisaties specifiek voor de Claude-modellenreeks. Je kunt nu het denkproces en de caching preciezer en handiger regelen. Verweven redenering in meerdelige gesprekken is nu gebruiksvriendelijker en maakt naadloze integratie mogelijk zonder extra parameters. Ook het inschakelen van de bètafuncties die Anthropic aanbiedt, wordt ondersteund.
1. Denken van het model (Extended Thinking)
1.1 Voordelen van verweven redenering
Wanneer verweven redenering niet is ingeschakeld, voert het model slechts één keer aan het begin van een assistentbeurt redenering uit; vervolgantwoorden worden direct gegenereerd nadat toolresultaten zijn ontvangen, zonder nieuwe denkblokken te produceren:
User → [Thinking] → Tool Call → Tool Result → Response
Wanneer verweven redenering is ingeschakeld, voegt het model elke keer dat het een toolresultaat ontvangt een nieuw denkblok in, waardoor een keten van redeneringen ontstaat:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Hierdoor kan het model:
- secundaire redenering uitvoeren op basis van toolresultaten, in plaats van outputs simpelweg aan elkaar te plakken.
- redeneringen koppelen over meerdere toolaanroepen heen, waarbij elke beslissing gebaseerd is op de analyse van de vorige stap.
Referentie: Anthropic Interleaved Thinking
1.2 Denken inschakelen
Je kunt denken op vier manieren inschakelen; kies er één:
| Methode | Voorbeeld | Beschrijving |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Standaard OpenAI-parameter, geplaatst op het hoogste niveau van de requestbody |
reasoning.effort |
"reasoning": {"effort": "low"} |
Gelijk aan de vorige methode, geplaatst binnen het reasoning-object |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Bepaalt nauwkeurig het maximale aantal tokens voor denken |
Modelnaam met -think |
"model": "claude-sonnet-4-5-think" |
De eenvoudigste manier; er zijn geen extra parameters nodig |
Prioriteit (wanneer meerdere methoden worden gebruikt):reasoning_effort>reasoning.max_tokens>reasoning.effort>-think-suffix
Mogelijke waarden voor effort: minimal / low / medium / high / xhigh
1.3 Teruggave van denken
Het antwoordbericht bevat twee nieuwe velden:
reasoning_content: Inhoud van het denken (string), voor eenvoudige weergave.reasoning_details: Volledige gestructureerde informatie over het denken, die ongewijzigd moet worden teruggestuurd in meerdelige gesprekken; de interne structuur kan per provider verschillen.
Voorbeeld zonder streaming (irrelevante velden weggelaten):
{
"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..."
}
}
}]
}
In streamingantwoorden wordt de inhoud van het denken in stukken verzonden via delta.reasoning_content en delta.reasoning_details. Voor de volledige logica om de stukken samen te voegen, zie het volledige voorbeeld hieronder.
1.4 Denken behouden in meerdelige gesprekken (verweven redenering is ingebouwd, er zijn geen extra parameters nodig)
Om het model zijn redeneervermogen te laten behouden in meerdelige gesprekken, plaats je de eerder teruggegeven reasoning_details ongewijzigd in het assistentbericht van de volgende ronde:
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 schakelt verweven redenering automatisch in wanneer het historische denkinformatie in het verzoek detecteert, zodat het model na ontvangst van toolaanroepresultaten diep kan blijven redeneren zonder extra parameters.
1.5 Volledig voorbeeld
De volgende twee voorbeelden tonen het volledige meerdelige proces van toolaanroep + verweven redenering: vraag van de gebruiker → model denkt en roept een tool aan → toolresultaten invoegen (met behoud van reasoning_details) → model geeft via verweven redenering het definitieve antwoord.
Zonder streaming · Verweven redenering
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})
Met streaming · Verweven redenering
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 Regels voor de intensiteit van het denken
Effortmodus:
- Opus 4.6 / Sonnet 4.6 en hoger: wordt gekoppeld aan het native Adaptive Thinking-effortniveau van Anthropic.
- Overige modellen: berekend met de formule voor
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 |
Toewijzing van Adaptive Thinking-effort:
| Binnenkomende effort | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
max_tokens-modus: wordt rechtstreeks toegewezen als Anthropic's budget_tokens.
-think suffix: Opus/Sonnet 4.6+ gebruikt adaptive thinking (effort=medium); andere modellen stellen budget_tokens = min(10240, max_tokens - 1) in, met een standaardwaarde van max_tokens van 4096.
2. Prompt Caching
Je kunt Prompt Caching gebruiken bij het doen van verzoeken aan het Claude-model via de Chat-interface. Door cache_control-breekpunten in berichten in te stellen, kunnen grote tekstblokken (zoals rolbeschrijvingen, RAG-data, boekhoofdstukken, enz.) worden gecachet voor hergebruik, zodat volgende verzoeken direct de cache raken en de kosten aanzienlijk worden verlaagd.
Officiële Claude-documentatie: Prompt Caching
2.1 Cachekosten
| Handeling | Prijsvermenigvuldiger (ten opzichte van de oorspronkelijke inputprijs) |
|---|---|
| Cache schrijven (TTL van 5 minuten) | 1.25x |
| Cache schrijven (TTL van 1 uur) | 2x |
| Cache lezen | 0.1x |
2.2 Ondersteunde modellen en minimale cachelengte
| Model | Minimaal aantal cachetokens |
|---|---|
| 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 (verouderd) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (verouderd) / Haiku 3 | 2048 |
Limiet voor aantal breekpunten: maximaal 4 cache_control-breekpunten per verzoek.2.3 Cache-TTL
| TTL | Syntaxis | Toepassingsscenario's |
|---|---|---|
| 5 minuten (standaard) | "cache_control": {"type": "ephemeral"} |
Korte sessies, routineverzoeken |
| 1 uur | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Lange sessies, om herhaald cache schrijven te vermijden |
De schrijfkosten voor een TTL van 1 uur zijn hoger, maar ze kunnen de totale kosten verlagen doordat er bij lange sessies minder herhaald wordt geschreven. Alle modellen vanaf Claude 4.5 en later van alle providers (waaronder Anthropic, Amazon Bedrock, Google Vertex AI) ondersteunen een TTL van 1 uur.
2.4 Gebruik
Je kunt cachebreekpunten instellen met het veld cache_control in system, user (inclusief afbeeldingen) en tools. De volgende voorbeelden tonen alleen de belangrijkste structuur, zonder grote tekstblokken.
Caching van systeembericht (standaard TTL van 5 minuten):
{
"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"}]
}
]
}
Caching van gebruikersbericht (TTL van 1 uur):
{
"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"}
]
}
]
}
Caching van afbeeldingsbericht:
{
"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?"}
]
}
Caching van tooldefinitie:
cache_control wordt op het hoogste niveau van het toolobject geplaatst (naast type en 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 Cachestatus bekijken
De usage van het antwoord geeft claude_cache_tokens_details terug, met gedetailleerde cacheinformatie:
Eerste verzoek (cache aanmaken):
{
"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
}
}
}
Volgende verzoeken (cachetreffer):
{
"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
}
}
}
| Veld | Betekenis |
|---|---|
cache_creation_input_tokens |
Aantal tokens dat in dit verzoek naar de cache is geschreven |
cache_read_input_tokens |
Aantal tokens dat in dit verzoek uit de cache is gelezen |
cache_write_5_minutes_input_tokens |
Aantal tokens dat is geschreven naar de cache met een TTL van 5 minuten |
cache_write_1_hour_input_tokens |
Aantal tokens dat is geschreven naar de cache met een TTL van 1 uur |
prompt_tokens_details.cached_tokens |
Aantal gecachete tokens bij een cachetreffer, compatibel met het OpenAI-formaat |
3. Requestheader voor anthropic-beta
Je kunt bètafuncties van het Claude-model inschakelen via de HTTP-header anthropic-beta; AIHubMix geeft deze door aan de Anthropic API.
Gebruik
Voeg anthropic-beta toe aan de requestheader, met als waarde de bijbehorende identifier van de bètafunctie:
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"}]}
]
}'
Voor de specifieke beschikbare bèta-identifiers, zie de Anthropic API-documentatie.
Laatst bijgewerkt: 2026-06-01



