Ulepszyliśmy interfejs kompatybilny z OpenAI, wprowadzając głębsze optymalizacje dedykowane modelom z serii Claude. Teraz możesz precyzyjniej i wygodniej kontrolować myślenie oraz buforowanie. Przeplatane myślenie w rozmowach wieloetapowych jest teraz bardziej przyjazne dla użytkownika i pozwala na bezproblemową integrację bez dodatkowych parametrów. Obsługiwane jest także włączanie funkcji beta oferowanych przez Anthropic.
1. Myślenie modelu (Extended Thinking)
1.1 Zalety przeplatanego myślenia
Gdy przeplatane myślenie nie jest włączone, model wykonuje myślenie tylko raz, na początku tury asystenta; kolejne odpowiedzi są generowane bezpośrednio po otrzymaniu wyników narzędzi, bez tworzenia nowych bloków myślenia:
User → [Thinking] → Tool Call → Tool Result → Response
Gdy przeplatane myślenie jest włączone, model wstawia nowy blok myślenia za każdym razem, gdy otrzymuje wynik narzędzia, tworząc łańcuch rozumowania:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Dzięki temu model potrafi:
- Przeprowadzić wtórne rozumowanie na podstawie wyników narzędzi, zamiast po prostu łączyć wyniki.
- Łączyć rozumowanie między wieloma wywołaniami narzędzi, gdzie każda decyzja opiera się na analizie poprzedniego kroku.
Źródło: Anthropic Interleaved Thinking
1.2 Włączanie myślenia
Myślenie możesz włączyć na cztery sposoby, wybierając dowolny z nich:
| Metoda | Przykład | Opis |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Standardowy parametr OpenAI, umieszczany na najwyższym poziomie treści żądania |
reasoning.effort |
"reasoning": {"effort": "low"} |
Odpowiednik poprzedniej metody, umieszczany w obiekcie reasoning |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Precyzyjnie kontroluje maksymalną liczbę tokenów przeznaczonych na myślenie |
Nazwa modelu z sufiksem -think |
"model": "claude-sonnet-4-5-think" |
Najprostszy sposób, nie wymaga dodatkowych parametrów |
Priorytet (gdy używanych jest wiele metod):reasoning_effort>reasoning.max_tokens>reasoning.effort> sufiks-think
Możliwe wartości effort: minimal / low / medium / high / xhigh
1.3 Zwracanie myślenia
Wiadomość odpowiedzi zawiera dwa nowe pola:
reasoning_content: treść myślenia (ciąg znaków), ułatwiająca wyświetlanie.reasoning_details: kompletne, ustrukturyzowane informacje o myśleniu, które należy zwracać bez zmian w rozmowach wieloetapowych; wewnętrzna struktura może różnić się między dostawcami.
Przykład odpowiedzi bez strumieniowania (pominięto niezwiązane pola):
{
"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..."
}
}
}]
}
W odpowiedziach strumieniowanych treść myślenia wysyłana jest fragmentami przez delta.reasoning_content i delta.reasoning_details. Pełną logikę łączenia fragmentów w strumieniu znajdziesz w poniższym kompletnym przykładzie.
1.4 Zachowywanie myślenia w rozmowach wieloetapowych (przeplatane myślenie jest wbudowane, nie wymaga dodatkowych parametrów)
Aby model mógł kontynuować rozumowanie w rozmowach wieloetapowych, wystarczy umieścić wcześniej zwrócone reasoning_details bez zmian w wiadomości asystenta z następnej rundy:
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 automatycznie włączy przeplatane myślenie, gdy wykryje w żądaniu historyczne informacje o myśleniu, dzięki czemu model będzie mógł kontynuować głębokie rozumowanie po otrzymaniu wyników wywołań narzędzi, bez dodatkowych parametrów.
1.5 Kompletny przykład
Poniższe dwa przykłady pokazują pełny proces wieloetapowego wywołania narzędzi z przeplatanym myśleniem: zapytanie użytkownika → model myśli i wywołuje narzędzie → wstrzyknięcie wyników narzędzia (z zachowaniem reasoning_details) → model, dzięki przeplatanemu myśleniu, udziela końcowej odpowiedzi.
Bez strumieniowania · przeplatane myślenie
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})
Strumieniowanie · przeplatane myślenie
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 Zasady mapowania intensywności myślenia
Tryb effort:
- Opus 4.6 / Sonnet 4.6 i nowsze: mapowane na natywny poziom effort Adaptive Thinking firmy Anthropic.
- Inne modele: obliczane według wzoru dla
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 |
Mapowanie effort dla Adaptive Thinking:
| Przychodzący effort | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Tryb max_tokens: wartość jest przekazywana bezpośrednio jako budget_tokens Anthropic.
-think sufiks: Opus/Sonnet 4.6+ korzysta z adaptacyjnego myślenia (effort=medium); pozostałe modele ustawiają budget_tokens = min(10240, max_tokens - 1), przy domyślnym max_tokens wynoszącym 4096.
2. Buforowanie promptów
Buforowanie promptów możesz wykorzystać przy wysyłaniu żądań do modelu Claude przez interfejs Chat. Ustawiając punkty kontrolne cache_control w wiadomościach, duże bloki tekstu (jak karty ról, dane RAG, rozdziały książek itp.) mogą zostać zbuforowane do ponownego użycia, dzięki czemu kolejne żądania trafiają bezpośrednio do bufora, co znacząco obniża koszty.
Oficjalna dokumentacja Claude: Buforowanie promptów
2.1 Koszty buforowania
| Operacja | Mnożnik ceny (w stosunku do oryginalnej ceny wejścia) |
|---|---|
| Zapis do bufora (TTL 5 minut) | 1.25x |
| Zapis do bufora (TTL 1 godzina) | 2x |
| Odczyt z bufora | 0.1x |
2.2 Obsługiwane modele i minimalna długość bufora
| Model | Minimalna liczba tokenów do buforowania |
|---|---|
| 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 (wycofany) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (wycofany) / Haiku 3 | 2048 |
Limit punktów kontrolnych: maksymalnie 4 punkty cache_control na żądanie.2.3 TTL bufora
| TTL | Składnia | Zastosowania |
|---|---|---|
| 5 minut (domyślnie) | "cache_control": {"type": "ephemeral"} |
Krótkie sesje, rutynowe żądania |
| 1 godzina | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Długie sesje, aby uniknąć powtarzających się zapisów do bufora |
Koszty zapisu dla TTL 1 godziny są wyższe, ale mogą obniżyć łączne wydatki dzięki ograniczeniu powtarzających się zapisów w długich sesjach. Wszystkie modele Claude 4.5 i nowsze, od wszystkich dostawców (w tym Anthropic, Amazon Bedrock, Google Vertex AI), obsługują TTL 1 godzina.
2.4 Użycie
Punkty buforowania ustawiasz za pomocą pola cache_control w system, user (w tym w obrazach) oraz tools. Poniższe przykłady pokazują tylko strukturę kluczy, bez dużych bloków tekstu.
Buforowanie wiadomości systemowej (domyślnie TTL 5 minut):
{
"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"}]
}
]
}
Buforowanie wiadomości użytkownika (TTL 1 godzina):
{
"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"}
]
}
]
}
Buforowanie wiadomości z obrazem:
{
"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?"}
]
}
Buforowanie definicji narzędzi:
cache_control umieszczane jest na najwyższym poziomie obiektu narzędzia (obok type i 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 Sprawdzanie stanu bufora
Pole usage w odpowiedzi zwróci claude_cache_tokens_details, zawierające szczegółowe informacje o buforze:
Pierwsze żądanie (tworzenie bufora):
{
"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
}
}
}
Kolejne żądania (trafienie w bufor):
{
"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
}
}
}
| Pole | Znaczenie |
|---|---|
cache_creation_input_tokens |
Liczba tokenów zapisanych do bufora w tym żądaniu |
cache_read_input_tokens |
Liczba tokenów odczytanych z bufora w tym żądaniu |
cache_write_5_minutes_input_tokens |
Liczba tokenów zapisanych do bufora o TTL 5 minut |
cache_write_1_hour_input_tokens |
Liczba tokenów zapisanych do bufora o TTL 1 godzina |
prompt_tokens_details.cached_tokens |
Liczba tokenów z bufora w przypadku trafienia, zgodna z formatem OpenAI |
3. Nagłówek żądania anthropic-beta
Funkcje beta modelu Claude możesz włączyć za pomocą nagłówka HTTP anthropic-beta, który AIHubMix przekaże bez zmian do API Anthropic.
Użycie
Dodaj anthropic-beta do nagłówka żądania, z wartością będącą odpowiednim identyfikatorem funkcji beta:
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"}]}
]
}'
Aktualne identyfikatory funkcji beta znajdziesz w dokumentacji API Anthropic.
Ostatnia aktualizacja: 2026-06-01



