ShvIA

Docs · API compatível com OpenAI

Chat completions

O dialeto Chat Completions da OpenAI. Não guarda estado: você envia a conversa inteira a cada chamada, e nada é guardado como conversa. As chamadas continuam sendo medidas, então contam para a sua cota.

POST/v1/chat/completions#

  • Auth: a sua chave de API, em Authorization: Bearer ou X-API-Key.
  • Limite: 20 requisições por minuto por conta por padrão, um contador que todos os endpoints /v1 dividem com os outros endpoints que têm um número por minuto próprio. Veja limites e cotas.
  • Corpo: JSON, com Content-Type: application/json.

Requisição#

CampoTipoObrigatórioNotas
modelstringsimum id de modelo de modelos, com no máximo 320 caracteres
messagesarraysimde 1 a 200 mensagens, veja abaixo
streambooleannãotrue para server-sent events. O padrão é false
stream_options.include_usagebooleannãoacrescenta um chunk final com a contagem de tokens a uma resposta em stream
toolsarraynãoferramentas de função, veja chamadas de ferramenta
tool_choicestring ou objetonãoauto, none, required, ou {"type":"function","function":{"name":"…"}}
reasoning_effortstringnãolow, medium, high, xhigh ou max, nos modelos que suportam. Qualquer outro valor é descartado
collectionsarray de inteirosnãoids de suas coleções, de 1 a 5. Os trechos delas que dizem respeito à última mensagem do usuário são acrescentados à mensagem de sistema. Não faz parte da API da OpenAI: um SDK envia como campo extra do corpo
parâmetros de amostragem e outros campos da OpenAInãoaplicados ou ignorados conforme o modelo, veja abaixo

Uma requisição malformada devolve 422 no formato de erro da OpenAI, com code: null.

Mensagens#

Cada mensagem tem um role e um content:

  • role é system, user, assistant ou tool.
  • content é uma string, ou null numa mensagem do assistente que traz tool_calls. No máximo 200000 caracteres por mensagem.
  • Um array de partes de conteúdo, a forma usada para enviar imagens, é recusado com 422 (The messages.0.content field must be a string.). Imagens não são suportadas neste endpoint.
  • Uma mensagem do assistente pode trazer tool_calls, e uma mensagem tool traz o tool_call_id que ela responde.

Quais parâmetros valem#

O que acontece com os parâmetros de amostragem depende do driver do modelo, um campo de GET /api/v1/profiles. Um modelo cujo driver é ollama é servido pelos servidores Ollama do próprio operador. Todos os outros drivers, que cobrem os provedores de nuvem e também qualquer servidor compatível com OpenAI que o operador rode, caem na segunda coluna.

Parâmetrodriver é ollamaqualquer outro driver
temperature, top_p, max_tokens, max_completion_tokens, stop, seed, frequency_penalty, presence_penaltyrepassados ao servidor do modeloignorados
response_format, n, parallel_tool_calls, user, logit_bias, logprobs, top_logprobsrepassados como estão. O servidor do modelo decide se têm algum efeitoignorados
tools, tool_choicerepassadosaplicados
reasoning_effortnão se aplicaaplicado quando o modelo tem ajuste de esforço
stream_options.include_usagesempre ligado nos streamsaplicado

Um parâmetro ignorado não é um erro: a requisição tem sucesso e o parâmetro não tem efeito. Se o tamanho da saída ou a aleatoriedade importam para você, confira primeiro o driver do modelo.

Resposta#

json
{
  "id": "chatcmpl-0b0f3c0e-6c4e-4d6f-9a0e-2f3b1d7a9c11",
  "object": "chat.completion",
  "created": 1767225600,
  "model": "claude-sonnet-4-6@anthropic",
  "choices": [
    { "index": 0, "message": { "role": "assistant", "content": "Hello! Nice to meet you." }, "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 14, "completion_tokens": 8, "total_tokens": 22 }
}
  • model é o id que o gateway resolveu para a requisição. Ele mostra uma substituição quando você enviou um nome sem servidor que o gateway não conhecia, mas não mostra um fallback para o seu modelo padrão. Veja modelos.
  • Há uma escolha nos modelos de nuvem: não envie n. Para modelos que não são ollama, finish_reason é stop ou tool_calls. Para modelos ollama é o que o servidor do modelo informar, o que inclui length.
  • O texto de raciocínio que alguns modelos produzem nunca é devolvido.

Headers#

HeaderSignificado
X-Request-Ididentifica a requisição HTTP. Envie o seu, com até 64 letras, dígitos, - e _, e ele é reaproveitado
X-Inference-Request-Ididentifica a chamada ao modelo. Passe-o ao suporte
X-Inference-Model, X-Inference-Servero alvo resolvido, a título de informação
X-Inference-Collections, X-Inference-Excerptssó quando a chamada nomeou collections: os ids que foram usados e quantos trechos entraram no prompt. Veja coleções
X-RateLimit-Limit, X-RateLimit-Remainingo seu limite de requisições e quanto resta dele

Streaming#

Com "stream": true a resposta é text/event-stream. Cada evento é uma linha data: {…} seguida de uma linha em branco, e o stream termina com data: [DONE].

sse
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1767225600,"model":"claude-sonnet-4-6@anthropic","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1767225600,"model":"claude-sonnet-4-6@anthropic","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1767225600,"model":"claude-sonnet-4-6@anthropic","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1767225600,"model":"claude-sonnet-4-6@anthropic","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":8,"total_tokens":22}}

data: [DONE]

O chunk de uso, o de choices vazio, aparece só quando você define stream_options.include_usage, exceto nos modelos ollama, em que ele está sempre presente. Nos modelos ollama os chunks são os do próprio servidor do modelo, então o chunk inicial só com o papel, do exemplo, não é garantido. Leia o stream como eventos, não como linhas de JSON: o gateway não envia comentários nem linhas de keep-alive.

Chamadas de ferramenta#

Declare funções com tools. Quando o modelo quer chamar uma, a resposta traz tool_calls e finish_reason é tool_calls.

bash
curl -s "$SHVIA_URL/v1/chat/completions" \
  -H "Authorization: Bearer $SHVIA_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "'"$SHVIA_MODEL"'",
    "messages": [{ "role": "user", "content": "What is the weather in Lisbon?" }],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Current weather for a city",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }]
  }'
json
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1767225600,
  "model": "claude-sonnet-4-6@anthropic",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          { "id": "call_1", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Lisbon\"}" } }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": { "prompt_tokens": 61, "completion_tokens": 18, "total_tokens": 79 }
}

