Dokumentation

Dokumentation

Chat Completions

Kunavos Endpunkt /v1/chat/completions verwendet das OpenAI-Chat-Completions-Protokoll für die Claude- und GPT-Familien. Streaming, Tools und JSON-Ausgabe funktionieren mit demselben SDK. Die Bedeutung von reasoning_effort hängt von der Modellfamilie ab; auf dieser Seite erfahren Sie, welche Funktion es jeweils hat.

Endpunkt: POST /v1/chat/completions. Request und Response entsprechen exakt der OpenAI-Chat-Completions-API — einschließlich Streaming und der optionalen Felder tool_calls / reasoning_tokens.

Einfacher Aufruf

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "system", "content": "You are a senior staff engineer."},
        {"role": "user", "content": "Pros and cons of postgres LISTEN/NOTIFY for a job queue?"},
    ],
    max_tokens=800,
)
print(resp.choices[0].message.content)

Parameter

Alle standardmäßigen OpenAI-Parameter werden akzeptiert. Einige sind nur für bestimmte Anbieter sinnvoll — der Übersetzer leitet die jeweils vom Upstream unterstützten Parameter weiter.

ParameterTypHinweise
modelString (erforderlich)Jeder aktivierte Slug aus /v1/models.
messagesArray (erforderlich)Standardmäßiges OpenAI-Nachrichtenformat.
temperature0..2Sampling-Temperatur. Standardwert 1. Hat keine Auswirkung auf die unter dieser Tabelle aufgeführten Modelle.
top_p0..1Nucleus-Sampling. Dieselbe Ausnahme wie bei temperature.
max_tokensintAusgabelimit; max_completion_tokens hat Vorrang, wenn beide gesendet werden. Bei GPT-Modellen zählen Reasoning-Tokens dazu. Eine Claude-Anfrage, die keines von beiden sendet, erhält den Wert 4.096.
streamboolChunks als SSE streamen. Siehe unten.
toolsarrayFunction- / Tool-Definitionen. Claude und GPT unterstützen beide die Tool-Nutzung.
tool_choiceauto|none|namedEin bestimmtes Tool erzwingen oder das Modell entscheiden lassen.
response_formatobjectJSON-Ausgabe. Bei Claude wird ein json_schema erzwungen, ein json_object dagegen nicht — Einzelheiten zu allen Modellfamilien finden Sie unter JSON-Ausgabe.
reasoning_effortstringNur GPT-Modelle — wird als reasoning.effort weitergeleitet. Für Claude wird es nicht weitergeleitet. Siehe Reasoning.
seedintDeterministisches Sampling, sofern unterstützt.
stopstring|arrayHarte Stoppsequenzen.
Bei Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4.8, Claude Opus 4.7 und Claude Sonnet 5 werden weder temperature noch top_p noch top_k akzeptiert. Kunavo entfernt diese drei Parameter aus Anfragen an solche Modelle, statt den 400-Fehler des Anbieters an Sie zurückzugeben. Daher haben sie bei diesen Modellen keine Wirkung.

Streaming

Setzen Sie stream=True. Kunavo gibt Server-Sent Events exakt im OpenAI-Format aus: Jeder Chunk ist ein chat.completion.chunk mit choices[0].delta.content. Die abschließende Nutzungsangabe wird mit data: [DONE] übermittelt.

stream = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Explain B-trees in one paragraph."}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
Streaming funktioniert mit allen Chat-Modellen. Bei Claude (mit Anthropic-Protokoll als Upstream) übersetzen wir den Anthropic-Event-Stream während der Übertragung in OpenAI-Deltas — Ihr SDK bemerkt keinen Unterschied.

Tool- / Function-Aufrufe

Tool-Aufrufe funktionieren über alle Anbieter hinweg. Definieren Sie Tools als JSON-Schema. Das Modell gibt in seiner Nachricht tool_calls zurück. Sie führen die Tools aus und senden die Ergebnisse als role: "tool"-Nachrichten zurück.

