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.
| Parameter | Typ | Hinweise |
|---|---|---|
model | String (erforderlich) | Jeder aktivierte Slug aus /v1/models. |
messages | Array (erforderlich) | Standardmäßiges OpenAI-Nachrichtenformat. |
temperature | 0..2 | Sampling-Temperatur. Standardwert 1. Hat keine Auswirkung auf die unter dieser Tabelle aufgeführten Modelle. |
top_p | 0..1 | Nucleus-Sampling. Dieselbe Ausnahme wie bei temperature. |
max_tokens | int | Ausgabelimit; max_ 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. |
stream | bool | Chunks als SSE streamen. Siehe unten. |
tools | array | Function- / Tool-Definitionen. Claude und GPT unterstützen beide die Tool-Nutzung. |
tool_choice | auto| | Ein bestimmtes Tool erzwingen oder das Modell entscheiden lassen. |
response_ | object | JSON-Ausgabe. Bei Claude wird ein json_schema erzwungen, ein json_object dagegen nicht — Einzelheiten zu allen Modellfamilien finden Sie unter JSON-Ausgabe. |
reasoning_ | string | Nur GPT-Modelle — wird als reasoning. weitergeleitet. Für Claude wird es nicht weitergeleitet. Siehe Reasoning. |
seed | int | Deterministisches Sampling, sofern unterstützt. |
stop | string|array | Harte Stoppsequenzen. |
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)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:
| Familie | json_schema | json_object |
|---|---|---|
| Claude | Erzwungen. Wird als strukturierte Ausgabe von Anthropic (output_) 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. |
| GPT | Wird 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 schemaBei 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 Pydanticsmodel_json_schema(). Anthropic weist Folgendes weiterhin mit einem 400-Fehler zurück, der das Problem benennt: ein offenes Objekt (additionalPropertieshat einen anderen Wert alsfalseoder es sind keine Properties aufgeführt undadditionalPropertiesist nicht gesetzt) sowieoneOf— verwenden SieanyOf. Die übrigen Einschränkungen sind auf der Seite Strukturierte Ausgaben von Anthropic aufgeführt. strictundnamewerden 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_tokensmitten im Objekt ausgeschöpft ist, wird das JSON abgeschnitten undfinish_reasonist"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:
| Familie | reasoning_ | Reasoning-Tokens in usage |
|---|---|---|
| GPT | Wird 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. 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_ enthalten und als completion_ separat ausgewiesen; Abrechnung zum Ausgabetarif. |
| Claude | Nicht 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_ — daher werden reasoning_, thinking und alle anderen Felder außerhalb dieser Liste hier verworfen. | Keine Aufschlüsselung. Anthropic zählt jegliches Thinking zu seinem output_. Das wird von completion_ 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)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)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:
| Feld | Bedeutung |
|---|---|
prompt_ | Abgerechnete Eingabe-Token – einschließlich gecachter Token. |
prompt_ | Gecachte Eingabe – eine Teilmenge von prompt_ |
completion_ | Von uns abgerechnete Ausgabetokens. Bei GPT-Modellen umfasst dies die Reasoning-Tokens; bei Claude entspricht es Anthropic's output_ |
completion_ | GPT-Modelle: der Anteil von completion_ |
total_tokens | prompt_ |
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:
| Funktion | Ollama v1 | Kunavo v1 |
|---|---|---|
| Endpunktpfad | /v1/ | /v1/ |
| Streaming | SSE, chat. | Identisch – gleiche Delta-Form |
| Tool-Aufrufe | tools / tool_calls | Bei Claude und GPT identisch |
| Bildeingabe | image_url-Blöcke bei multimodalen lokalen Modellen | Dieselben Blöcke; URL oder Base64-Daten-URI |
| api_key | Platzhalter, wird ignoriert | Ein echter Kunavo-Schlüssel |
| model | Ein heruntergeladenes Tag (llama3.2) | Ein gehosteter Slug (claude-sonnet-5) |
| zusätzliche Nutzungsdaten | Nur Token-Zählungen | Ergänzt cached_ |
| Über Chat hinaus | completions, embeddings | Zusätzlich Endpunkte für Bilder, Video und Audio |
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.