# Python-SDK mit Unsloth verbinden

Unsloth stellt drei OpenAI-kompatible Dialekte unter derselben Basis-URL bereit. Chat Completions, Responses und Anthropic Messages, sodass jedes gängige Python-SDK damit funktioniert. \
\
Du änderst nur die `base_url` und `api_key`  am Client; alles andere (Streaming, Tool-Aufrufe, Vision, strukturierte Ausgabe) verhält sich so, wie es die SDK-Dokumentation beschreibt. Diese Seite behandelt die zwei SDKs, zu denen die meisten Entwickler zuerst greifen: das offizielle **OpenAI Python SDK** und das offizielle **Anthropic Python SDK**.

{% hint style="info" %}
Wenn du dir nicht sicher bist, welche URL / welchen Schlüssel / welchen Modellnamen du verwenden sollst, lies zuerst die API-Übersicht. Dort wird erklärt, wie du startest, ein Modell lädst und einen `sk-unsloth-…` Schlüssel.
{% endhint %}

### 🔑 Voraussetzungen

Bevor du eines der unten stehenden Snippets ausführst, brauchst du:

* **Lokal laufendes Unsloth** mit einem geladenen Modell (beachte den Port: typischerweise `8000` oder `8888`).
* **Einen `sk-unsloth-…` API-Schlüssel** erstellt unter **Einstellungen → API**.
* **Einen Modellnamen.** Den Namen des GGUF-Modells innerhalb von Unsloth (z. B. `qwen-local`, `unsloth/Qwen3.6-27B-GGUF`). Wenn du ihn vergessen hast, führe Folgendes aus:

  ```bash
  curl http://localhost:8888/v1/models -H "Authorization: Bearer sk-unsloth-…"
  ```

  und kopiere das `id` Feld.

Setze den Schlüssel als Umgebungsvariable, damit du ihn nie in den Code einfügen musst:

```bash
export UNSLOTH_STUDIO_AUTH_TOKEN=sk-unsloth-xxxxxxxxxxxx
```

#### 🤖 OpenAI SDK

Unsloths `/v1/chat/completions` Endpunkt ist ein direkter Ersatz für das OpenAI Python SDK. Der Client behandelt Unsloth wie jeden anderen OpenAI-kompatiblen Anbieter.

**1. Installiere das SDK:**

```bash
pip install openai
```

**2. Erstelle einen Client** der auf Unsloth zeigt:

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8888/v1",              # dein Unsloth-Port + /v1
    api_key=os.environ["UNSLOTH_STUDIO_AUTH_TOKEN"],     # dein sk-unsloth-…-Schlüssel
)
```

#### Einfache Chat-Completion

```python
response = client.chat.completions.create(
    model="default",                               # der Name, den du dem Modell in Unsloth gegeben hast, oder default
    messages=[
        {"role": "user", "content": "Nenne mir zwei Fakten über Paris"}
    ],
)
print(response.choices[0].message.content)
```

<figure><img src="/files/efe2208657bf65f61eb750f586e9e46f24ddf462" alt=""><figcaption></figcaption></figure>

#### Streaming

Setze `stream=True` und iteriere über den zurückgegebenen Generator:

```python
stream = client.chat.completions.create(
    model="qwen-local",
    messages=[{"role": "user", "content": "Schreibe ein Haiku über lokal ausgeführte LLMs."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices:
        delta = chunk.choices[0].delta.content
        if delta:
            print(delta, end="", flush=True)
```

<figure><img src="/files/66f1de4e4d79f45e815917269cc451a557243804" alt=""><figcaption></figcaption></figure>

#### Bilder (Vision)

Hänge ein Bild als `image_url` Content-Teil an. Unsloth akzeptiert entweder eine HTTP(S)-URL oder eine `data:` base64-URI:

```python
import base64
from pathlib import Path

img_b64 = base64.b64encode(Path("test.jpg").read_bytes()).decode()

response = client.chat.completions.create(
    model="default",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{img_b64}"},
                },
                {"type": "text", "text": "Was ist auf diesem Bild zu sehen?"},
            ],
        }
    ],
)
print(response.choices[0].message.content)
```

{% hint style="info" %}
Das geladene Modell muss multimodal sein. Wenn du ein reines Textmodell lädst, wird die Vision-Anfrage strukturell zwar erfolgreich sein, aber das Modell wird das Bild nicht „sehen“ können.
{% endhint %}

<figure><img src="/files/7ba4d6e7b014756da807f51acd6aad9d9bd5b0d3" alt=""><figcaption></figcaption></figure>

#### Funktionsaufrufe (OpenAI-Tools)

Übergebe OpenAI-artige `tools` und (optional) `tool_choice` und Unsloth leitet sie an das Backend weiter. Dein Client ist dafür verantwortlich, jeden Tool-Aufruf auszuführen und das Ergebnis im nächsten Turn zurückzugeben:

```python
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Hole das aktuelle Wetter für eine Stadt",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "Stadtname, z. B. 'Paris'"},
                },
                "required": ["city"],
            },
        },
    }
]

