Documentação
conclusões de chat
O endpoint /v1/chat/completions da Kunavo usa o protocolo chat completions da OpenAI para as famílias Claude e GPT. Streaming, ferramentas e saída JSON funcionam com o mesmo SDK; o efeito de reasoning_effort depende da família, e esta página explica qual é.
Endpoint: POST /v1/chat/completions. O formato da solicitação e da resposta corresponde exatamente ao da API chat completions da OpenAI — incluindo streaming e os campos opcionais tool_calls / reasoning_tokens.
Chamada básica
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)Parâmetros
Todos os parâmetros padrão da OpenAI são aceitos. Alguns só fazem sentido para determinados provedores — o tradutor repassa os campos compatíveis com cada provedor upstream.
| Parâmetro | Tipo | Observações |
|---|---|---|
model | string (obrigatório) | Qualquer identificador habilitado de /v1/models. |
messages | array (obrigatório) | Formato padrão de mensagem da OpenAI. |
temperature | 0..2 | Temperatura de amostragem. Padrão: 1. Não tem efeito nos modelos listados nesta tabela. |
top_p | 0..1 | Amostragem por núcleo. A mesma exceção da temperatura. |
max_tokens | int | Limite de saída; max_ prevalece quando ambos são enviados. Nos modelos GPT, os tokens de raciocínio contam para esse limite. Uma solicitação Claude que não envie nenhum dos dois recebe 4.096. |
stream | bool | Transmite blocos como SSE. Veja abaixo. |
tools | array | Definições de funções/ |
tool_choice | auto| | Força uma ferramenta específica ou permite que o modelo decida. |
response_ | object | Saída JSON. No Claude, um json_schema é imposto e json_object não é — consulte Saída JSON para ver todas as famílias. |
reasoning_ | string | Somente modelos GPT — repassado como reasoning.. Não é repassado para Claude. Consulte Raciocínio. |
seed | int | Amostragem determinística quando compatível. |
stop | string|array | Sequências de parada obrigatória. |
temperature, top_p e top_k não são aceitos. A Kunavo remove os três das solicitações a esses modelos, em vez de repassar o erro 400 do fornecedor; portanto, eles não têm efeito nesses modelos.Streaming
Defina stream=True. A Kunavo emite eventos enviados pelo servidor no formato exato da OpenAI: cada bloco é um chat.completion.chunk com choices[0].delta.content. O payload final de uso chega com 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)Chamadas de ferramentas / funções
Chamadas de ferramentas funcionam entre provedores. Defina as ferramentas como esquema JSON; o modelo retorna tool_calls na mensagem; você executa as ferramentas e envia os resultados de volta como mensagens 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)Saída JSON (response_format)
response_format solicita JSON. O que isso garante depende da família do modelo, pois a solicitação de cada família é traduzida para um mecanismo upstream diferente:
| Família | json_schema | json_object |
|---|---|---|
| Claude | Imposto. Enviado como saídas estruturadas da Anthropic (output_); a resposta é restringida ao seu esquema. Verificado em todos os modelos Claude oferecidos pela Kunavo, em 2026-09-24. | Não imposto. A Anthropic não tem um modo JSON sem esquema, então a solicitação é aceita e ignorada — a resposta pode começar com prosa ou um bloco de código. |
| GPT | Repassado como text.format da API Responses, mas o provedor upstream atual não o aplica em todas as solicitações. Valide antes de analisar. | Repassado como 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 schemaQuatro pontos a saber sobre Claude:
- O esquema é enviado à Anthropic praticamente como você o escreveu. A Anthropic exige
additionalProperties: falsenos objetos, então a Kunavo o adiciona a qualquer objeto que liste suas propriedades e deixe esse campo indefinido — como omodel_json_schema()do Pydantic gera. A Anthropic ainda rejeita os seguintes casos com erro 400 que identifica o problema: um objeto aberto (additionalPropertiesdefinido como qualquer valor diferente defalse, ou sem propriedades listadas e comadditionalPropertiesindefinido) eoneOf— useanyOf. A página de saídas estruturadas da Anthropic lista os demais. strictenamesão ignorados: a Anthropic impõe todos os esquemas que aceita, sejam estritos ou não.- Um esquema não pode ser combinado com uma mensagem final
assistant(um prefill); a Anthropic responde com erro 400. - Quando
max_tokensacaba no meio de um objeto, o JSON fica truncado efinish_reasoné"length".
Entrada visual / multimodal
Modelos com o recurso vision aceitam blocos de conteúdo de imagem. Use uma URL HTTPS ou um URI data: base64.
# 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)O catálogo inclui modelos com capacidade de visão, como Claude Opus 5.5 — consulte a lista de modelos para ver os demais.
Para uma imagem HTTPS, a Kunavo baixa o arquivo diretamente e o envia ao modelo em linha, pois alguns provedores upstream ignoram uma URL de imagem simples. Limites: 16 imagens por solicitação, 5 MB por imagem, 20 MB no total, 10 segundos por download. Se não for possível buscar uma imagem, será retornado um erro que a identifica, em vez de ela ser ignorada.
Raciocínio
O efeito de um controle de raciocínio neste endpoint depende da família, pois a solicitação de cada família é traduzida para uma API upstream diferente:
| Família | reasoning_ | Tokens de raciocínio no uso |
|---|---|---|
| GPT | Repassado como reasoning. da API Responses, sem alteração de valor, em GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra e GPT-5.5. Os valores aceitos são definidos pelo próprio modelo; em GPT-6 Sol e GPT-6 Luna, none desativa o raciocínio e max é o nível máximo. | Contabilizados dentro de completion_ e discriminados como completion_, cobrados pela tarifa de saída. |
| Claude | Não repassado. A solicitação Anthropic é criada a partir de uma lista fixa de campos — model, max_tokens, messages, stream, temperature, top_p, top_k, stop, tools, tool_choice e response_ — portanto, reasoning_, thinking e qualquer outro campo fora dessa lista são descartados aqui. | Sem discriminação. A Anthropic contabiliza qualquer raciocínio dentro de seu output_, que é o que completion_ informa. |
# 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 à Anthropic sem tradução.cache de prompts
Um prompt longo de sistema, um documento de referência, um bloco de exemplos few-shot — qualquer prefixo estável pode ser armazenado em cache no provedor e reutilizado em chamadas posteriores por uma fração do preço de entrada. Os acertos de cache aparecem no objeto de uso como prompt_tokens_details.cached_tokens.
Os modelos GPT armazenam em cache automaticamente — não é preciso alterar a solicitação. cached_tokens é um subconjunto de prompt_tokens e é cobrado a uma tarifa reduzida de leitura do cache.
O Claude armazena em cache apenas até um ponto de interrupção cache_control, e em um prompt longo este endpoint define os pontos de interrupção para você: no prompt de sistema, nas definições de ferramentas e na última mensagem assim que a conversa contém um turno do assistente. Para escolher o prefixo você mesmo, anexe cache_control a um bloco de conteúdo, como abaixo; a Kunavo mantém seus pontos de interrupção e adiciona os próprios apenas nas posições que você deixou vazias:
# 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 de uso — use a API Messages nativa. Este endpoint também armazena em cache o prompt de sistema e as definições de ferramentas, aceita vários pontos de interrupção em uma mesma requisição e informa as gravações em cache como cache_creation_input_tokens e as leituras do cache como prompt_tokens_details.cached_tokens; o que só o endpoint nativo faz é repassar o corpo da sua requisição sem adicionar nenhum ponto de interrupção.Objeto de uso
Toda resposta (e o trecho final do streaming) inclui um objeto usage:
| Campo | Significado |
|---|---|
prompt_ | Tokens de entrada cobrados — incluindo os tokens em cache. |
prompt_ | Entrada em cache — um subconjunto de prompt_ |
completion_ | Tokens de saída que cobramos. Nos modelos GPT, isso inclui os tokens de raciocínio; no Claude, corresponde a output_ |
completion_ | Modelos GPT: a parcela de tokens de raciocínio em completion_ |
total_tokens | prompt_ |
Compatibilidade do Ollama com OpenAI — /v1/chat/completions
O Ollama disponibiliza seus modelos locais por meio de uma API compatível com OpenAI em http://localhost:11434/v1, implementando o mesmo contrato /chat/completions documentado nesta página. Assim, os dois são intercambiáveis no cliente: qualquer coisa escrita para a API v1 do Ollama funciona com a Kunavo ao alterar a URL base e o modelo.
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."}],
)Os elementos que costumam falhar ao trocar de provedor não falham aqui, porque o formato transmitido é o mesmo:
| Recurso | Ollama v1 | Kunavo v1 |
|---|---|---|
| Caminho do endpoint | /v1/ | /v1/ |
| Streaming | SSE, chat. | Idêntico — mesma estrutura de delta |
| Chamadas de ferramentas | tools / tool_calls | Idêntico para Claude e GPT |
| Entrada de visão | Blocos image_url em modelos locais multimodais | Mesmos blocos; URL ou URI de dados em base64 |
| api_key | Espaço reservado, ignorado | Uma chave Kunavo real |
| model | Uma tag baixada (llama3.2) | Um slug hospedado (claude-sonnet-5) |
| extras de uso | Somente contagens de tokens | Adiciona cached_ |
| Além do chat | completions, embeddings | Além de endpoints de imagem, vídeo e áudio |
base_url, model e a chave de variáveis de ambiente e alterne por ambiente — modelos locais para iteração offline, modelos hospedados quando a qualidade importa, tudo em um único caminho de código. O guia completo, incluindo o que a interface OpenAI do Ollama implementa e o que não implementa, está no guia da API do Ollama compatível com OpenAI.Onde está a documentação oficial do endpoint /v1/chat/completions compatível com OpenAI do Ollama?
Ollama documenta sua camada de compatibilidade com OpenAI em seu próprio repositório, em docs/openai.md; essa é a referência oficial dos campos OpenAI implementados pelo servidor local. Esta página é a referência equivalente para o endpoint hospedado /v1/chat/completions da Kunavo: o mesmo contrato de chat completions da OpenAI, documentado campo a campo acima, para que você possa comparar diretamente as duas interfaces. Em resumo, os formatos de solicitação e resposta são os mesmos — o Ollama atende em http://localhost:11434/v1 os modelos baixados localmente, enquanto a Kunavo atende em https://api.kunavo.com/v1 os modelos Claude e GPT hospedados.
O endpoint /v1/chat/completions da Kunavo é compatível com a API OpenAI do Ollama?
Sim — ambos implementam o mesmo contrato de chat completions da OpenAI, então um cliente escrito para o Ollama em http://localhost:11434/v1 funciona sem alterações em https://api.kunavo.com/v1. Os campos da solicitação (messages, temperature, max_tokens, stream, tools, tool_choice, response_format, stop, seed) e da resposta (choices[].message, choices[].delta em transmissões, usage) correspondem. As diferenças são as esperadas em modelos hospedados: api_key é uma chave real, e não um placeholder; model recebe um identificador hospedado, como claude-sonnet-5, em vez de uma tag baixada, como llama3.2; e usage inclui cached_tokens e reasoning_tokens, que modelos locais não informam.
Como migrar um aplicativo Ollama para Claude ou GPT hospedado?
Altere duas linhas: defina base_url de http://localhost:11434/v1 para https://api.kunavo.com/v1 e altere model da tag local para um identificador hospedado. Use uma chave Kunavo real em vez do placeholder que o Ollama ignora. Não é necessário alterar o código de streaming, chamadas de ferramentas ou visão, pois os formatos de SSE e tool_calls são idênticos.
Posso continuar usando o Ollama no desenvolvimento e modelos hospedados em produção?
Sim, é uma configuração comum — leia a URL base, o modelo e a chave de variáveis de ambiente e altere-os por ambiente. Como os dois lados usam o mesmo protocolo OpenAI, não há um segundo fluxo de código para manter: Llama ou Qwen local para desenvolvimento offline e Claude ou GPT hospedado quando a qualidade importa. As definições de ferramentas e os manipuladores de streaming são compartilhados sem alterações.
Quais endpoints OpenAI a Kunavo adiciona à interface compatível do Ollama?
A interface compatível com OpenAI do Ollama abrange /chat/completions, /completions, /embeddings e /models. A Kunavo adiciona endpoints de mídia usando a mesma chave: /v1/images/generations, /v1/images/edits, /v1/video/generations, /v1/videos e /v1/audio/music, além do Claude no endpoint Anthropic nativo /v1/messages. Há duas ressalvas importantes no sentido inverso: /v1/audio/speech, /v1/audio/transcriptions e /v1/embeddings são implementados como formatos de transmissão, mas atualmente não têm nenhum modelo habilitado por trás deles, então não funcionarão por enquanto — e, ao contrário do Ollama, a Kunavo não executa modelos localmente. GET /v1/models é sempre a fonte oficial sobre o que pode ser chamado.