> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI-kompatible Schnittstelle mit tiefgehender Claude-Anpassung

> AIHubMix erweitert die OpenAI-kompatible Schnittstelle mit tiefgehender Claude-Anpassung: Interleaved Thinking über mehrere Turns hinweg ohne zusätzliche Parameter, automatisch greifendes Prompt-Caching sowie die Möglichkeit, Anthropic-Beta-Features zu aktivieren – damit Claude auch unter dem OpenAI-Protokoll seine nativen Fähigkeiten voll ausschöpft.

<Frame>
  <img src="https://mintcdn.com/aihubmix/KfVPdfHEI_4FVLQw/images/blogs/aihubmix-openai-upgrade-claude.webp?fit=max&auto=format&n=KfVPdfHEI_4FVLQw&q=85&s=fb6ff92d4f19b7f29976a709ab43ba76" alt="OpenAI-kompatible Schnittstelle mit tiefgehender Unterstützung für Claude Thinking, Caching und Beta-Features" width="2400" height="1260" data-path="images/blogs/aihubmix-openai-upgrade-claude.webp" />
</Frame>

Wir haben die OpenAI-kompatible Schnittstelle mit tiefergehenden Optimierungen speziell für die Modelle der Claude-Serie aktualisiert. Sie können nun Thinking und Caching präziser und komfortabler steuern – insbesondere Interleaved Thinking in Multi-Turn-Konversationen, das wir nutzerfreundlicher gestaltet haben, sodass eine nahtlose Integration ohne zusätzliche Parameter möglich ist. Außerdem werden die von Anthropic angebotenen Beta-Features unterstützt.

## 1. Modell-Thinking (Extended Thinking)

### 1.1 Vorteile von Interleaved Thinking

Ohne Interleaved Thinking führt das Modell den Denkprozess nur einmal am Anfang eines Assistant-Turns aus; nachfolgende Antworten werden direkt nach dem Erhalt von Tool-Ergebnissen erzeugt, ohne neue Thinking-Blöcke zu produzieren:

```json theme={null}
User → [Thinking] → Tool Call → Tool Result → Response
```

Mit aktiviertem Interleaved Thinking fügt das Modell jedes Mal, wenn es ein Tool-Ergebnis erhält, einen neuen Thinking-Block ein und bildet so eine Argumentationskette:

```json theme={null}
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
                                                ↑ Interleaved Thinking
```

So kann das Modell:

* **Auf Basis von Tool-Ergebnissen sekundäres Reasoning** durchführen, statt nur Ausgaben aneinanderzureihen.
* **Reasoning über mehrere Tool-Aufrufe hinweg verknüpfen**, wobei jede Entscheidung auf der Analyse des vorherigen Schritts basiert.

