Актуализация на интерфейса, съвместим с OpenAI: Дълбока поддръжка за Claude

31.07.2026 г. · AIHubMix · 8 min read · Новини

Актуализация на интерфейса, съвместим с OpenAI: Дълбока поддръжка за Claude

Актуализирахме OpenAI-съвместимия интерфейс с по-дълбоки оптимизации, специално за моделите от серията Claude. Сега можете да контролирате мисленето и кеширането по-прецизно и удобно. Интерлираното мислене в многопосочни разговори е сега по-полезно за потребителя, позволявайки безпроблемна интеграция без допълнителни параметри. То също така поддържа активирането на бета функциите, предлагани от Anthropic.

1. Моделно мислене (Разширено мислене)

1.1 Предимства на интерлираното мислене

Когато интерлираното мислене не е активирано, моделът извършва мислене само веднъж в началото на помощния ход; последващите отговори се генерират директно след получаване на резултатите от инструмента, без да се произвеждат нови блокове на мислене:

User → [Thinking] → Tool Call → Tool Result → Response

Когато интерлираното мислене е активирано, моделът вмъква нов блок на мислене всеки път, когато получи резултат от инструмент, формирайки верига на разсъждения:

User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
                                                ↑ Интерлирано мислене

Това позволява на модела да:

  • Извършва вторично разсъждение на базата на резултатите от инструмента, вместо просто да конкатенира изходите.
  • Свързва разсъждения между множество извиквания на инструменти, където всяко решение е основано на анализа на предишната стъпка.
Справка: Интерлирано мислене на Anthropic

1.2 Активиране на мисленето

Можете да активирате мисленето по четири начина, избирайки който и да е от тях:

Метод Пример Описание
reasoning_effort "reasoning_effort": "low" Стандартен параметър на OpenAI, поставен на най-високо ниво на тялото на заявката
reasoning.effort "reasoning": {"effort": "low"} Еквивалентен на предишния метод, поставен в обекта на разсъжденията
reasoning.max_tokens "reasoning": {"max_tokens": 1024} Прецизно контролира максималния брой токени за мислене
Име на модела с -think "model": "claude-sonnet-4-5-think" Най-простият начин, не изисква допълнителни параметри
Приоритет (когато се използват множество методи): reasoning_effort > reasoning.max_tokens > reasoning.effort > -think суфикс

Възможни стойности за усилие: minimal / low / medium / high / xhigh

1.3 Връщане на мисленето

Съобщението за отговор ще включва две нови полета:

  • reasoning_content: Съдържание на мисленето (стринг), за лесно показване.
  • reasoning_details: Пълна структурирана информация за мисленето, която трябва да бъде върната така, както е, в многопосочни разговори; вътрешната структура може да се различава между доставчиците.

Пример без стрийминг (пропускайки несвързаните полета):

{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": "Здравейте! Как мога да ви помогна днес?",
      "reasoning_content": "Потребителят просто казва здравей...",
      "reasoning_details": {
        "type": "thinking",
        "thinking": "Потребителят просто казва здравей...",
        "signature": "Er8CCkYI..."
      }
    }
  }]
}

В отговорите със стрийминг, съдържанието на мисленето ще бъде изпратено на части чрез delta.reasoning_content и delta.reasoning_details. За пълната логика на стрийминг конкатенацията, вижте пълния пример по-долу.

1.4 Запазване на мисленето в многопосочни разговори (Интерлираното мислене е вградена функция, не са необходими допълнителни параметри)

За да позволите на модела да продължи своите способности за разсъждение в многопосочни разговори, просто поставете предишно върнатото reasoning_details така, както е в съобщението на помощника за следващия рунд:

messages = [
    {"role": "user", "content": "Какво е времето в Бостън?"},
    {
        "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": "дъждовно"}',
    }
]

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-***"),
)

