Обновихме OpenAI съвместимия интерфейс с по-дълбоки оптимизации, специално за моделите от серията Claude. Вече можете да управлявате разсъжденията и кеширането по-прецизно и удобно. Преплетеното разсъждение в многоетапни разговори е по-лесно за използване и позволява безпроблемна интеграция без допълнителни параметри. Поддържа се и активирането на бета функциите, предлагани от Anthropic.
1. Разсъждение на модела (Extended Thinking)
1.1 Предимства на преплетеното разсъждение
Когато преплетеното разсъждение не е активирано, моделът извършва разсъждение само веднъж в началото на репликата на асистента; следващите отговори се генерират директно след получаване на резултатите от инструментите, без да се създават нови блокове с разсъждения:
User → [Thinking] → Tool Call → Tool Result → Response
Когато преплетеното разсъждение е активирано, моделът вмъква нов блок с разсъждения всеки път, когато получи резултат от инструмент, образувайки верига от разсъждения:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Това позволява на модела да:
- Извършва вторично разсъждение въз основа на резултатите от инструментите, вместо просто да обединява изходните данни.
- Свързва разсъжденията между няколко извиквания на инструменти, като всяко решение се основава на анализа на предишната стъпка.
Справка: Anthropic Interleaved Thinking
1.2 Активиране на разсъждението
Можете да активирате разсъжденията по четири начина, като изберете който и да е от тях:
| Метод | Пример | Описание |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Стандартен параметър на OpenAI, поставен на най-горното ниво на тялото на заявката |
reasoning.effort |
"reasoning": {"effort": "low"} |
Еквивалентен на предишния метод, поставен в обекта reasoning |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Прецизно контролира максималния брой токени за разсъждение |
Име на модела с -think |
"model": "claude-sonnet-4-5-think" |
Най-простият начин, не изисква допълнителни параметри |
Приоритет (когато се използват няколко метода):reasoning_effort>reasoning.max_tokens>reasoning.effort> суфикс-think
Възможни стойности за effort: minimal / low / medium / high / xhigh
1.3 Връщане на разсъжденията
Отговорното съобщение ще включва две нови полета:
reasoning_content: Съдържание на разсъжденията (низ), за лесно показване.reasoning_details: Пълна структурирана информация за разсъжденията, която трябва да се връща без промени в многоетапни разговори; вътрешната структура може да се различава между доставчиците.
Пример за не-стрийминг отговор (без несвързаните полета):
{
"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..."
}
}
}]
}
При стрийминг отговорите съдържанието на разсъжденията се изпраща на части чрез delta.reasoning_content и delta.reasoning_details. За пълната логика на сглобяване при стрийминг вижте пълния пример по-долу.
1.4 Запазване на разсъжденията в многоетапни разговори (Преплетеното разсъждение е вградено, не са нужни допълнителни параметри)
За да може моделът да продължи да използва възможностите си за разсъждение в многоетапни разговори, просто поставете предварително върнатите reasoning_details без промени в съобщението на асистента за следващия рунд:
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 автоматично активира преплетеното разсъждение, когато открие исторически данни за разсъжденията в заявката, което позволява на модела да продължи дълбокото разсъждение след получаване на резултатите от извикванията на инструменти, без да се изискват допълнителни параметри.
1.5 Пълен пример
Следните два примера демонстрират пълния процес на многоетапно извикване на инструменти + преплетено разсъждение: запитване на потребителя → моделът разсъждава и извиква инструмент → вмъкване на резултатите от инструмента (със запазване на reasoning_details) → моделът, чрез преплетено разсъждение, дава окончателния отговор.
Без стрийминг · Преплетено разсъждение
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})
Стрийминг · Преплетено разсъждение
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 Правила за съпоставяне на интензитета на разсъжденията
Режим на усилие (effort):
- Opus 4.6 / Sonnet 4.6 и по-нови: съпоставя се с нативното ниво на усилие Adaptive Thinking на Anthropic.
- Други модели: изчисляват се по формулата за
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 |
Съпоставяне на усилието при Adaptive Thinking:
| Входящо усилие | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Режим max_tokens: Директно се присвоява като budget_tokens на Anthropic.
-think суфикс: Opus/Sonnet 4.6+ използва adaptive thinking (effort=medium); останалите модели задават budget_tokens = min(10240, max_tokens - 1), със стандартна стойност на max_tokens от 4096.
2. Кеширане на промптове
Можете да използвате кеширане на промптове при заявки към модела Claude чрез интерфейса Chat. Като зададете точки на прекъсване cache_control в съобщенията, големи блокове текст (като ролеви карти, RAG данни, глави от книги и др.) могат да бъдат кеширани за повторна употреба, което позволява последващите заявки да попадат директно в кеша и значително намалява разходите.
Официална документация на Claude: Prompt Caching
2.1 Разходи за кеширане
| Операция | Ценов множител (спрямо оригиналната входна цена) |
|---|---|
| Запис в кеша (TTL 5 минути) | 1.25x |
| Запис в кеша (TTL 1 час) | 2x |
| Четене от кеша | 0.1x |
2.2 Поддържани модели и минимална дължина на кеша
| Модел | Минимален брой токени за кеширане |
|---|---|
| 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 (оттеглен) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (оттеглен) / Haiku 3 | 2048 |
Ограничение на броя точки на прекъсване: Максимум 4 точки cache_control на заявка.2.3 TTL на кеша
| TTL | Синтаксис | Приложими сценарии |
|---|---|---|
| 5 минути (по подразбиране) | "cache_control": {"type": "ephemeral"} |
Кратки сесии, рутинни заявки |
| 1 час | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Дълги сесии, за избягване на повторни записи в кеша |
Цените за запис с TTL от 1 час са по-високи, но могат да спестят общи разходи, като намалят повторните записи в дълги сесии. Всички модели от Claude 4.5 и по-нови при всички доставчици (включително Anthropic, Amazon Bedrock, Google Vertex AI) поддържат TTL от 1 час.
2.4 Употреба
Можете да задавате точки на прекъсване за кеширане чрез полето cache_control в system, user (включително изображения) и tools. Следните примери показват само ключовата структура, без големите текстови блокове.
Кеширане на системното съобщение (по подразбиране TTL 5 минути):
{
"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"}]
}
]
}
Кеширане на потребителското съобщение (TTL 1 час):
{
"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"}
]
}
]
}
Кеширане на съобщение с изображение:
{
"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_control се поставя на най-горното ниво на обекта на инструмента (заедно с type и 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 Преглед на състоянието на кеша
Полето usage в отговора ще върне claude_cache_tokens_details, което записва подробна информация за кеша:
Първа заявка (създаване на кеш):
{
"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
}
}
}
Следващи заявки (попадение в кеша):
{
"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
}
}
}
| Поле | Значение |
|---|---|
cache_creation_input_tokens |
Брой токени, записани в кеша при тази заявка |
cache_read_input_tokens |
Брой токени, прочетени от кеша при тази заявка |
cache_write_5_minutes_input_tokens |
Брой токени, записани в кеш с TTL 5 минути |
cache_write_1_hour_input_tokens |
Брой токени, записани в кеш с TTL 1 час |
prompt_tokens_details.cached_tokens |
Брой кеширани токени при попадение в кеша, съвместим с формата на OpenAI |
3. Заглавка на заявката anthropic-beta
Можете да активирате бета функциите на модела Claude чрез HTTP заглавката anthropic-beta, която AIHubMix предава непроменена към Anthropic API.
Употреба
Добавете anthropic-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"}]}
]
}'
За конкретните налични бета идентификатори вижте документацията на Anthropic API.
Последна актуализация: 2026-06-01



