Documentazione
completamenti chat
L'endpoint /v1/chat/completions di Kunavo usa il protocollo Chat Completions di OpenAI per le famiglie Claude e GPT. Streaming, strumenti e output JSON funzionano con lo stesso SDK; la funzione di reasoning_effort dipende dalla famiglia e questa pagina spiega quale sia.
Endpoint: POST /v1/chat/completions. La forma della richiesta e della risposta corrisponde esattamente all'API Chat Completions di OpenAI, compresi lo streaming e i campi facoltativi tool_calls / reasoning_tokens.
Chiamata di base
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)Parametri
Sono accettati tutti i parametri standard di OpenAI. Alcuni hanno senso solo per determinati fornitori: il traduttore inoltra quelli supportati da ciascun fornitore upstream.
| Parametro | Tipo | Note |
|---|---|---|
model | stringa (obbligatorio) | Qualsiasi slug abilitato di /v1/models. |
messages | array (obbligatorio) | Formato standard dei messaggi OpenAI. |
temperature | 0..2 | Temperatura di campionamento. Valore predefinito: 1. Non ha effetto sui modelli elencati sotto questa tabella. |
top_p | 0..1 | Campionamento per nucleo. Vale la stessa eccezione indicata per temperature. |
max_tokens | int | Limite dell'output; se vengono inviati entrambi, prevale max_. Nei modelli GPT, i token di ragionamento vengono conteggiati nel limite. Se una richiesta Claude non specifica nessuno dei due, il valore è 4,096. |
stream | bool | Trasmette i segmenti in streaming tramite SSE. Vedi sotto. |
tools | array | Definizioni di funzioni/ |
tool_choice | auto| | Forza uno strumento specifico oppure lascia decidere al modello. |
response_ | object | Output JSON. In Claude viene applicato un vincolo tramite json_schema, ma non tramite json_object: consulta Output JSON per i dettagli di ogni famiglia. |
reasoning_ | string | Solo modelli GPT: viene inoltrato come reasoning.. Non viene inoltrato per Claude. Vedi Ragionamento. |
seed | int | Campionamento deterministico, ove supportato. |
stop | string|array | Sequenze di arresto rigide. |
temperature, top_p o top_k. Kunavo rimuove questi tre campi dalle richieste inviate a tali modelli, anziché inoltrare il 400 del fornitore; non hanno quindi alcun effetto su quei modelli.Streaming
Imposta stream=True. Kunavo emette eventi inviati dal server nel formato esatto di OpenAI: ogni segmento è un chat.completion.chunk con choices[0].delta.content. Il payload finale di utilizzo arriva con data: [DONE].
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)Chiamata agli strumenti / alle funzioni
La chiamata agli strumenti funziona con tutti i fornitori. Definisci gli strumenti tramite uno schema JSON; il modello restituisce tool_calls nel messaggio; esegui lo strumento e reinviane i risultati come messaggi role: "tool".
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)Output JSON (response_format)
response_format richiede JSON. Le garanzie dipendono dalla famiglia di modelli, perché la richiesta di ciascuna famiglia viene tradotta in un meccanismo upstream diverso:
| Famiglia | json_schema | json_object |
|---|---|---|
| Claude | Applicato. Inviato come output strutturato di Anthropic (output_); la risposta è vincolata al tuo schema. Verificato su tutti i modelli Claude offerti da Kunavo, 2026-09-24. | Non applicato. Anthropic non dispone di una modalità JSON senza schema, quindi il campo viene accettato e ignorato: la risposta può iniziare con prosa o con un blocco di codice. |
| GPT | Inoltrato come text.format della Responses API, ma l'upstream attuale non lo applica a tutte le richieste. Convalida il risultato prima di analizzarlo. | Inoltrato come text.format. |
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 schemaQuattro aspetti da conoscere su Claude:
- Lo schema viene inviato ad Anthropic quasi esattamente come l'hai scritto. Anthropic richiede
additionalProperties: falseper gli oggetti, quindi Kunavo lo aggiunge agli oggetti con proprietà elencate e lo lascia non impostato se lo produce Pydantic tramitemodel_json_schema(). Anthropic continua a rifiutare questi casi con un errore 400 che indica il problema: un oggetto lasciato aperto (additionalPropertiesimpostato su un valore diverso dafalseoppure, se non sono elencate proprietà,additionalPropertiesnon impostato) eoneOf— usaanyOf. La pagina di Anthropic sugli output strutturati elenca gli altri casi. strictenamevengono ignorati: Anthropic applica tutti gli schemi che accetta, in modalità strict o meno.- Uno schema non può essere combinato con un messaggio
assistantfinale (un prefill); Anthropic risponde con un errore 400. - Se
max_tokenssi esaurisce nel mezzo di un oggetto, il JSON viene troncato efinish_reasonè"length".
Input visivo / multimodale
I modelli con la funzionalità vision accettano blocchi di contenuto immagine. Usa un URL HTTPS oppure un URI base64 data:.
# 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)Tra i modelli con funzionalità visiva nel catalogo figurano Claude Opus 5.5: consulta l'elenco dei modelli per gli altri.
Per un'immagine https, Kunavo scarica il file direttamente e lo invia al modello in linea, perché alcuni fornitori upstream ignorano un semplice URL dell'immagine. Limiti: 16 immagini per richiesta, 5 MB per immagine, 20 MB in totale, 10 secondi per download. Se non è possibile recuperare un'immagine, viene restituito un errore che la identifica, invece di ignorarla.
Ragionamento
La funzione di un controllo del ragionamento su questo endpoint dipende dalla famiglia, perché la richiesta di ciascuna famiglia viene tradotta in un'API upstream diversa:
| Famiglia | reasoning_ | Token di ragionamento nell'utilizzo |
|---|---|---|
| GPT | Inoltrato come reasoning. della Responses API, mantenendone invariato il valore, su GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra e GPT-5.5. I valori accettati sono quelli previsti dal modello; su GPT-6 Sol e GPT-6 Luna, none disattiva il ragionamento e max è il livello massimo. | Conteggiati in completion_ e indicati separatamente come completion_, con addebito alla tariffa di output. |
| Claude | Non inoltrato. La richiesta Anthropic viene costruita da un elenco fisso di campi — model, max_tokens, messages, stream, temperature, top_p, top_k, stop, tools, tool_choice e response_ — quindi reasoning_, thinking e ogni altro campo al di fuori dell'elenco vengono eliminati qui. | Nessuna suddivisione. Anthropic conteggia ogni contenuto di ragionamento all'interno del proprio output_, indicato da completion_. |
# 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 ad Anthropic senza traduzioni.caching dei prompt
Un prompt di sistema lungo, un documento di riferimento, un blocco few-shot: qualsiasi prefisso stabile può essere memorizzato nella cache a monte e riutilizzato nelle chiamate successive a una frazione del costo di input. Le cache hit compaiono nell’oggetto usage come prompt_tokens_details.cached_tokens.
I modelli GPT memorizzano automaticamente nella cache: non serve modificare la richiesta. cached_tokens è un sottoinsieme di prompt_tokens e viene fatturato a una tariffa ridotta per la lettura dalla cache.
Claude memorizza nella cache solo fino a un breakpoint cache_control e, su un prompt lungo, questo endpoint imposta i breakpoint al posto tuo: sul prompt di sistema, sulle definizioni degli strumenti e sull’ultimo messaggio non appena la conversazione contiene un turno dell’assistente. Per scegliere tu il prefisso, applica cache_control a un blocco di contenuto, come qui sotto; Kunavo mantiene i tuoi breakpoint e aggiunge i propri solo nelle posizioni che hai lasciato libere:
# 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 — usa la Messages API nativa. Anche questo endpoint memorizza nella cache il prompt di sistema e le definizioni degli strumenti, accetta più breakpoint in una sola richiesta e riporta le scritture nella cache come cache_creation_input_tokens e le letture dalla cache come prompt_tokens_details.cached_tokens; ciò che fa solo l’endpoint nativo è inoltrare il corpo della richiesta senza aggiungere alcun breakpoint.Oggetto usage
Ogni risposta (e il chunk finale dello streaming) include un oggetto usage:
| Campo | Significato |
|---|---|
prompt_ | Token di input fatturati, inclusi quelli memorizzati nella cache. |
prompt_ | Input memorizzato nella cache: un sottoinsieme di prompt_ |
completion_ | Token di output fatturati. Nei modelli GPT includono i token di ragionamento; in Claude corrispondono a output_ |
completion_ | Modelli GPT: la quota di completion_ |
total_tokens | prompt_ |
Compatibilità di Ollama con OpenAI — /v1/chat/completions
Ollama rende disponibili i suoi modelli locali tramite un’API compatibile con OpenAI all’indirizzo http://localhost:11434/v1, implementando lo stesso contratto /chat/completions documentato in questa pagina. I due servizi sono quindi intercambiabili lato client: qualsiasi applicazione sviluppata per l’API v1 di Ollama funziona con quella di Kunavo cambiando l’URL di base e il modello.
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."}],
)Gli elementi che di solito si rompono quando si cambia provider qui funzionano, perché il formato sul filo è lo stesso:
| Funzionalità | Ollama v1 | Kunavo v1 |
|---|---|---|
| Percorso dell’endpoint | /v1/ | /v1/ |
| Streaming | SSE, chat. | Identico: stessa struttura delta |
| Chiamata agli strumenti | tools / tool_calls | Identica tra Claude e GPT |
| Input visivo | Blocchi image_url sui modelli locali multimodali | Stessi blocchi; URL o URI dati base64 |
| api_key | Segnaposto, ignorato | Una chiave Kunavo valida |
| model | Un tag scaricato (llama3.2) | Uno slug ospitato (claude-sonnet-5) |
| Campi usage aggiuntivi | Solo conteggi dei token | Aggiunge cached_ |
| Oltre la chat | completions, embeddings | In più, endpoint per immagini, video e audio |
base_url, model e la chiave dalle variabili d’ambiente e scegli in base all’ambiente: modelli locali per lo sviluppo offline, modelli ospitati quando la qualità è importante, con un unico percorso di codice. La guida completa, che illustra anche cosa supporta e cosa non supporta l’interfaccia OpenAI di Ollama, è disponibile nella guida all’API di Ollama compatibile con OpenAI.Dove si trova la documentazione ufficiale di Ollama per il suo endpoint /v1/chat/completions compatibile con OpenAI?
Ollama documenta il proprio livello di compatibilità con OpenAI nel suo repository, in docs/openai.md. Questa è la fonte autorevole per sapere quali campi OpenAI implementa il server locale. Questa pagina è il riferimento equivalente per l'endpoint /v1/chat/completions ospitato da Kunavo: lo stesso contratto Chat Completions di OpenAI, documentato sopra campo per campo, che permette di confrontare direttamente le due interfacce. In breve, la forma di richieste e risposte è la stessa: Ollama lo offre all'indirizzo http://localhost:11434/v1 per i modelli scaricati localmente, mentre Kunavo lo offre all'indirizzo https://api.kunavo.com/v1 per i modelli Claude e GPT ospitati.
L'endpoint /v1/chat/completions di Kunavo è compatibile con l'API OpenAI di Ollama?
Sì: entrambi implementano lo stesso contratto Chat Completions di OpenAI, quindi un client sviluppato per Ollama su http://localhost:11434/v1 funziona invariato con https://api.kunavo.com/v1. I campi della richiesta (messages, temperature, max_tokens, stream, tools, tool_choice, response_format, stop, seed) e quelli della risposta (choices[].message, choices[].delta negli stream, usage) corrispondono. Le differenze sono quelle prevedibili per i modelli ospitati: api_key è una chiave effettiva e non un segnaposto; model accetta uno slug ospitato come claude-sonnet-5 anziché un tag scaricato come llama3.2; usage include cached_tokens e reasoning_tokens, che i modelli locali non segnalano.
Come si migra un'app Ollama a Claude o GPT ospitati?
Modifica due righe: imposta base_url da http://localhost:11434/v1 a https://api.kunavo.com/v1 e imposta model sullo slug ospitato invece che sul tag locale. Passa una vera chiave Kunavo al posto del segnaposto ignorato da Ollama. Non serve modificare il codice per lo streaming, la chiamata agli strumenti o la visione, perché le strutture SSE e tool_calls sono identiche.
Posso usare Ollama per lo sviluppo e i modelli ospitati in produzione?
Sì, è una configurazione comune: leggi l'URL di base, il modello e la chiave dalle variabili d'ambiente e selezionali in base all'ambiente. Poiché entrambe le piattaforme usano lo stesso protocollo OpenAI, non serve mantenere un secondo percorso di codice: Llama o Qwen locali per le iterazioni offline, Claude o GPT ospitati quando la qualità è importante. Le definizioni degli strumenti e i gestori dello streaming sono condivisi senza modifiche.
Quali endpoint OpenAI aggiunge Kunavo rispetto all'interfaccia compatibile di Ollama?
L'interfaccia compatibile con OpenAI di Ollama copre /chat/completions, /completions, /embeddings e /models. Kunavo aggiunge gli endpoint multimediali usando la stessa chiave: /v1/images/generations, /v1/images/edits, /v1/video/generations, /v1/videos e /v1/audio/music, oltre a Claude sull'endpoint nativo Anthropic /v1/messages. Due precisazioni necessarie: /v1/audio/speech, /v1/audio/transcriptions e /v1/embeddings sono implementati come formati wire, ma al momento non hanno alcun modello abilitato, quindi oggi non funzioneranno; inoltre, a differenza di Ollama, Kunavo non esegue modelli in locale. GET /v1/models è sempre la fonte di riferimento per verificare quali modelli sono disponibili.