tools = [{
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "Get current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"},
                "unit": {"type": "string", "enum": ["c", "f"]},
            },
            "required": ["city"],
        },
    },
}]

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
    tools=tools,
    tool_choice="auto",
)

# Inspect tool calls the model wants to make
for call in resp.choices[0].message.tool_calls or []:
    print(call.function.name, call.function.arguments)

JSON-Ausgabe (response_format)

response_format fordert JSON an. Was damit garantiert wird, hängt von der Modellfamilie ab, da die Anfrage für jede Familie in einen anderen Upstream-Mechanismus übersetzt wird:

Familiejson_schemajson_object
ClaudeErzwungen. Wird als strukturierte Ausgabe von Anthropic (output_config.format) gesendet. Die Antwort entspricht dem Schema. Dies wurde am 2026-09-24 für jedes von Kunavo bereitgestellte Claude-Modell geprüft.Nicht erzwungen. Anthropic bietet keinen JSON-Modus ohne Schema. Daher wird die Anfrage akzeptiert, aber ignoriert — die Antwort kann mit Fließtext oder einem Codeblock beginnen.
GPTWird als text.format der Responses API weitergeleitet, aber der aktuelle Upstream wendet es nicht bei jeder Anfrage an. Validieren Sie die Antwort, bevor Sie sie parsen.Wird als text.format weitergeleitet.
import json

resp = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Jane Doe <jane@example.com> wants the Pro plan."}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "signup",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                    "plan": {"type": "string", "enum": ["free", "pro", "enterprise"]},
                },
                "required": ["name", "email", "plan"],
                "additionalProperties": False,
            },
        },
    },
)
signup = json.loads(resp.choices[0].message.content)  # constrained to the schema

Bei Claude sind vier Dinge zu beachten:

  • Das Schema wird fast genau so an Anthropic übermittelt, wie Sie es geschrieben haben. Anthropic verlangt bei Objekten additionalProperties: false. Kunavo fügt es daher jedem Objekt mit aufgeführten Properties hinzu und lässt es bei Objekten ohne Properties weg — so erzeugt es Pydantics model_json_schema(). Anthropic weist Folgendes weiterhin mit einem 400-Fehler zurück, der das Problem benennt: ein offenes Objekt (additionalProperties hat einen anderen Wert als false oder es sind keine Properties aufgeführt und additionalProperties ist nicht gesetzt) sowie oneOf — verwenden Sie anyOf. Die übrigen Einschränkungen sind auf der Seite Strukturierte Ausgaben von Anthropic aufgeführt.
  • strict und name werden ignoriert: Anthropic erzwingt jedes akzeptierte Schema, unabhängig davon, ob es als strict markiert ist.
  • Ein Schema kann nicht mit einer abschließenden assistant-Nachricht (einem Prefill) kombiniert werden. Anthropic antwortet mit 400.
  • Wenn max_tokens mitten im Objekt ausgeschöpft ist, wird das JSON abgeschnitten und finish_reason ist "length".

Vision- / multimodale Eingabe

Modelle mit der Fähigkeit vision akzeptieren Bildinhaltsblöcke. Verwenden Sie entweder eine HTTPS-URL oder einen data:-Base64-URI.

# Pass an image URL or a base64 data URI as part of a multimodal message
resp = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {"type": "image_url", "image_url": {
                "url": "https://example.com/cat.jpg"
            }},
        ],
    }],
)
print(resp.choices[0].message.content)

Der Katalog enthält Vision-fähige Modelle, darunter Claude Opus 5.5 — die übrigen finden Sie in der Modellliste.

Bei einem HTTPS-Bild lädt Kunavo die Datei selbst herunter und übergibt sie dem Modell inline, da manche Upstreams eine unverarbeitete Bild-URL ignorieren. Beschränkungen: 16 Bilder pro Anfrage, 5 MB pro Bild, insgesamt 20 MB und 10 Sekunden pro Download. Kann ein Bild nicht abgerufen werden, wird ein Fehler zurückgegeben, der es benennt, statt es zu überspringen.