response = client.chat.completions.create(
    model="default",
    messages=[{"role": "user", "content": "Wie ist das Wetter gerade in Perth?"}],
    tools=tools,
    tool_choice="auto",
)

tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name, tool_call.function.arguments)
```

<figure><img src="/files/9c50d5ce83825a947d5569e29ef89e42dcff3596" alt=""><figcaption></figcaption></figure>

#### Unsloth-Server-seitige Tools (Kurzform)

Zusätzlich zu OpenAI-artigen Client-seitigen Tools kann Unsloth **Python**, **bash**, und **Websuche** serverseitig ausführen und die Ergebnisse automatisch zurückstreamen. Aktiviere dies über den `extra_body` Parameter, damit die Felder direkt an Unsloth weitergereicht werden:

```python
stream = client.chat.completions.create(
    model="default",
    messages=[{"role": "user", "content": "Was ist 123 * 456? Verwende Python, um es zu berechnen."}],
    stream=True,
    extra_body={
        "enable_tools": True,
        "enabled_tools": ["python", "web_search"],
        "session_id": "my-session",
    },
)
for chunk in stream:
    if chunk.choices:
        delta = chunk.choices[0].delta.content
        if delta:
            print(delta, end="", flush=True)
```

<figure><img src="/files/b92c7c598e3e8ccb966f033e6d5098f4b5a2d3a3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/1c5efc6f879754840981c7850d26fa1105c6b4c2" alt=""><figcaption></figcaption></figure>

Die `session_id` ist optional. Verwende sie, um den Tool-Status (z. B. einen Python-Kernel) über mehrere Aufrufe hinweg beizubehalten.

{% hint style="info" %}
`enabled_tools` unterstützt derzeit `"python"`, `"bash"`, und `"web_search"`. Tool-Ergebnisse werden als `tool_result` Ereignisse zurückgestreamt, damit das Modell sie im nächsten Turn sehen kann.
{% endhint %}

**Modelle auflisten**

```python
models = client.models.list()
for m in models.data:
    print(m.id)
```

<figure><img src="/files/25efb86d60880c661d317a8ddac2c65a042086e0" alt=""><figcaption></figcaption></figure>

#### 🧠 Anthropic SDK

Unsloths `/v1/messages` Endpunkt ist ein direkter Ersatz für das Anthropic Python SDK.

**1. Installiere das SDK:**

```bash
pip install anthropic
```

**2. Erstelle einen Client** der auf Unsloth zeigt:

```python
import os
from anthropic import Anthropic