# ── Определение на инструмента ───────────────────────────────────────────
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Получаване на текущото време за местоположение",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string", "description": "Име на града"}},
            "required": ["location"]
        }
    }
}]

# ── Изпълнение на инструмента ───────────────────────────────────────
WEATHER_DB = {
    "boston": {"temperature": "45°F (7°C)", "condition": "дъждовно", "humidity": "85%", "wind": "15 mph NE"},
    "tokyo":  {"temperature": "72°F (22°C)", "condition": "слънчево", "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": "ясно"}))
    return "{}"

# ── Цикъл на многопосочен разговор ─────────────────────────────
messages = [
    {"role": "user", "content": "Какво е времето в Бостън? След това препоръчай какво да нося."}
]

turn = 0
while True:
    turn += 1
    print(f"\n── Ход {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

    # Печат на процеса на мислене
    if msg.reasoning_content:
        label = "Интерлирано мислене" if turn > 1 else "Мислене"
        print(f"[{label}] {msg.reasoning_content}")

    # Печат на съдържанието на отговора
    if msg.content:
        print(f"[Отговор] {msg.content}")

    # Печат на извикванията на инструменти
    if msg.tool_calls:
        for tc in msg.tool_calls:
            print(f"[Извикване на инструмент: {tc.function.name}] {tc.function.arguments}")

    # Създаване на съобщение от помощника, запазване на reasoning_details (критично!)
    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  # предаване без модификация
    messages.append(assistant_msg)

    # Няма tool_calls, означава, че разговорът е приключил
    if not msg.tool_calls:
        break

    # Изпълнение на инструменти и добавяне на резултати към съобщенията
    for tc in msg.tool_calls:
        args = json.loads(tc.function.arguments)
        result = execute_tool(tc.function.name, args)
        print(f"[Резултат от инструмента: {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-***"),
)

# ── Определение на инструмента и имитация на изпълнение ─────────────────────────
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Получаване на текущото време за местоположение",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string", "description": "Име на града"}},
            "required": ["location"]
        }
    }
}]

WEATHER_DB = {
    "boston": {"temperature": "45°F (7°C)", "condition": "дъждовно", "humidity": "85%", "wind": "15 mph NE"},
    "tokyo":  {"temperature": "72°F (22°C)", "condition": "слънчево", "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": "ясно"}))
    return "{}"

# ── Стрийминг на отговори ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
    """Стрийминг на отговор, печат на мисленето/съдържанието в реално време, натрупване на reasoning_details/tool_calls."""
    rd = {}            # натрупани reasoning_details
    content = ""       # натрупан текст на отговора
    tc_map = {}        # натрупани tool_calls (по индекс)
    cur = "none"       # текуща секция на изхода: 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

        # ── Обработка на мисленето ──
        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
            # Печат на части от мисленето в реално време
            thinking_chunk = rd_delta.get("thinking", "")
            if thinking_chunk:
                if cur != "thinking":
                    cur = "thinking"
                    label = "Интерлирано мислене" if turn > 1 else "Мислене"
                    sys.stdout.write(f"\n[{label}] ")
                sys.stdout.write(thinking_chunk)
                sys.stdout.flush()

        # ── Обработка на съдържанието ──
        if delta.content:
            if cur != "content":
                if cur == "thinking":
                    sys.stdout.write("\n")
                cur = "content"
                sys.stdout.write("\n[Отговор] ")
            sys.stdout.write(delta.content)
            sys.stdout.flush()
            content += delta.content

        # ── Обработка на 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 ""

    # Завършване на текущата секция на изхода
    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,
    }

# ── Цикъл на многопосочен разговор ─────────────────────────────
messages = [
    {"role": "user", "content": "Какво е времето в Бостън? След това препоръчай какво да нося."}
]