Schlussfolgern

Die Wirkung einer Reasoning-Steuerung an diesem Endpunkt hängt von der Modellfamilie ab, da die Anfrage jeder Familie in eine andere Upstream-API übersetzt wird:

Familiereasoning_effortReasoning-Tokens in usage
GPTWird unter GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra und GPT-5.5 wertgetreu als reasoning.effort der Responses API weitergeleitet. Die akzeptierten Werte richten sich nach dem Modell selbst. Bei GPT-6 Sol und GPT-6 Luna schaltet none Reasoning aus, und max ist die höchste Stufe.In completion_tokens enthalten und als completion_tokens_details.reasoning_tokens separat ausgewiesen; Abrechnung zum Ausgabetarif.
ClaudeNicht weitergeleitet. Die Anthropic-Anfrage wird aus einer festen Liste von Feldern erstellt — model, max_tokens, messages, stream, temperature, top_p, top_k, stop, tools, tool_choice und response_format — daher werden reasoning_effort, thinking und alle anderen Felder außerhalb dieser Liste hier verworfen.Keine Aufschlüsselung. Anthropic zählt jegliches Thinking zu seinem output_tokens. Das wird von completion_tokens gemeldet.
# GPT models: reasoning_effort is forwarded as the Responses API's
# reasoning.effort. Reasoning tokens are part of completion_tokens.
resp = client.chat.completions.create(
    model="gpt-6-sol",
    messages=[{"role": "user", "content": "Plan a 3-week MLOps migration."}],
    reasoning_effort="high",
)
details = resp.usage.completion_tokens_details   # absent when no reasoning ran
print(details.reasoning_tokens if details else 0)
Extended Thinking bei Claude wird über die native Messages API abgewickelt, die thinking unverändert an Anthropic weiterleitet.

Prompt-Caching

Ein langer System-Prompt, ein Referenzdokument, ein Few-Shot-Block – jeder stabile Präfix kann vorgelagert zwischengespeichert und bei späteren Aufrufen zu einem Bruchteil des Eingabepreises wiederverwendet werden. Cache-Treffer werden im Nutzungsobjekt als prompt_tokens_details.cached_tokens ausgewiesen.

GPT-Modelle cachen automatisch – eine Änderung an der Anfrage ist nicht erforderlich. cached_tokens ist eine Teilmenge von prompt_tokens und wird zu einem reduzierten Cache-Lesetarif abgerechnet.

Claude cacht nur bis zu einem cache_control-Breakpoint, und bei einem langen Prompt setzt dieser Endpunkt die Breakpoints für Sie: am System-Prompt, an den Tool-Definitionen und an der letzten Nachricht, sobald die Unterhaltung eine Assistentenantwort enthält. Um das Präfix selbst zu wählen, fügen Sie cache_control wie unten an einen Inhaltsblock an; Kunavo behält Ihre Breakpoints bei und fügt eigene nur an Positionen hinzu, die Sie frei gelassen haben:

# Claude caches prefixes you mark with cache_control. Attach it to a content
# block; later calls reusing that prefix read it at ~10% of the input price.
resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": LONG_DOCUMENT,            # the stable, reused prefix
                "cache_control": {"type": "ephemeral"},
            },
            {"type": "text", "text": "Summarize the document above."},
        ],
    }],
)
print(resp.usage.prompt_tokens_details.cached_tokens)
Für die vollständige Kontrolle über das Claude-Prompt-Caching – einschließlich des Cachings von System-Prompt und Tool-Definitionen, mehrerer Breakpoints und der nativen Nutzungsfelder cache_creation_input_tokens / cache_read_input_tokens – verwenden Sie die native Messages API. Auch dieser Endpunkt cacht den System-Prompt und die Tool-Definitionen, nimmt mehrere Breakpoints in einer Anfrage an und meldet Cache-Schreibvorgänge als cache_creation_input_tokens und Cache-Lesevorgänge als prompt_tokens_details.cached_tokens; nur der native Endpunkt gibt Ihren Request-Body ohne hinzugefügten Breakpoint weiter.

