# Chat-Completions-API

> POST /v1/chat/completions bei OpenCheese: Beispiele in curl, Python und JavaScript für Anfragen, Streaming, Tool-Aufrufe, Bildeingabe und Reasoning-Stufe.
>
> Webseite: https://opencheese.dev/de/docs/chat-completions/ · Alle Seiten der Doku: https://opencheese.dev/de/docs.md

`POST https://api.opencheese.dev/v1/chat/completions` ist die Chat-Completions-API von OpenAI.
Die OpenAI-SDKs, OpenCode, Zed, Harness AI und die meisten Chat-Apps nutzen sie.

## Eine erste Anfrage

```bash
curl https://api.opencheese.dev/v1/chat/completions \
  -H "Authorization: Bearer $OPENCHEESE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "messages": [{"role": "system", "content": "Answer in one sentence."}, {"role": "user", "content": "What is a gateway?"}]}'
```

`model` und `messages` sind Pflichtfelder. Die Modell-ID liefert
[`GET /v1/models`](https://opencheese.dev/de/docs/models.md).

Die Antwort hat die gewohnte Form:

```json
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "model": "MODEL_ID",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "A gateway passes your requests on to the models behind it." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 24, "completion_tokens": 13, "total_tokens": 37 }
}
```

## Parameter

| Feld | Hinweise |
| --- | --- |
| `model` | Pflichtfeld. Eine `id` aus `/v1/models`. |
| `messages` | Pflichtfeld. Nachrichten mit den Rollen `system`, `user`, `assistant` und `tool`. |
| `stream` | `true` für Server-Sent Events. |
| `tools`, `tool_choice` | Function Calling, sofern das Modell Tools unterstützt. |
| `reasoning_effort` | Eine Stufe aus den `supported_reasoning_levels` des Modells. |
| `response_format` | Strukturierte Ausgabe, sofern das Modell sie unterstützt. |
| `temperature`, `top_p`, `max_tokens` | Optional. Setzt du sie nicht, gelten die Standardwerte des Modells. |

## Streaming

```bash
curl -N https://api.opencheese.dev/v1/chat/completions \
  -H "Authorization: Bearer $OPENCHEESE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "stream": true, "messages": [{"role": "user", "content": "Count to three."}]}'
```

Jedes Event ist ein `chat.completion.chunk`; der Text steht in `choices[0].delta.content`.
Gegen Ende folgen `finish_reason` und `usage`, und der Stream endet mit `data: [DONE]`:

```text
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"One"},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":", two, three."},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":6,"total_tokens":18}}

data: [DONE]
```

## Tool-Aufrufe

```bash
curl https://api.opencheese.dev/v1/chat/completions \
  -H "Authorization: Bearer $OPENCHEESE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "messages": [{"role": "user", "content": "What is the weather in Paris?"}], "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Current weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}]}'
```

Ruft das Modell ein Tool auf, ist `finish_reason` in der Antwort `tool_calls`, und
`message.tool_calls` enthält den Aufruf. Führe das Tool aus und sende dann den Verlauf zurück,
ergänzt um eine `tool`-Nachricht mit dem Ergebnis:

```json
{
  "model": "MODEL_ID",
  "messages": [
    { "role": "user", "content": "What is the weather in Paris?" },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [{ "id": "call_1", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } }]
    },
    { "role": "tool", "tool_call_id": "call_1", "content": "18 degrees, sunny" }
  ]
}
```

Wird eine Antwort mitten in einem Tool-Aufruf vom Ausgabelimit abgeschnitten, endet sie mit
`finish_reason: "length"`: Behandle diesen Tool-Aufruf als unvollständig und führe ihn nicht
aus.

## Bilder im Prompt

Modelle, deren `modalities.input` den Wert `image` enthält, lesen Bilder, die als
`image_url`-Teile gesendet werden, entweder als `https://`-Adresse oder als `data:`-URL:

```json
{
  "model": "MODEL_ID",
  "messages": [
    {
      "role": "user",
      "content": [
        { "type": "text", "text": "What is in this picture?" },
        { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KGgo..." } }
      ]
    }
  ]
}
```

## Reasoning-Stufe

Setze `reasoning_effort` auf eine der Stufen, die das Modell in `supported_reasoning_levels`
auflistet (`reasoning.effort` und `output_config.effort` aus der Anthropic-API werden ebenfalls
gelesen). Setzt du keine, gilt die Standardstufe des Modells.

```bash
curl https://api.opencheese.dev/v1/chat/completions \
  -H "Authorization: Bearer $OPENCHEESE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "reasoning_effort": "high", "messages": [{"role": "user", "content": "Plan a three-day trip to Lyon."}]}'
```

Eine Stufe, die das Modell nicht anbietet, wird mit `unsupported_reasoning_effort` abgelehnt,
und der Fehler nennt die Stufen, die es anbietet. Reasoning-Text kommt, sofern das Modell ihn
liefert, in `message.reasoning_content` (beim Streaming in `delta.reasoning_content`).

## Bildmodelle im Chat

Wählst du ein Bildmodell (sein `modalities.output` ist `image`), wird die letzte Nachricht des
Nutzers zum Bild-Prompt. Das Bild kommt in `message.images` als `data:`-URL, und ein in der
Unterhaltung gesendetes Bild wird bearbeitet, sofern das Modell das kann.
Bildmodelle liefern ein Bild pro Anfrage; für alle Bildparameter nutzt du die
[Bild-API](https://opencheese.dev/de/docs/images.md).

## Fehler, die als Antwort ankommen

Probleme, um die du dich kümmern musst, etwa ein ungültiger Schlüssel, ein aufgebrauchter Tarif
oder ein leeres Guthaben, kommen als Nachricht des Assistenten in einer `200`-Antwort, die als
`text/event-stream` gestreamt wird, auch wenn `stream` auf `false` steht. So zeigen Chat-Apps
sie dir an. Alle anderen Fehler kommen als normaler HTTP-Status mit JSON-Body. Prüfe den
`Content-Type` der Antwort, bevor du sie als JSON parst; siehe
[Fehler und Ratenlimits](https://opencheese.dev/de/docs/errors.md).

## SDKs

Python:

```python
from openai import OpenAI

client = OpenAI(base_url="https://api.opencheese.dev/v1", api_key="YOUR_OPENCHEESE_API_KEY")
stream = client.chat.completions.create(
    model="MODEL_ID",
    messages=[{"role": "user", "content": "Write a haiku about cheese."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
```

JavaScript:

```javascript
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.opencheese.dev/v1", apiKey: process.env.OPENCHEESE_API_KEY });
const reply = await client.chat.completions.create({
  model: "MODEL_ID",
  messages: [{ role: "user", content: "Write a haiku about cheese." }]
});
console.log(reply.choices[0].message.content);
```

Damit die Anfragen einer Unterhaltung im Dashboard zusammenbleiben, füge den Header
[`opencheese-session-uuid`](https://opencheese.dev/de/docs/sessions.md) hinzu.