Execute a função você mesmo e depois envie a conversa de volta com a chamada e o resultado dela:

json
{
  "model": "claude-sonnet-4-6@anthropic",
  "messages": [
    { "role": "user", "content": "What is the weather in Lisbon?" },
    { "role": "assistant", "content": null, "tool_calls": [
      { "id": "call_1", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Lisbon\"}" } }
    ] },
    { "role": "tool", "tool_call_id": "call_1", "content": "18 degrees, clear" }
  ],
  "tools": [ … the same tools … ]
}

Num stream, cada chamada de ferramenta chega inteira numa única entrada delta.tool_calls, e não em fragmentos incrementais dos argumentos.

Erros#

Os erros usam o formato da OpenAI: {"error": {"message", "type", "param", "code"}}. Decida pelo status HTTP e por code; o texto de message pode estar em outro idioma e pode mudar.

StatuscodeQuando
401invalid_api_keya chave está ausente, errada, expirada ou revogada
403permission_deniedo seu grupo não pode usar este modelo, uma cota acabou, ou o grupo não pode usar servidores remotos. Não repita às cegas
404model_not_foundo id traz um servidor e o gateway não tem esse modelo lá, ou o modelo não é exposto
422nullo corpo falhou na validação
422, 404, 403invalid_collections, collection_not_found, collections_blocked_by_lgpdo campo collections não pôde ser usado. Veja coleções
429nenhumlimite de requisições atingido. O corpo é {"message": "Too Many Attempts."} quando você envia Accept: application/json; leia Retry-After
502empty_responseo modelo não devolveu nada. Não vale para modelos ollama
502, 503, ou o status do próprio provedorservice_unavailableo servidor do modelo, ou todos os servidores da cadeia, não puderam ser alcançados ou recusaram a chamada. Se todos os modelos da cadeia falham, a recusa de um provedor de nuvem mantém o status do provedor, por exemplo 401 quando a sua chave do provedor é rejeitada. Se outro modelo pode responder, ele responde, e você recebe o 200 dele (veja modelos)
504read_timeouto modelo parou de responder no meio da resposta. O corpo acrescenta um objeto partial com a resposta que chegou, e o header X-Inference-Incomplete: read_timeout é enviado. Não vale para modelos ollama

Para modelos ollama, uma resposta vazia é um 200 comum com content vazio, e um modelo que trava termina, depois de uma longa espera, como um 502 com service_unavailable. Uma recusa das credenciais do próprio gateway pelo servidor do modelo é informada como 502, nunca como 401, para que você não regenere uma chave de API que está boa.

Não suportado#

  • Imagens e outras partes de conteúdo nas mensagens.
  • O /v1/completions legado e o /v1/embeddings da OpenAI. Os embeddings estão em /api/v1/embeddings.
  • Mais de uma escolha (n).
  • Recuperar um modelo ou uma completion passada pelo id.

Tratamento de dados#

  • Nada é guardado como conversa. Cada chamada é registrada para medição, com o texto da sua última mensagem mascarado e encurtado. Veja seus dados.
  • Quando o modelo não está na infraestrutura do próprio operador, identificadores comuns no texto das mensagens, como endereços de e-mail, números de CPF e CNPJ e telefones, são trocados por marcadores como [EMAIL] e [CPF] antes de ele sair. O mascaramento é por padrões: não reconhece nomes nem dados livres, e não mexe nos argumentos das chamadas de ferramenta. Não use um modelo assim para processar esses identificadores.