> Referenz: [Anthropic Interleaved Thinking](https://platform.claude.com/docs/en/build-with-claude/extended-thinking#interleaved-thinking)

### 1.2 Thinking aktivieren

Sie können Thinking auf vier Wegen aktivieren – wählen Sie einen davon:

| Methode                 | Beispiel                             | Beschreibung                                                         |
| :---------------------- | :----------------------------------- | :------------------------------------------------------------------- |
| `reasoning_effort`      | `"reasoning_effort": "low"`          | OpenAI-Standard-Parameter, auf oberster Ebene des Request-Body       |
| `reasoning.effort`      | `"reasoning": {"effort": "low"}`     | Äquivalent zur vorherigen Methode, innerhalb des `reasoning`-Objekts |
| `reasoning.max_tokens`  | `"reasoning": {"max_tokens": 1024}`  | Steuert maximale Token-Anzahl für Thinking präzise                   |
| Modellname mit `-think` | `"model": "claude-sonnet-4-5-think"` | Einfachster Weg, keine zusätzlichen Parameter nötig                  |

> **Priorität** (bei mehreren Methoden): `reasoning_effort` > `reasoning.max_tokens` > `reasoning.effort` > `-think`-Suffix

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

### 1.3 Thinking-Rückgabe

Die Antwort enthält zwei neue Felder:

* `reasoning_content`: Thinking-Inhalt (String) zur einfachen Anzeige.
* `reasoning_details`: Vollständige strukturierte Thinking-Informationen, die **bei Multi-Turn-Konversationen unverändert zurückgegeben werden müssen; die interne Struktur kann sich je nach Anbieter unterscheiden.**

Beispiel (non-streaming, irrelevante Felder ausgelassen):

```json theme={null}
{
  "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..."
      }
    }
  }]
}
```

Bei Streaming-Antworten werden Thinking-Inhalte in Chunks über `delta.reasoning_content` und `delta.reasoning_details` gesendet. Die komplette Streaming-Konkatenationslogik finden Sie im Beispiel unten.

### 1.4 Thinking in Multi-Turn-Konversationen erhalten **(Interleaved Thinking ist integriert, keine zusätzlichen Parameter nötig)**

Damit das Modell sein Reasoning in Multi-Turn-Konversationen fortsetzen kann, fügen Sie die zurückgegebenen `reasoning_details` **unverändert** in die Assistant-Nachricht der nächsten Runde ein:

```json theme={null}
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 **Interleaved Thinking automatisch**, sobald historische Thinking-Informationen im Request erkannt werden, sodass das Modell nach Tool-Aufrufen tiefgehendes Reasoning fortsetzen kann – ohne zusätzliche Parameter.

### 1.5 Vollständiges Beispiel

Die folgenden beiden Beispiele demonstrieren den vollständigen Multi-Turn-Tool-Call- + Interleaved-Thinking-Ablauf: Benutzeranfrage → Modell denkt und ruft Tool auf → Tool-Ergebnisse injizieren (mit erhaltenem `reasoning_details`) → Modell **interleaved thinking** liefert finale Antwort.

Non-Streaming · Interleaved Thinking

```python theme={null}
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 · Interleaved Thinking

```python theme={null}
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 Mapping-Regeln für die Thinking-Intensität

**Effort-Modus:**

* Opus 4.6 / Sonnet 4.6 und neuer: Mapping auf Anthropics native **Adaptive-Thinking**-Effort-Stufe.
* Andere Modelle: Berechnung über die Formel für `budget_tokens`:

```json theme={null}
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-Effort-Mapping:**

| 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 Anthropics `budget_tokens` zugewiesen.

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

***

## 2. Prompt Caching

Sie können Prompt Caching bei Aufrufen an das Claude-Modell über die Chat-Schnittstelle nutzen. Indem Sie `cache_control`-Breakpoints in Nachrichten setzen, lassen sich große Textblöcke (z. B. Rollenkarten, RAG-Daten, Buchkapitel) zur Wiederverwendung cachen, sodass nachfolgende Requests direkt Cache-Hits erzielen und Kosten deutlich senken.

> Offizielle Claude-Dokumentation: [Prompt Caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)

### 2.1 Caching-Kosten

| Operation                   | Preis-Faktor (relativ zum ursprünglichen Eingabepreis) |
| :-------------------------- | :----------------------------------------------------- |
| Cache-Write (5-Minuten-TTL) | 1,25×                                                  |
| Cache-Write (1-Stunden-TTL) | 2×                                                     |
| Cache-Read                  | 0,1×                                                   |

### 2.2 Unterstützte Modelle und Mindest-Cache-Länge

| Modell                                                                                | Mindest-Cache-Token |
| :------------------------------------------------------------------------------------ | :------------------ |
| 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                |

> **Breakpoint-Limit:** Maximal **4** `cache_control`-Breakpoints pro Request.

### 2.3 Cache-TTL

| TTL                  | Syntax                                                | Geeignete Szenarien                                |
| :------------------- | :---------------------------------------------------- | :------------------------------------------------- |
| 5 Minuten (Standard) | `"cache_control": {"type": "ephemeral"}`              | Kurze Sessions, Routine-Anfragen                   |
| 1 Stunde             | `"cache_control": {"type": "ephemeral", "ttl": "1h"}` | Lange Sessions, vermeidet wiederholte Cache-Writes |

Die Write-Kosten für 1-Stunden-TTL sind höher, sparen aber bei langen Sessions Gesamtkosten durch weniger Cache-Writes. Alle Modelle ab Claude 4.5 und neuer von allen Anbietern (einschließlich Anthropic, Amazon Bedrock, Google Vertex AI) unterstützen 1-Stunden-TTL.

### 2.4 Verwendung

Sie können Cache-Breakpoints über das `cache_control`-Feld in `system`, `user` (inkl. Bildern) und `tools` setzen. Die Beispiele zeigen nur die wesentliche Struktur und lassen große Textblöcke weg.

**System-Message-Caching (Standard 5-Minuten-TTL):**

```json theme={null}
{
  "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"}]
    }
  ]
}
```

**User-Message-Caching (1-Stunden-TTL):**

```json theme={null}
{
  "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"}
      ]
    }
  ]
}
```

**Bild-Message-Caching:**

```json theme={null}
{
  "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?"}
  ]
}
```

**Tool-Definitions-Caching:**

`cache_control` wird auf der obersten Ebene des Tool-Objekts platziert (auf gleicher Ebene wie `type` und `function`):

```json theme={null}
{
  "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

Die `usage`-Antwort liefert `claude_cache_tokens_details` mit detaillierten Cache-Informationen:

**Erste Anfrage (Cache wird angelegt):**

```json theme={null}
{
  "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-Hit):**

```json theme={null}
{
  "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 in diesem Request in den Cache geschriebenen Token            |
| `cache_read_input_tokens`             | Anzahl der in diesem Request aus dem Cache gelesenen Token               |
| `cache_write_5_minutes_input_tokens`  | Anzahl der in den 5-Minuten-TTL-Cache geschriebenen Token                |
| `cache_write_1_hour_input_tokens`     | Anzahl der in den 1-Stunden-TTL-Cache geschriebenen Token                |
| `prompt_tokens_details.cached_tokens` | Anzahl gecachter Token bei einem Cache-Hit, kompatibel mit OpenAI-Format |

***

## 3. Request-Header für `anthropic-beta`

Sie können Beta-Features des Claude-Modells über den HTTP-Header `anthropic-beta` aktivieren; AihubMix reicht diesen an die Anthropic-API weiter.

### Verwendung

Fügen Sie `anthropic-beta` zum Request-Header hinzu, mit dem Wert der entsprechenden Beta-Feature-Kennung:

```json theme={null}
curl "https://aihubmix.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -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"}]}
  ]
}'
```

> Konkret verfügbare Beta-Kennungen finden Sie in der [Anthropic-API-Dokumentation](https://docs.anthropic.com/en/api/beta).

***

Zuletzt aktualisiert: 2026-06-01
