Upgrade der OpenAI-kompatiblen Schnittstelle: Umfassende Unterstützung für Claude

AIHubMix hat seine OpenAI-kompatible API für Claude aktualisiert: verschachteltes Denken ohne zusätzliche Parameter, Prompt-Caching und Unterstützung von Anthropic-Beta-Funktionen.

AIHubMix8 Min. Lesezeit
Upgrade der OpenAI-kompatiblen Schnittstelle: Umfassende Unterstützung für Claude

Wir haben die OpenAI-kompatible Schnittstelle mit tiefergehenden Optimierungen speziell für die Claude-Modellreihe aufgewertet. Sie können Denkprozesse und Caching nun präziser und komfortabler steuern. Verschachteltes Denken in Mehrfachkonversationen ist jetzt benutzerfreundlicher und lässt sich ohne zusätzliche Parameter nahtlos integrieren. Außerdem werden die Beta-Funktionen unterstützt, die Anthropic anbietet.

1. Modell-Denkprozess (Extended Thinking)

1.1 Vorteile des verschachtelten Denkens

Wenn verschachteltes Denken nicht aktiviert ist, führt das Modell das Denken nur einmal zu Beginn eines Assistenten-Zuges aus; nachfolgende Antworten werden nach Erhalt der Tool-Ergebnisse direkt erzeugt, ohne neue Denkblöcke zu produzieren:

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

Wenn verschachteltes Denken aktiviert ist, fügt das Modell jedes Mal, wenn es ein Tool-Ergebnis erhält, einen neuen Denkblock ein und bildet so eine Argumentationskette:

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

Dadurch kann das Modell:

  • auf Grundlage von Tool-Ergebnissen eine Folgeüberlegung anstellen, statt die Ausgaben einfach aneinanderzureihen.
  • Überlegungen über mehrere Tool-Aufrufe hinweg verketten, wobei jede Entscheidung auf der Analyse des vorherigen Schritts beruht.
Referenz: Anthropic Interleaved Thinking

1.2 Denken aktivieren

Sie können das Denken auf vier Arten aktivieren; wählen Sie eine davon aus:

Methode Beispiel Beschreibung
reasoning_effort "reasoning_effort": "low" OpenAI-Standardparameter, auf oberster Ebene des Request-Bodys platziert
reasoning.effort "reasoning": {"effort": "low"} Entspricht der vorherigen Methode, innerhalb des reasoning-Objekts platziert
reasoning.max_tokens "reasoning": {"max_tokens": 1024} Steuert die maximale Anzahl an Tokens für das Denken präzise
Modellname mit -think "model": "claude-sonnet-4-5-think" Der einfachste Weg, es sind keine zusätzlichen Parameter nötig
Priorität (bei Verwendung mehrerer Methoden): reasoning_effort > reasoning.max_tokens > reasoning.effort > -think-Suffix

Mögliche Werte für effort: minimal / low / medium / high / xhigh

1.3 Rückgabe des Denkprozesses

Die Antwortnachricht enthält zwei neue Felder:

  • reasoning_content: Denkinhalt (String), zur einfachen Anzeige.
  • reasoning_details: Vollständige strukturierte Informationen über das Denken, die in Mehrfachkonversationen unverändert zurückgegeben werden müssen; die interne Struktur kann sich zwischen Anbietern unterscheiden.

Beispiel ohne Streaming (unwichtige Felder weggelassen):

{
  "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 Streaming-Antworten wird der Denkinhalt stückweise über delta.reasoning_content und delta.reasoning_details gesendet. Die vollständige Logik zum Zusammenfügen beim Streaming finden Sie im vollständigen Beispiel unten.

1.4 Denkprozess in Mehrfachkonversationen beibehalten (Verschachteltes Denken ist integriert, es sind keine zusätzlichen Parameter nötig)

Damit das Modell seine Denkfähigkeiten in Mehrfachkonversationen fortsetzen kann, fügen Sie die zuvor zurückgegebenen reasoning_details unverändert in die Assistenten-Nachricht der nächsten Runde ein:

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 aktiviert verschachteltes Denken automatisch, sobald es historische Denkinformationen in der Anfrage erkennt. So kann das Modell nach Erhalt der Tool-Aufrufergebnisse weiter tiefgehend nachdenken, ohne dass zusätzliche Parameter nötig sind.

1.5 Vollständiges Beispiel

Die folgenden zwei Beispiele zeigen den vollständigen Ablauf eines mehrstufigen Tool-Aufrufs mit verschachteltem Denken: Benutzeranfrage → Modell denkt nach und ruft ein Tool auf → Tool-Ergebnisse einfügen (unter Beibehaltung von reasoning_details) → Modell gibt per verschachteltem Denken die finale Antwort.

Ohne Streaming · Verschachteltes Denken

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})

Streaming · Verschachteltes Denken

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 Regeln zur Zuordnung der Denkintensität

