SovrGPT Dokumentation
API

POST /v1/chat/completions

Chat-Completions der SovrGPT-API im OpenAI-Schema: Request-Felder, Streaming, Denk-Aufwand, Werkzeuge, Bildeingabe, Modell-Kopfzeilen und Fehlercodes.

Erzeugt eine Modellantwort auf einen Chatverlauf. Schema und Streaming entsprechen OpenAI; zusätzlich nennt jede Antwort in einer Kopfzeile das Modell, das tatsächlich geantwortet hat.

curl https://sovrgpt.com/api/v1/chat/completions \
  -H "Authorization: Bearer $SOVR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemma-4-12b",
    "messages": [
      { "role": "system", "content": "Du bist ein hilfreicher Assistent." },
      { "role": "user",   "content": "Erkläre Diffusionsmodelle in zwei Sätzen." }
    ],
    "temperature": 0.5,
    "max_tokens": 400
  }'

Request-Body

FeldTypDefaultBeschreibung
modelstring–Modell-ID aus GET /v1/models.
messagesarray–Chatverlauf. Rollen: system, user, assistant, tool.
temperaturenumber0.70.0 – 2.0. Höher = kreativer.
top_pnumber1.0Nucleus-Sampling.
max_tokensintModell-DefaultMaximale Antwortlänge in Token.
streamboolfalsetrue → SSE-Stream.
stopstring|array–Stop-Sequenzen.
toolsarray–OpenAI-Tool-Schema (Function-Calling).
tool_choicestring|object"auto""none", "auto", "required" oder ein bestimmtes Tool.
response_formatobject–{ "type": "json_object" } für den JSON-Modus.
reasoning_effortstring–Denk-Aufwand. Welche Modelle ihn auswerten, steht in effort_levels von GET /v1/models. Siehe Denk-Level.
chat_template_kwargsobject–Argumente für die Chat-Vorlage des Modellservers, unverändert durchgereicht (z. B. { "enable_thinking": false } für Qwen). Hat Vorrang vor reasoning_effort.

Weitere OpenAI-Felder (seed, logit_bias, user, presence_penalty, frequency_penalty) reichen wir unverändert an den Modellserver weiter; ob sie wirken, hängt vom Modell ab. n > 1 wird nicht unterstützt.

Denk-Level (reasoning_effort)

Viele Modelle können je Anfrage unterschiedlich gründlich „denken“. Sie steuern das wie bei OpenAI über reasoning_effort (im Python-SDK über extra_body):

curl https://sovrgpt.com/api/v1/chat/completions \
  -H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "stackit-qwen3.8-27b",
    "messages": [{ "role": "user", "content": "Finde und behebe den Bug in diesem Stacktrace …" }],
    "reasoning_effort": "high"
  }'

GET /v1/models nennt je Modell in effort_levels die Stufen, deren Wirkung wir gemessen haben. Ein leeres Array heißt: kein wirksamer Regler, ein trotzdem gesendeter Wert wird nicht übersetzt. Modelle, die einen Wert zwar annehmen, aber ignorieren, führen keine Stufen.

WertBedeutung
weggelassenVoreinstellung des Modells.
noneNicht denken, schnellste Antwort.
minimal, lowSparsam.
mediumNormal.
high, max, xhighGründlich.

Führt ein Modell die gewünschte Stufe nicht (manche haben nur low und high), nehmen wir die nächstniedrigere vorhandene, nie eine höhere.

Beim Modell kommt je nach Anbieter etwas anderes an: ein Token-Deckel statt einer Stufe, andere Stufennamen oder eine umgekehrte Skala. Diese Übersetzung übernimmt der Server. Sie schicken immer low, medium oder high.

high kann das Antwortbudget aufbrauchen. Der Gedankengang zählt gegen max_tokens. Bei stackit-gpt-oss-120b bleibt mit high und knappem max_tokens der Antworttext leer (gemessen). Heben Sie max_tokens mit an.

Antwort (ohne Streaming)

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1715520000,
  "model": "gemma-4-12b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Diffusionsmodelle …"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 87,
    "total_tokens": 129
  }
}

Welches Modell geantwortet hat

Jede Antwort trägt diese Kopfzeilen, mit und ohne Streaming und auch beim 503 unten:

KopfzeileWannBedeutung
x-sovrgpt-model-servedimmerDie Katalog-ID, die tatsächlich geantwortet hat.
x-sovrgpt-model-requestednur bei ErsetzungDie ID, die Sie geschickt haben — ohne Leerraum am Rand und höchstens 200 Zeichen; Zeichen außerhalb von druckbarem ASCII erscheinen als ?.
x-sovrgpt-model-substitutednur bei Ersetzungunavailable: die ID ist bekannt, aber gerade nicht bedienbar, z. B. ein externes Modell ohne hinterlegten Anbieter-Schlüssel.

Unbekannte Modell-IDs: 404

Eine unbekannte Modell-ID (ein Tippfehler, gpt-4o, eine Embedding-ID wie bge-m3) scheitert mit HTTP 404 und dem Code model_not_found. Tragen Sie dann eine ID aus GET /v1/models ein.

curl -s -X POST https://sovrgpt.com/api/v1/chat/completions \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hallo"}]}'

# {"error":{"message":"The model 'gpt-4o' does not exist. Call GET /v1/models for the list you may use.","type":"invalid_request_error","param":"model","code":"model_not_found"}}

Bis zum 14.10.2026 hat SovrGPT eine unbekannte ID stattdessen durch das Standardmodell ersetzt.

Nicht betroffen: Aliase und Rollennamen (unten), eine Anfrage ganz ohne model (sie bekommt wie bisher das Standardmodell) und unavailable (eine bekannte ID, die gerade nicht bedienbar ist).

Ein Alias ist keine Ersetzung. coding löst auf qwen3.6-35b-a3b auf; dann steht nur x-sovrgpt-model-served da. Rollennamen wie coder zeigen nach einem Modellwechsel auf den Nachfolger, ebenfalls ohne Ersetzungs-Kopfzeile. Ist Ihnen die Rolle wichtiger als das konkrete Modell, schicken Sie den Rollennamen.

Ein zurückgezogenes Modell: 404 model_withdrawn

Eine ID, die es bei uns gab und die wir zurückgezogen haben, wird nicht ersetzt. Sie scheitert mit eigenem Code und nennt den Nachfolger:

{
  "error": {
    "message": "The model 'qwen3-coder-next-fp8' has been withdrawn and is no longer served. Zurückgezogen am 2026-09-11 (32 768 Token Kontext, von 'qwen3.6-35b-a3b' überholt). Nachfolger: 'qwen3.6-35b-a3b' … Call GET /v1/models for the list you may use.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_withdrawn"
  }
}

HTTP 404, dazu die Kopfzeile x-sovrgpt-model-withdrawn mit der betroffenen ID. Wer ausdrücklich ein bestimmtes Modell benannt hat, ist mit einem klaren Fehler besser bedient als mit einem allgemeinen Ersatz.

Die beiden 404-Codes verlangen verschiedene Reaktionen:

CodeBedeutungWas hilft
model_not_foundIhre Organisation hat dieses Modell nicht freigeschaltet, oder ein eigenes Modell (org-model:…) ist pausiert oder gelöscht. Oder die ID gibt es gar nicht (Meldung „does not exist“).Ein Org-Admin kann es unter Einstellungen → Modelle aktivieren. Bei „does not exist“ eine ID aus GET /v1/models eintragen.
model_withdrawnDas Modell gibt es nicht mehr.Niemand kann es aktivieren. Tragen Sie den genannten Nachfolger ein.

Streaming (SSE)

Mit "stream": true:

data: {"id":"chatcmpl-abc","choices":[{"delta":{"role":"assistant"},"index":0}]}
data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Diff"},"index":0}]}
data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"usions"},"index":0}]}
…
data: {"id":"chatcmpl-abc","choices":[{"delta":{},"finish_reason":"stop","index":0}]}
data: [DONE]

Das Format entspricht OpenAI; der Streaming-Modus der OpenAI-SDKs funktioniert unverändert. Kommt länger als zehn Sekunden kein Token, etwa während das Modell denkt, sendet der Server die Kommentarzeile : keep-alive, damit die Verbindung offen bleibt. SSE-Clients ignorieren sie.

Wenn das Modell erst hochfahren muss: 503

Selbst betriebene Modelle fahren auf null herunter, wenn niemand sie nutzt. Erkennen wir vor dem Absenden, dass nachweislich kein Worker bereit ist, antworten wir sofort:

HTTP/1.1 503 Service Unavailable
Retry-After: 60

{"error":{"message":"The model 'qwen3.8-27b' is scaled to zero and has no worker ready. A warm-up has been started for you — retry in about a minute. Typical cold start: …","type":"api_error","param":null,"code":"model_cold_start"}}

Das Hochfahren ist dann bereits angestoßen. Warten Sie Retry-After Sekunden und schicken Sie dieselbe Anfrage erneut. Ein Kaltstart dauert je nach Modell mehrere Minuten, oft sind also mehrere Versuche nötig. Die Größenordnung je Modell steht in der Meldung und unter Modelle.

Eine laufende Antwort brechen wir nicht ab. Wir prüfen nur vor dem Absenden. Ist der Zustand dann nicht sicher erkennbar, wartet die Anfrage, bis das Modell bereit ist. Die Obergrenze je Anfrage liegt bei 780 Sekunden; setzen Sie Ihr Client-Timeout entsprechend.

Partner-Modelle (tensorx-…, stackit-…) und die eigenen Endpunkte Ihrer Organisation haben keinen Kaltstart und liefern dieses 503 nie.

Wenn mitten im Stream etwas schiefgeht

Sobald das erste Byte gesendet ist, steht der HTTP-Status fest (200). Ein späterer Fehler kommt deshalb im Stream, als drei Rahmen in dieser Reihenfolge:

data: {"id":"chatcmpl-err-…","object":"chat.completion.chunk","created":1700000000,"model":"gemma-4-12b","choices":[{"index":0,"delta":{},"finish_reason":"error"}]}

event: error
data: {"error":{"message":"upstream error","type":"api_error","param":null,"code":"upstream_502"}}

data: [DONE]
  • Der Abschluss-Rahmen kommt zuerst und setzt finish_reason: "error". Daran erkennen Sie, dass die Antwort unvollständig ist.
  • Der Fehler-Rahmen trägt die Felder message, type, param und code.
  • [DONE] schließt den Stream wie im Erfolgsfall.

type ist eine der üblichen Kategorien (authentication_error, permission_error, rate_limit_error, invalid_request_error, api_error). code trägt bei einem durchgereichten Anbieterfehler dessen eigenen Code, sonst upstream_<HTTP-Status>.

Werten Sie jeden Rahmen einzeln aus und brechen Sie bei finish_reason: "error" ab. error kommt bewusst in einem eigenen Rahmen: Viele Client-Bibliotheken verwerfen das Feld, wenn es im selben Rahmen wie choices steht, und der Fehler ginge verloren.

Bildeingabe (Vision)

Nur bei Modellen mit accepts_vision: true, z. B. gemma-4-12b und gemma-4-26b-a4b:

{
  "model": "gemma-4-26b-a4b",
  "messages": [
    {
      "role": "user",
      "content": [
        { "type": "text", "text": "Was ist auf dem Bild?" },
        { "type": "image_url", "image_url": { "url": "https://…/foto.jpg" } }
      ]
    }
  ]
}

image_url.url kann eine öffentliche URL oder eine Base64-Data-URL sein (data:image/png;base64,…).

Function-Calling (Tools)

Wie bei OpenAI. Ob ein Modell Werkzeuge beherrscht, steht in accepts_tools von GET /v1/models. Beispiel:

{
  "model": "gemma-4-12b",
  "messages": [{ "role": "user", "content": "Was kostet ein Bitcoin?" }],
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_price",
      "description": "Holt aktuellen Preis",
      "parameters": {
        "type": "object",
        "properties": { "symbol": { "type": "string" } },
        "required": ["symbol"]
      }
    }
  }]
}

Die Antwort enthält tool_calls wie bei OpenAI. Ihr Client führt die Funktion aus und schickt das Ergebnis als Nachricht mit role: "tool" zurück.

Gedankengang (reasoning_content)

Modelle mit sichtbarem Gedankengang, etwa qwen3.5-9b-deepseek-v4 (reasoning-Tier), liefern ihn im eigenen Feld reasoning_content, getrennt vom Antworttext in content. Im Stream steht er im delta. Der Gedankengang zählt gegen max_tokens.

POST /v1/chat/completions