Nutzungsobjekt

Jede Antwort (und der letzte Streaming-Chunk) enthält ein usage-Objekt:

FeldBedeutung
prompt_tokensAbgerechnete Eingabe-Token – einschließlich gecachter Token.
prompt_tokens_details.cached_tokensGecachte Eingabe – eine Teilmenge von prompt_tokens, die zu einem reduzierten Cache-Lesetarif abgerechnet wird.
completion_tokensVon uns abgerechnete Ausgabetokens. Bei GPT-Modellen umfasst dies die Reasoning-Tokens; bei Claude entspricht es Anthropic's output_tokens.
completion_tokens_details.reasoning_tokensGPT-Modelle: der Anteil von completion_tokens, der auf das Reasoning entfällt. Fehlt bei null und wird für Claude nicht ausgewiesen.
total_tokensprompt_tokens + completion_tokens.

Ollama-OpenAI-Kompatibilität — /v1/chat/completions

Ollama stellt seine lokalen Modelle über eine OpenAI-kompatible API unter http://localhost:11434/v1 bereit und implementiert denselben /chat/completions-Vertrag, der auf dieser Seite dokumentiert ist. Dadurch sind beide auf Client-Seite austauschbar: Alles, was für Ollamas v1-API geschrieben wurde, funktioniert auch mit Kunavo, wenn Sie die Basis-URL und das Modell ändern.

from openai import OpenAI

# Before — Ollama's OpenAI-compatible API, local models
client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",                       # ignored locally
)
resp = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Summarize this changelog."}],
)

# After — the same call against hosted frontier models.
# Two lines changed. Everything below them is untouched.
client = OpenAI(
    base_url="https://api.kunavo.com/v1",   # <- was localhost:11434/v1
    api_key=os.environ["KUNAVO_API_KEY"],
)
resp = client.chat.completions.create(
    model="claude-sonnet-5",  # <- was llama3.2
    messages=[{"role": "user", "content": "Summarize this changelog."}],
)

Die Dinge, die bei einem Anbieterwechsel üblicherweise Probleme bereiten, funktionieren hier, weil das Drahtformat identisch ist:

FunktionOllama v1Kunavo v1
Endpunktpfad/v1/chat/completions/v1/chat/completions
StreamingSSE, chat.completion.chunkIdentisch – gleiche Delta-Form
Tool-Aufrufetools / tool_callsBei Claude und GPT identisch
Bildeingabeimage_url-Blöcke bei multimodalen lokalen ModellenDieselben Blöcke; URL oder Base64-Daten-URI
api_keyPlatzhalter, wird ignoriertEin echter Kunavo-Schlüssel
modelEin heruntergeladenes Tag (llama3.2)Ein gehosteter Slug (claude-sonnet-5)
zusätzliche NutzungsdatenNur Token-ZählungenErgänzt cached_tokens und reasoning_tokens
Über Chat hinauscompletions, embeddingsZusätzlich Endpunkte für Bilder, Video und Audio
Beide behalten? Lesen Sie base_url, model und den Schlüssel aus Umgebungsvariablen aus und wechseln Sie je nach Umgebung – lokale Modelle für Offline-Iterationen, gehostete Modelle, wenn die Qualität zählt, mit einem gemeinsamen Codepfad. Die vollständige Anleitung, einschließlich der Funktionen, die Ollamas OpenAI-Schnittstelle unterstützt und nicht unterstützt, finden Sie im Leitfaden zur OpenAI-kompatiblen Ollama-API.

Wo finde ich die offizielle Dokumentation zu Ollamas OpenAI-kompatiblem Endpunkt /v1/chat/completions?