client = Anthropic(
    base_url="http://localhost:8888",                 # dein Unsloth-Port (hier kein /v1 - das SDK fügt es hinzu)
    api_key="dummy",                                  # ein zufälliger nichtleerer Wert
    default_headers={"Authorization": "Bearer {os.environ['UNSLOTH_STUDIO_AUTH_TOKEN']}"} # dein sk-unsloth-…-Schlüssel
)
```

#### Einfache Nachricht

```python
message = client.messages.create(
    model="default",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Sag Hallo in drei Sprachen."}
    ],
)
print(message.content[0].text)
```

<figure><img src="/files/f035d2fc8f2282bd57c48fb0d93ef1d831e85996" alt=""><figcaption></figcaption></figure>

#### Streaming

Das SDK stellt einen Context Manager bereit, der Text-Deltas liefert:

```python
with client.messages.stream(
    model="default",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Erkläre LoRA in zwei Sätzen."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
```

#### Bilder (Vision)

Anthropic-artiger Bildinhalt verwendet einen `source` Block mit base64-Daten:

```python
import base64
from pathlib import Path

img_b64 = base64.standard_b64encode(Path("photo.jpg").read_bytes()).decode()

message = client.messages.create(
    model="default",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/jpeg",
                        "data": img_b64,
                    },
                },
                {"type": "text", "text": "Was ist auf diesem Bild zu sehen?"},
            ],
        }
    ],
)
print(message.content[0].text)
```

<figure><img src="/files/057be132cf5514c16511c1e6baae37b738b68de2" alt=""><figcaption></figcaption></figure>

#### Tool-Aufrufe (Anthropic-Tools)

Übergebe Anthropic-artige `tools` mit einem `input_schema` und Unsloth leitet sie nativ weiter:

```python
tools = [
    {
        "name": "get_weather",
        "description": "Hole das aktuelle Wetter für eine Stadt",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "Stadtname, z. B. 'Tokyo'"},
            },
            "required": ["city"],
        },
    }
]

message = client.messages.create(
    model="default",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto"},
    messages=[{"role": "user", "content": "Wie ist das Wetter in Tokyo?"}],
)

for block in message.content:
    if block.type == "tool_use":
        print(block.name, block.input)