turn = 0
while True:
    turn += 1
    print(f"\n── Ход {turn} ──")

    result = stream_and_collect(
        turn,
        model="claude-sonnet-4-5",
        messages=messages,
        tools=tools,
        extra_body={"reasoning": {"max_tokens": 2000}},
    )

    # Печат на извикванията на инструменти
    if result["tool_calls"]:
        for tc in result["tool_calls"]:
            print(f"[Извикване на инструмент: {tc['function']['name']}] {tc['function']['arguments']}")

    # Създаване на съобщение от помощника, запазване на reasoning_details (критично!)
    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"]  # предаване без модификация
    messages.append(assistant_msg)

    # Няма tool_calls, означава, че разговорът е приключил
    if not result["tool_calls"]:
        break

    # Изпълнение на инструменти и добавяне на резултати към съобщенията
    for tc in result["tool_calls"]:
        args = json.loads(tc["function"]["arguments"])
        tool_result = execute_tool(tc["function"]["name"], args)
        print(f"[Резултат от инструмента: {tc['function']['name']}] {tool_result}")
        messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})

1.6 Правила за картографиране на интензивността на мисленето

Режим на усилие:

  • Opus 4.6 / Sonnet 4.6 и по-нови: картографира се на родното ниво на усилие на Адаптивно мислене на Anthropic.
  • Други модели: изчислява се с формулата за budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
усилие усилие_ratio
xhigh 0.95
high 0.80
medium 0.50
low 0.20
minimal 0.10

Картографиране на усилието за адаптивно мислене:

Входящо усилие Opus 4.6 Sonnet 4.6
xhigh макс високо
high високо високо
medium средно средно
low ниско ниско
minimal ниско ниско

Режим max_tokens: Пряко зададен като budget_tokens на Anthropic.

-think суфикс: Opus/Sonnet 4.6+ използва адаптивно мислене (усилие=средно); другите модели задават budget_tokens = min(10240, max_tokens - 1), с подразбираща се стойност max_tokens от 4096.


2. Кеширане на подсказки

Можете да използвате кеширане на подсказки, когато правите заявки към модела Claude чрез интерфейса за чат. Чрез задаване на точки за контрол на кеша в съобщенията, големи блокове текст (като карти на роли, RAG данни, глави от книги и др.) могат да бъдат кеширани за повторна употреба, позволявайки на последващите заявки да достигнат кеша директно и значително да намалят разходите.

Официална документация на Claude: Кеширане на подсказки

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": "Вие сте AI асистент"},
        {
          "type": "text",
          "text": "(дълъг контекст)",
          "cache_control": {"type": "ephemeral"}
        }
      ]
    },
    {
      "role": "user",
      "content": [{"type": "text", "text": "Здравейте"}]
    }
  ]
}

Кеширане на съобщения от потребителя (TTL от 1 час):

{
  "model": "claude-opus-4-5",
  "messages": [
    {
      "role": "system",
      "content": [{"type": "text", "text": "Вие сте AI асистент"}]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "(дълъг контекст)",
          "cache_control": {"type": "ephemeral", "ttl": "1h"}
        },
        {"type": "text", "text": "Здравейте"}
      ]
    }
  ]
}

Кеширане на съобщения с изображения:

{
  "role": "user",
  "content": [
    {
      "type": "image_url",
      "image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
      "cache_control": {"type": "ephemeral"}
    },
    {"type": "text", "text": "Какво е това?"}
  ]
}

Кеширане на дефиниции на инструменти:

cache_control се поставя на най-високо ниво на обекта на инструмента (заедно с type и function):

{
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Получаване на текущото време за местоположение",
      "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": "Вие сте AI асистент"},
        {
          "type": "text",
          "text": "(дълъг контекст)",
          "cache_control": {"type": "ephemeral"}
        }
      ]
    },
    {"role": "user", "content": [{"type": "text", "text": "здравей"}]}
  ]
}'
За конкретни налични бета идентификатори, моля, вижте Документация на Anthropic API.

Последна актуализация: 2026-06-01

More from the blog