Effort-Modus:

  • Opus 4.6 / Sonnet 4.6 und neuer: wird auf die native Adaptive-Thinking-Effort-Stufe von Anthropic abgebildet.
  • Andere Modelle: berechnet mit der Formel für 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

Zuordnung der Adaptive-Thinking-Effort-Stufen:

Eingehender 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: Wird direkt als Anthropic-budget_tokens übernommen.

-think-Suffix: Opus/Sonnet 4.6+ verwendet Adaptive Thinking (effort=medium); andere Modelle setzen budget_tokens = min(10240, max_tokens - 1), mit einem Standardwert von max_tokens von 4096.


2. Prompt-Caching

Sie können Prompt-Caching verwenden, wenn Sie über die Chat-Schnittstelle Anfragen an das Claude-Modell stellen. Indem Sie cache_control-Haltepunkte in Nachrichten setzen, können große Textblöcke (etwa Rollenbeschreibungen, RAG-Daten, Buchkapitel usw.) zur Wiederverwendung gecacht werden. Nachfolgende Anfragen treffen dann direkt den Cache, was die Kosten deutlich senkt.

Offizielle Claude-Dokumentation: Prompt Caching

2.1 Caching-Kosten

Vorgang Preismultiplikator (im Verhältnis zum ursprünglichen Input-Preis)
Cache-Schreibvorgang (5-Minuten-TTL) 1.25x
Cache-Schreibvorgang (1-Stunden-TTL) 2x
Cache-Lesevorgang 0.1x

2.2 Unterstützte Modelle und minimale Cache-Länge

Modell Minimale Anzahl an Cache-Tokens
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 (veraltet) 1024
Claude Haiku 4.5 4096
Claude Haiku 3.5 (veraltet) / Haiku 3 2048
Begrenzung der Haltepunkte: Maximal 4 cache_control-Haltepunkte pro Anfrage.

2.3 Cache-TTL

TTL Syntax Anwendungsszenarien
5 Minuten (Standard) "cache_control": {"type": "ephemeral"} Kurze Sitzungen, routinemäßige Anfragen
1 Stunde "cache_control": {"type": "ephemeral", "ttl": "1h"} Lange Sitzungen, um wiederholte Cache-Schreibvorgänge zu vermeiden

Die Schreibkosten für die 1-Stunden-TTL sind höher, können aber in langen Sitzungen die Gesamtkosten senken, weil wiederholte Schreibvorgänge entfallen. Alle Claude-Modelle ab Version 4.5 unterstützen von allen Anbietern (einschließlich Anthropic, Amazon Bedrock, Google Vertex AI) die 1-Stunden-TTL.

2.4 Verwendung

Sie können Cache-Haltepunkte über das Feld cache_control in system, user (einschließlich Bilder) und tools setzen. Die folgenden Beispiele zeigen nur die grundlegende Struktur und lassen große Textblöcke weg.

Caching von System-Nachrichten (Standard-TTL von 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 von Benutzer-Nachrichten (1-Stunden-TTL):

{
  "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 von Bild-Nachrichten:

{
  "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 von Tool-Definitionen:

cache_control wird auf der obersten Ebene des Tool-Objekts platziert (neben type und 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 Cache-Status einsehen

Das Feld usage der Antwort enthält claude_cache_tokens_details mit detaillierten Cache-Informationen:

Erste Anfrage (Cache wird erstellt):

{
  "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
    }
  }
}

Folgeanfragen (Cache-Treffer):

{
  "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
    }
  }
}
Feld Bedeutung
cache_creation_input_tokens Anzahl der Tokens, die in dieser Anfrage in den Cache geschrieben wurden
cache_read_input_tokens Anzahl der Tokens, die in dieser Anfrage aus dem Cache gelesen wurden
cache_write_5_minutes_input_tokens Anzahl der Tokens, die in den Cache mit 5-Minuten-TTL geschrieben wurden
cache_write_1_hour_input_tokens Anzahl der Tokens, die in den Cache mit 1-Stunden-TTL geschrieben wurden
prompt_tokens_details.cached_tokens Anzahl der gecachten Tokens bei einem Cache-Treffer, kompatibel mit dem OpenAI-Format

3. Request-Header für anthropic-beta

Sie können Beta-Funktionen des Claude-Modells über den HTTP-Header anthropic-beta aktivieren; AIHubMix leitet diesen an die Anthropic-API weiter.

Verwendung

Fügen Sie anthropic-beta dem Request-Header hinzu, wobei der Wert der entsprechende Beta-Funktionsbezeichner ist:

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"}]}
  ]
}'
Die verfügbaren Beta-Bezeichner finden Sie in der Anthropic-API-Dokumentation.

Zuletzt aktualisiert: 2026-06-01

Ein Gateway zu mehreren KI-Anbietern. Gebaut für den Produktiveinsatz.

AIHubMix besuchen