```

<figure><img src="/files/f1feca5faa4a3bce6d196e784c43c33d896fa9b6" alt=""><figcaption></figcaption></figure>

#### Unsloth-Server-seitige Tools (Kurzform)

Dieselbe `enable_tools` / `enabled_tools` / `session_id` Kurzform funktioniert mit `/v1/messages` reiche es durch `extra_body`:

```python
with client.messages.stream(
    model="default",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Suche nach Python-3.13-Funktionen und fasse sie zusammen."}],
    extra_body={
        "enable_tools": True,
        "enabled_tools": ["web_search", "python"],
        "session_id": "my-session",
    },
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
```

<figure><img src="/files/c97c054339881a245b5d0e5f87990ef02cf9efb3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/39780bcf89e8d210a7dd1cfda50194274ce6795c" alt=""><figcaption></figcaption></figure>

Unsloth gibt benutzerdefinierte `tool_result` SSE-Ereignisse für die Sicht des Modells auf die Ausgabe jedes Tool-Aufrufs aus. Das Anthropic SDK reicht diese in seinem Ereignisstrom unverändert durch.

#### JSON-Dekodierung (`response_format`)

Unsloth unterstützt OpenAI-artige strukturierte Ausgaben über `response_format`. Übergib ein JSON-Schema, und das Modell wird darauf beschränkt, JSON zu erzeugen, das diesem Schema entspricht.

````python
import json
import os
import re
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8888/v1",
    api_key=os.environ["UNSLOTH_STUDIO_AUTH_TOKEN"],
)

response = client.chat.completions.create(
    model="default",
    stream=False,
    temperature=0.0,
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": "Wähle ein Land: Japan, Ägypten oder Peru. Erkläre warum in einem Satz.",
        },
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "country_pick",
            "schema": {
                "type": "object",
                "properties": {
                    "country": {"type": "string", "enum": ["Japan", "Egypt", "Peru"]},
                    "reason":  {"type": "string"},
                },
                "required": ["country", "reason"],
                "additionalProperties": False,
            },
            "strict": True,
        },
    },
)

raw = response.choices[0].message.content
# Entferne den Markdown-Zaun, den Gemma 4 um das JSON legt, und parse es dann.
cleaned = re.sub(r"^```(?:json)?\s*", "", raw)
cleaned = re.sub(r"\s*```$", "", cleaned)
parsed = json.loads(cleaned)

print(json.dumps(parsed, indent=2))
print()
print("country:", parsed["country"] )
print("reason :", parsed["reason"] )
````

Die `strict: True` Kennzeichnung weist Unsloth an, das Schema während der Dekodierung durchzusetzen, anstatt sich darauf zu verlassen, dass das Modell es von selbst einhält. `additionalProperties: False` und `required` funktionieren wie im Standard-JSON-Schema.

Die Terminalausgabe sollte in etwa so aussehen:

<figure><img src="/files/ca6e61b57e5367ea5066d823ab292199030111f0" alt=""><figcaption></figcaption></figure>

## Entferne den Markdown-Zaun, den Gemma 4 um das JSON legt, und parse es dann.

cleaned = re.sub(r"^`(?:json)?\s*", "", raw) cleaned = re.sub(r"\s*`$", "", cleaned) parsed = json.loads(cleaned)

print(json.dumps(parsed, indent=2)) print() print("country:", parsed\["country"]) print("reason :", parsed\["reason"] )

### 🧪 Auswahl eines SDKs

Beide SDKs funktionieren mit Unsloth. Die richtige Wahl hängt vom Rest deines Stacks ab:

* Verwende das **OpenAI SDK** wenn dein Code bereits vom OpenAI-Python-Paket abhängt, du OpenAI-artige `tools` / `tool_choice`, oder du planst, die Responses API aufzurufen.
* Verwende das **Anthropic SDK** wenn dein Code bereits vom Anthropic-Paket abhängt, du Anthropics `input_schema` Tool-Format bevorzugst oder die Anthropic-nativen Streaming-Ereignistypen möchtest.

Du kannst beide im selben Projekt verwenden. Unsloth stellt sie auf demselben Port bereit, sodass ein einziger `sk-unsloth-…` Schlüssel beide authentifiziert.

### ❔ Fehlerbehebung

**`401 Unauthorized`**  Die `UNSLOTH_STUDIO_API_KEY` Umgebungsvariable ist nicht gesetzt, oder der Schlüssel ist falsch. Exportiere sie erneut und bestätige mit `echo $UNSLOTH_STUDIO_API_KEY`.

**`404 Nicht gefunden` vom OpenAI SDK** Prüfe, dass `base_url` endet auf `/v1`. Das OpenAI SDK hängt Endpunktpfade unverändert an die Basis-URL an.

**`404 Nicht gefunden` vom Anthropic SDK** Prüfe, dass `base_url` endet **nicht** auf `/v1`. Das Anthropic SDK fügt `/v1/messages` selbst hinzu.

**`extra_body` Felder erreichen Unsloth nicht** Stelle sicher, dass du ein aktuelles `openai` / `anthropic` SDK verwendest. Ältere Versionen verwerfen unbekannte Felder stillschweigend. Aktualisiere mit `pip install -U openai anthropic`.

**Streaming „hängt“ und gibt dann alles auf einmal aus** Was auch immer deine Ausgabe umhüllt, puffert. In einem Skript `print(..., flush=True)`; in einem Notebook ist es normalerweise in Ordnung; hinter einem Proxy deaktiviere die Antwortpufferung im Proxy.

Bei Problemen auf Endpunktebene (falscher Port, Modell lädt nicht, Verbindung verloren usw.) siehe die API-Übersichtsseite.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://unsloth.ai/docs/de/integrationen/python-sdk-mit-unsloth-verbinden.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
