Documentação

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âmetroTipoObservações
modelstring (obrigatório)Qualquer identificador habilitado de /v1/models.
messagesarray (obrigatório)Formato padrão de mensagem da OpenAI.
temperature0..2Temperatura de amostragem. Padrão: 1. Não tem efeito nos modelos listados nesta tabela.
top_p0..1Amostragem por núcleo. A mesma exceção da temperatura.
max_tokensintLimite de saída; max_completion_tokens 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.
streamboolTransmite blocos como SSE. Veja abaixo.
toolsarrayDefinições de funções/ferramentas. Claude e GPT são compatíveis com o uso de ferramentas.
tool_choiceauto|none|namedForça uma ferramenta específica ou permite que o modelo decida.
response_formatobjectSaída JSON. No Claude, um json_schema é imposto e json_object não é — consulte Saída JSON para ver todas as famílias.
reasoning_effortstringSomente modelos GPT — repassado como reasoning.effort. Não é repassado para Claude. Consulte Raciocínio.
seedintAmostragem determinística quando compatível.
stopstring|arraySequências de parada obrigatória.
Em Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4.8, Claude Opus 4.7 e Claude Sonnet 5, 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)
O streaming funciona em todos os modelos de chat. Para Claude (provedor upstream com protocolo Anthropic), traduzimos o fluxo de eventos Anthropic em deltas OpenAI em tempo real — seu SDK não percebe a diferença.

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íliajson_schemajson_object
ClaudeImposto. Enviado como saídas estruturadas da Anthropic (output_config.format); 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.
GPTRepassado 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 schema

Quatro pontos a saber sobre Claude:

  • O esquema é enviado à Anthropic praticamente como você o escreveu. A Anthropic exige additionalProperties: false nos objetos, então a Kunavo o adiciona a qualquer objeto que liste suas propriedades e deixe esse campo indefinido — como o model_json_schema() do Pydantic gera. A Anthropic ainda rejeita os seguintes casos com erro 400 que identifica o problema: um objeto aberto (additionalProperties definido como qualquer valor diferente de false, ou sem propriedades listadas e com additionalProperties indefinido) e oneOf — use anyOf. A página de saídas estruturadas da Anthropic lista os demais.
  • strict e name sã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_tokens acaba no meio de um objeto, o JSON fica truncado e finish_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íliareasoning_effortTokens de raciocínio no uso
GPTRepassado como reasoning.effort 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_tokens e discriminados como completion_tokens_details.reasoning_tokens, cobrados pela tarifa de saída.
ClaudeNã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_format — portanto, reasoning_effort, 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_tokens, que é o que completion_tokens 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)
O extended thinking no Claude usa a API Messages nativa, que repassa 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)
Para ter controle total sobre o cache de prompts do Claude — armazenando em cache o prompt de sistema e as definições de ferramentas, usando vários pontos de interrupção e os campos nativos 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:

CampoSignificado
prompt_tokensTokens de entrada cobrados — incluindo os tokens em cache.
prompt_tokens_details.cached_tokensEntrada em cache — um subconjunto de prompt_tokens, cobrado a uma tarifa reduzida de leitura do cache.
completion_tokensTokens de saída que cobramos. Nos modelos GPT, isso inclui os tokens de raciocínio; no Claude, corresponde a output_tokens da Anthropic.
completion_tokens_details.reasoning_tokensModelos GPT: a parcela de tokens de raciocínio em completion_tokens. O campo fica ausente quando o valor é zero e não é informado para Claude.
total_tokensprompt_tokens + completion_tokens.

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:

RecursoOllama v1Kunavo v1
Caminho do endpoint/v1/chat/completions/v1/chat/completions
StreamingSSE, chat.completion.chunkIdêntico — mesma estrutura de delta
Chamadas de ferramentastools / tool_callsIdêntico para Claude e GPT
Entrada de visãoBlocos image_url em modelos locais multimodaisMesmos blocos; URL ou URI de dados em base64
api_keyEspaço reservado, ignoradoUma chave Kunavo real
modelUma tag baixada (llama3.2)Um slug hospedado (claude-sonnet-5)
extras de usoSomente contagens de tokensAdiciona cached_tokens e reasoning_tokens
Além do chatcompletions, embeddingsAlém de endpoints de imagem, vídeo e áudio
Mantém ambos? Leia 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.

Próximos passos