Ollama dokumentiert seine OpenAI-Kompatibilitätsschicht im eigenen Repository unter docs/openai.md. Diese Dokumentation ist die maßgebliche Referenz dafür, welche OpenAI-Felder der lokale Server implementiert. Diese Seite ist die entsprechende Referenz für Kunavos gehosteten Endpunkt /v1/chat/completions: Sie dokumentiert oben Feld für Feld denselben OpenAI-Chat-Completions-Vertrag, sodass Sie die beiden Schnittstellen direkt vergleichen können. Kurz gesagt: Request und Response haben dieselbe Struktur — Ollama stellt den Endpunkt unter http://localhost:11434/v1 für lokal heruntergeladene Modelle bereit, Kunavo unter https://api.kunavo.com/v1 für gehostete Claude- und GPT-Modelle.

Ist Kunavos /v1/chat/completions mit Ollamas OpenAI-API kompatibel?

Ja — beide implementieren denselben OpenAI-Chat-Completions-Vertrag. Daher funktioniert ein für Ollamas http://localhost:11434/v1 geschriebener Client unverändert mit https://api.kunavo.com/v1. Die Request-Felder (messages, temperature, max_tokens, stream, tools, tool_choice, response_format, stop, seed) und die Response-Felder (choices[].message, choices[].delta bei Streams, usage) stimmen überein. Die Unterschiede entsprechen den Erwartungen an gehostete Modelle: api_key ist ein echter Schlüssel statt eines Platzhalters, bei model wird ein gehosteter Slug wie claude-sonnet-5 statt eines heruntergeladenen Tags wie llama3.2 verwendet, und usage enthält cached_tokens und reasoning_tokens, die von lokalen Modellen nicht gemeldet werden.

Wie migriere ich eine Ollama-App zu gehostetem Claude oder GPT?

Ändern Sie zwei Zeilen: Setzen Sie base_url von http://localhost:11434/v1 auf https://api.kunavo.com/v1 und ändern Sie model vom lokalen Tag zu einem gehosteten Slug. Verwenden Sie einen echten Kunavo-Schlüssel statt des Platzhalters, den Ollama ignoriert. Am Code für Streaming, Tool-Aufrufe und Vision müssen Sie nichts ändern, da die SSE- und tool_calls-Strukturen identisch sind.

Kann ich Ollama in der Entwicklung und gehostete Modelle in der Produktion verwenden?

Ja, das ist eine gängige Konfiguration — lesen Sie Basis-URL, Modell und Schlüssel aus Umgebungsvariablen und wechseln Sie je nach Umgebung. Da beide Seiten dasselbe OpenAI-Protokoll verwenden, muss kein zweiter Codepfad gepflegt werden: lokales Llama oder Qwen für Offline-Iterationen, gehostetes Claude oder GPT, wenn es auf die Qualität ankommt. Tool-Definitionen und Streaming-Handler können unverändert gemeinsam genutzt werden.

Welche OpenAI-Endpunkte bietet Kunavo zusätzlich zu Ollamas kompatibler Schnittstelle?

Ollamas OpenAI-kompatible Schnittstelle umfasst /chat/completions, /completions, /embeddings und /models. Kunavo ergänzt Media-Endpunkte, die denselben Schlüssel verwenden: /v1/images/generations, /v1/images/edits, /v1/video/generations, /v1/videos und /v1/audio/music sowie Claude über den nativen Anthropic-Endpunkt /v1/messages. Zwei wichtige Einschränkungen in die andere Richtung: /v1/audio/speech, /v1/audio/transcriptions und /v1/embeddings sind zwar als Wire-Formate implementiert, aber derzeit ist dahinter kein Modell aktiviert. Daher funktionieren sie aktuell nicht — und anders als Ollama führt Kunavo keine Modelle lokal aus. Maßgeblich dafür, was aufrufbar ist, ist immer GET /v1/models.

Nächste Schritte