Aviso: Lançamento do GPT Image 2.6 Flare e Sunburst com 20% de desconto por tempo limitado, experimente agora
HiAPI
Blogue

Tutorial

Como chamar o kimi-k3.1-pro pela API do HiAPI: curl, Python e requisições prontas para executar

Um guia prático de integração que cobre endpoint, parâmetros de requisição, streaming, chamadas de ferramentas e solução de erros

Nov 12, 2026
封面图:深墨绿底色上,两组扁平缎带呈经纬交错编织成规整的开放式网格,缎带为克制的黄铜色与暗绿色。
Nesta página

Por que chamar o kimi-k3.1-pro por meio de uma API agregadora

Toda integração de modelo carrega o mesmo custo oculto: no primeiro dia é divertido, no segundo mês é manutenção. Quando você conecta o kimi-k3.1-pro diretamente na aplicação, herda junto o esquema de autenticação, a semântica de erros, o modelo de cotas e o ritmo de lançamentos do provedor. Para um protótipo de modelo único, isso não é problema. Mas quando você quiser um segundo modelo, um segundo ambiente, ou um caminho de degradação para quando algum endpoint apresentar problema, isso se transforma em atrito.

Uma API agregadora reduz essas diferenças a um único contrato. O HiAPI expõe o kimi-k3.1-pro em um formato de requisição compatível com OpenAI, o que significa que o código cliente que você escrever aqui não é descartável. Troque o identificador do modelo e a mesma estrutura de requisição continua valendo para outros modelos da plataforma — os mesmos cabeçalhos, o mesmo array de mensagens, o mesmo envelope de streaming.

No caso específico do kimi-k3.1-pro, isso tem três implicações práticas:

  • Uma única superfície de credenciais. Você gerencia apenas uma API Key e uma URL base, em vez de um conjunto crescente de contas de provedores.
  • Payloads previsíveis. Os esquemas de requisição e resposta se mantêm estáveis entre modelos, então suas camadas de parsing, retry e logging precisam ser escritas uma única vez.
  • Baixo custo de migração. Se no futuro algum tipo de carga for mais adequado a outro modelo, a mudança é uma string no payload, não uma reescrita da camada de transporte.

O restante deste guia é a integração em si: anatomia da requisição, chamada curl pronta para copiar, o cliente Python equivalente e, em seguida, os dois recursos que costumam causar mais problemas em produção — streaming e chamadas de ferramentas — e por fim uma lista de verificação para solução de erros.

O que você precisa antes de começar

  • Uma API Key do HiAPI, armazenada onde o seu projeto guarda segredos.
  • A URL base da API da sua conta, obtida no console do HiAPI. Todos os exemplos abaixo usam https://api.hiapi.ai/v1 como URL base de exemplo; antes de ir para produção, confirme o host real no console.
  • A string do identificador do modelo kimi-k3.1-pro — copiada exatamente como aparece na lista de modelos do console, pois o identificador diferencia maiúsculas de minúsculas.
  • curl para o primeiro teste, e Python 3.9+ com a biblioteca requests para o exemplo de cliente.

Forma da requisição: endpoint, cabeçalhos e parâmetros do modelo

Toda chamada de conversa segue a mesma anatomia. Entenda cada parte uma vez e você não precisará depurar campo por campo depois.

Endpoint

A conclusão de conversa fica em um único caminho sob a URL base:

POST {BASE_URL}/chat/completions

Este é o único endpoint necessário para todos os exemplos deste guia. Streaming e chamadas de ferramentas não são endpoints separados — são opções no mesmo corpo da requisição.

Cabeçalhos

Apenas dois cabeçalhos realmente importam:

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

A chave vai no cabeçalho Authorization, com o prefixo Bearer. Não a coloque na URL, em parâmetros de consulta nem no corpo da requisição — essas três práticas a expõem em logs e relatórios de erro. Defina Content-Type explicitamente; alguns clientes HTTP não o inferem por você.

Os campos do corpo da requisição que realmente importam

Uma requisição mínima tem quatro campos relevantes:

  • model — o identificador do kimi-k3.1-pro. Obrigatório. É o campo mais fácil de errar na primeira tentativa, porque precisa corresponder exatamente.
  • messages — um array ordenado de objetos, cada um com role (system, user ou assistant) e content. Obrigatório e não vazio. A ordem é o seu histórico de conversa; o modelo vê exatamente esse array, e nada mais.
  • stream — booleano, padrão false. Quando true, a resposta chega como eventos enviados pelo servidor, em vez de um único corpo JSON. Há uma seção dedicada abaixo.
  • temperature — controle opcional de amostragem. Valores baixos produzem saídas mais determinísticas; valores altos, mais variação. Escolha um valor por caso de uso e não mexa mais; não o ajuste a cada requisição.

Campos opcionais que você pode adicionar conforme a integração amadurece:

  • max_tokens — limite de comprimento da geração. Serve como proteção contra custo e latência. Observe que ele limita a saída, não a entrada.
  • tools — array de definições de ferramentas, detalhado mais adiante.
  • tool_choice — controla se e como o modelo deve chamar as ferramentas que você forneceu.
  • stop — uma ou mais sequências que encerram a geração.

A resposta que você deve esperar

Uma resposta não streaming retorna um objeto JSON cujo array choices contém pelo menos um item. Nesse item você encontrará um objeto message, com role e content, além de um finish_reason, que informa por que a geração parou. Sempre ramifique com base no finish_reason, em vez de presumir que o conteúdo está completo — uma resposta truncada ainda tem conteúdo, só não é a resposta completa.

Escreva o parser para essa estrutura, e não para uma resposta serializada como string. Assim ele sobrevive independentemente de como você trocar de modelo na plataforma.

Uma requisição curl pronta para executar

Comece por aqui. Se ela retornar uma resposta válida, significa que sua chave, URL base e identificador de modelo estão corretos; qualquer problema depois disso está no código, não nas credenciais.

curl -sS "$HIAPI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3.1-pro",
    "messages": [
      {"role": "system", "content": "Você é um assistente técnico conciso."},
      {"role": "user", "content": "Explique em duas frases o que é uma chave de idempotência."}
    ],
    "temperature": 0.3,
    "max_tokens": 256
  }'

Explicação de cada campo

  • -sS mantém o curl silencioso quanto ao progresso, mas ainda expõe erros. Sem o segundo S, uma requisição com falha pode sair silenciosamente, desperdiçando uma rodada de depuração.
  • Variáveis de ambiente mantêm a chave fora do histórico do shell e do buffer de rolagem do terminal. Exporte HIAPI_BASE_URL e HIAPI_API_KEY no seu arquivo de configuração de shell ou em um .env carregado.
  • Corpo entre aspas simples é o correto para shells POSIX, desde que o payload não contenha aspas simples. Quando precisar de aspas simples, mova o corpo para um arquivo e passe com -d @body.json — isso evita uma classe de bugs de aspas que parecem erros de formato JSON.
  • A mensagem system é opcional, mas vale a pena incluir. É o lugar mais simples para fixar tom e formato de saída.
  • max_tokens é deliberadamente conservador neste exemplo. Ele limita tanto a latência quanto o custo do teste rápido.

Interpretando o resultado

Uma chamada bem-sucedida retorna HTTP 200 e um corpo JSON. Antes de prosseguir, confirme três coisas:

  1. choices é um array não vazio.
  2. choices[0].message.content contém uma resposta real.
  3. choices[0].finish_reason é um valor de conclusão normal, e não truncamento por comprimento.

Se o corpo da resposta for um objeto de erro, pule para a seção de solução de problemas — a mensagem de erro geralmente aponta o campo específico com problema.

Dica de repetibilidade

Salve essa chamada curl como um script de shell no repositório. Um único comando para fazer um teste rápido contra a API em tempo real é a forma mais rápida de distinguir "minha integração quebrou" de "minha conta ou chave mudou". Sempre que algo parecer errado, execute-o primeiro.

A mesma requisição em Python

A versão em Python deve parecer entediante — esse é justamente o objetivo. Todas as decisões interessantes (identificador do modelo, URL base, timeout) devem ficar na configuração, e não espalhadas pelos pontos de chamada.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
MODEL = os.environ.get("HIAPI_MODEL", "kimi-k3.1-pro")

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def chat(messages, temperature=0.3, max_tokens=512, timeout=60):
    payload = {
        "model": MODEL,
        "messages": messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
    }
    resp = requests.post(
        f"{BASE_URL}/chat/completions",
        headers=HEADERS,
        json=payload,
        timeout=timeout,
    )
    resp.raise_for_status()
    data = resp.json()
    choice = data["choices"][0]
    return choice["message"]["content"], choice.get("finish_reason")


if __name__ == "__main__":
    text, reason = chat([
        {"role": "system", "content": "Você é um assistente técnico conciso."},
        {"role": "user", "content": "Explique em duas frases o que é uma chave de idempotência."},
    ])
    print(reason)
    print(text)

Por que organizar assim

  • Use json= em vez de data= — a biblioteca requests serializa o dicionário e define o tipo de conteúdo por você. Serializar manualmente introduz erros de escape com facilidade.
  • Sempre timeout=60 — a ausência de timeout é a causa mais comum de processos de trabalho travarem até serem mortos pelo gerenciador. Toda chamada de rede em um serviço deve ter timeout.
  • raise_for_status() antes de analisar — isso transforma falhas na camada HTTP em exceções no ponto da chamada, em vez de deixar um corpo de resposta malformado fluir para o downstream.
  • MODEL vindo do ambiente — ao trocar de modelo, o identificador é a única coisa que muda. Mantê-lo na configuração significa que a troca é uma variável de implantação, não uma alteração de código.
  • Retornar finish_reason — quem chama quase sempre precisa saber se a resposta foi truncada.

Mantenha reutilizável entre modelos

A assinatura de chat(messages, ...) deliberadamente não expõe nada específico de modelo. Se mais tarde você rotear cargas mais baratas para outros modelos, ou passe um parâmetro explícito de substituição de modelo, ou construa um segundo objeto de cliente com um MODEL diferente. Transporte, cabeçalhos, política de retry e tratamento de erros permanecem iguais.

Uma observação sobre retries

Não faça retry cego dentro de chat(). Faça retry na camada que sabe se a operação pode ser repetida com segurança — uma conclusão que falhou geralmente é segura, mas uma requisição que já alterou estado downstream não é. Faça retry apenas para falhas transitórias de transporte e respostas de rate limiting, e apenas com backoff exponencial limitado.

Streaming de respostas sem quebrar o cliente

Streaming é a diferença entre uma interface de chat que parece instantânea e uma tela em branco por dez segundos. Também é o que introduz mais bugs de integração, porque a resposta deixa de ser um único documento JSON.

Como ativar

Adicione "stream": true ao corpo da requisição. O restante da requisição não muda.

with requests.post(
    f"{BASE_URL}/chat/completions",
    headers=HEADERS,
    json={"model": MODEL, "messages": messages, "stream": True},
    stream=True,
    timeout=120,
) as resp:
    resp.raise_for_status()
    for line in resp.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        chunk = line[len("data:"):].strip()
        if chunk == "[DONE]":
            break
        # Analise o chunk como JSON e leia choices[0].delta.content

O que realmente chega

O corpo da resposta é uma série de eventos enviados pelo servidor. Cada evento é uma linha data: que carrega um pequeno objeto JSON. Em choices[0] há um objeto delta em vez de um objeto message — o delta geralmente contém um fragmento de content, e pode não conter nada. O stream termina com a linha sentinela data: [DONE].

Quatro regras cobrem quase todos os erros:

  1. Acumule, não substitua. Cada delta é um fragmento. Anexe delta.content a um buffer; a resposta completa é a concatenação de cada fragmento na ordem.
  2. Ignore deltas vazios. O primeiro e o último evento frequentemente não trazem conteúdo. Evite anexar None.
  3. Trate [DONE] como terminador, não como dado. Pare de ler ali; o conteúdo posterior não faz parte da resposta.
  4. Leia finish_reason do último evento que o carrega. No modo streaming, o estado de conclusão aparece em um delta mais tarde, não em um campo de nível superior.

Armadilhas que merecem ser citadas

  • Esquecer de definir stream=True na chamada do cliente. Você receberá o stream inteiro como um corpo em buffer, o que contraria o objetivo e parece uma requisição não streaming muito lenta.
  • Timeout configurado como em não streaming. Streams de gerações longas duram mais que requisições curtas. Dê ao caminho de streaming um timeout de leitura mais folgado e considere um temporizador de inatividade que aborta quando nenhum byte chega em um intervalo escolhido.
  • Analisar linha por linha sem verificar o prefixo. Nem toda linha é dado. Linhas vazias separam eventos; ignore-as.
  • Presumir que o delta tem a chave content. O streaming de chamadas de ferramentas coloca outras chaves no delta. Sempre leia de forma defensiva.
  • Esquecer o consumidor no cliente. Um servidor que grava o stream em um buffer e só o emite no final é tecnicamente streaming, mas não na prática. Garanta que o downstream renderize os fragmentos à medida que chegam.

Quando não usar streaming

Tarefas em lote, resumos em background e qualquer coisa cuja saída seja consumida por um programa em vez de exibida a uma pessoa costumam ser mais simples sem streaming. Respostas não streaming exigem apenas uma análise, são mais fáceis de registrar em log e mais fáceis de validar por esquema. Use streaming onde a latência é visível para o usuário; não o use por padrão.

Adicionando chamadas de ferramentas ao fluxo

Chamadas de ferramentas permitem que o modelo peça ao seu código para executar uma ação, em vez de inventar uma resposta. O protocolo é uma conversa em duas rodadas: você declara a ferramenta, o modelo pode responder com uma solicitação de chamada, você a executa e então envia o resultado de volta.

Declarando uma ferramenta

Adicione o array tools à requisição. Cada item envolve a descrição de uma função:

{
  "model": "kimi-k3.1-pro",
  "messages": [{"role": "user", "content": "Como está o tempo em Lisboa?"}],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Retorna o tempo atual na cidade especificada.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "Nome da cidade"}
          },
          "required": ["city"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

O description na função e em cada parâmetro não é decoração — é a única orientação que o modelo tem para decidir quando e como chamar a ferramenta. Escreva-o como se estivesse explicando para um novo colega.

O ciclo de resposta

  1. Envie a requisição.
  2. Se choices[0].finish_reason indicar uma chamada de ferramenta, leia choices[0].message.tool_calls. Cada item tem id, o name da função e arguments — uma string codificada em JSON, não um objeto. Analise-a.
  3. Execute a função no seu código. Valide os argumentos antes de fazer qualquer coisa com eles; o modelo pode gerar payloads plausíveis, mas com campos faltando ou tipos errados.
  4. Anexe a mensagem do assistente — incluindo suas tool_calls — ao seu array messages.
  5. Anexe uma nova mensagem com role tool, contendo o tool_call_id correspondente e o resultado como content.
  6. Envie a requisição novamente. O modelo agora monta a resposta final usando a saída da ferramenta.

O passo 4 é o que as pessoas pulam, e é exatamente onde quebra. Se você só devolver o resultado da ferramenta sem a rodada de chamada de ferramenta do assistente, a conversa terá uma referência pendente e o modelo não terá registro de que pediu algo.

Lidando com múltiplas chamadas

Uma resposta pode conter várias chamadas de ferramenta na mesma rodada. Execute cada uma e retorne uma mensagem tool para cada chamada, cada uma com seu próprio tool_call_id. Não as combine.

Controlando chamadas

tool_choice é sua alavanca de política: auto deixa o modelo decidir, exigir uma ferramenta específica força uma chamada, e desabilitar ferramentas diz ao modelo para responder diretamente. Mantenha um orçamento — se uma ferramenta continuar falhando e o modelo continuar tentando, o ciclo de ferramentas pode durar muito. Limite o número de iterações no seu próprio ciclo e retorne uma mensagem clara ao atingir o limite, em vez de deixar a requisição se arrastar.

Trate a saída da ferramenta como não confiável

O modelo lê o resultado da ferramenta como texto. Mantenha-os pequenos, estruturados, sem instruções, e valide os argumentos do seu lado. Ferramentas que retornam texto ilimitado são tanto um problema de custo quanto um risco de correção.

Diagnosticando erros comuns

A maioria das falhas de integração se encaixa em cinco categorias. Siga esta lista antes de mexer nos prompts.

1. Autenticação e autorização

  • Sintoma: status HTTP na faixa 401/403.
  • Verifique: a chave existe, não tem espaços em branco antes ou depois ao colar, e tem exatamente o prefixo Bearer .
  • Verifique: a URL base corresponde à exibida no console do HiAPI — um host desatualizado ou colado errado gera erros de autenticação confusos.
  • Correção: reexporte as variáveis de ambiente e execute novamente o teste rápido com curl antes de mexer no código.

2. Payload malformado

  • Sintoma: erro de validação de requisição nomeando um campo, ou corpo de resposta impossível de analisar.
  • Verifique: o corpo é JSON válido. Quando construído manualmente, valide com um json.tool rápido; quando construído em código, garanta que o dicionário não tenha um nível extra de aninhamento por acidente.
  • Verifique: messages não está vazio e cada item tem role e content.
  • Verifique: os valores de role pertencem ao conjunto suportado. Erros de digitação como role: "human" são falhas silenciosas em alguns clientes, e não erros óbvios.
  • Verifique: os itens de tools têm type: "function" e um objeto function aninhado. Definições achatadas são o erro mais comum de chamadas de ferramentas.

3. Identificador do modelo

  • Sintoma: erro do tipo não encontrado, ou aviso de que o modelo não está disponível para sua conta.
  • Verifique: o identificador foi copiado exatamente do console. Maiúsculas, minúsculas e separadores importam.
  • Verifique: o modelo está habilitado para sua chave. Mesmo com um identificador válido, um modelo que sua conta não pode chamar ainda falhará.

4. Limites de contexto e comprimento

  • Sintoma: erro sobre a requisição exceder o contexto máximo, ou resposta terminando com um finish_reason relacionado a comprimento.
  • Verifique: a soma do seu prompt de sistema, histórico de mensagens e quaisquer definições de ferramentas. Os esquemas de ferramentas contam no orçamento e são facilmente esquecidos.
  • Correção: corte o histórico, resuma turnos anteriores ou divida a tarefa. Para truncamento de saída, aumente max_tokens se a carga realmente precisar de mais; caso contrário, mantenha-o limitado.

5. Rate limiting e timeouts

  • Sintoma: status de limitação sob carga, ou timeout de leitura no cliente.
  • Verifique: se os retries estão sendo feitos sem nenhum backoff. Ciclos de retry apertados transformam uma limitação passageira em limitação contínua.
  • Correção: siga os sinais de rate limiting indicados na resposta, use backoff exponencial limitado com jitter e controle a concorrência por chave. Para timeouts, verifique primeiro o valor de timeout do cliente — um limite do cliente menor que o tempo de geração do modelo produz exatamente esse sintoma.

Disciplina geral de depuração

Registre quatro coisas em cada falha: status HTTP, corpo da resposta, identificador do modelo e se stream estava definido. Esses quatro itens explicam a grande maioria dos incidentes. E mantenha o teste rápido com curl atualizado — quando ele passa e sua aplicação falha, você sabe que o problema está no código, não nas credenciais.

Lendo as mensagens de erro

A camada agregadora em geral informa claramente qual campo causou a rejeição. Resista à tentação de reescrever o prompt. Leia a mensagem, corrija o campo indicado e tente mais uma vez. Se o mesmo erro persistir, valide a requisição contra o teste rápido antes de aprofundar.

Antes de ir para produção: lista de verificação

A diferença entre "funciona no meu terminal" e "funciona em produção" é, em grande parte, uma lista de verificação que ninguém escreveu. Aqui está uma que vale copiar.

Configuração e segredos

  • A API Key fica em um gerenciador de segredos, nunca no controle de código-fonte e nunca em uma URL ou linha de log. Confirme que seu cliente HTTP não consegue imprimir o cabeçalho Authorization em nível de depuração.
  • A URL base e o identificador do modelo são configuração, não constantes espalhadas pelo código. Confirme a URL base no console.
  • Rotacione chaves de acordo com um plano e após a saída de qualquer membro da equipe. Seu código cliente deve pegar a chave rotacionada sem alterações.

Higiene das requisições

  • Toda chamada de saída tem timeout explícito, e o caminho de streaming tem timeout mais folgado com regras de aborto por inatividade.
  • Todo caminho de chamada define max_tokens. Geração ilimitada é fatura ilimitada.
  • As configurações de amostragem são fixas por caso de uso e documentadas, para que os resultados sejam reproduzíveis quando precisar depurar.

Tratamento de respostas

  • Seu parser ramifica com base no finish_reason e trata truncamento como um resultado separado, não como resposta completa.
  • A acumulação de streaming é testada tanto com respostas curtas quanto longas, incluindo respostas encerradas antecipadamente.
  • Os argumentos de chamadas de ferramentas são validados antes do uso, e o turno de chamada de ferramenta do assistente sempre é ecoado no array de mensagens.
  • O ciclo de ferramentas tem um limite de iterações e uma mensagem de falha clara.

Comportamento em falhas

  • Os retries são limitados, usam backoff exponencial limitado com jitter e se aplicam apenas a operações seguras de repetir.
  • Respostas de rate limiting são respeitadas, e não bombardeadas.
  • Falhas registram status, corpo da resposta, identificador do modelo e o flag de stream — esses quatro campos realmente resolvem incidentes.
  • O teste rápido com curl roda em CI ou de forma agendada, para que você descubra mudanças de credenciais ou de modelo pelo painel, e não por meio de clientes.

Custo e capacidade

  • Você sabe como o uso é cobrado — a plataforma cobra por token processado, então prompts longos e gerações longas importam. Consulte as tarifas atuais no painel de preços do console.
  • Você sabe qual tipo de carga é o maior consumidor e se ele precisa do modelo completo ou de um modelo mais leve.
  • Você tem um caminho de degradação: se uma chamada falhar repetidamente, a aplicação degrada de forma visível em vez de travar silenciosamente.

A última pergunta

Pergunte-se: alguém que não escreveu esta integração consegue observá-la. Se um desenvolvedor da sua equipe consegue ler o teste rápido, os campos de log de erro e a configuração, e entender como diagnosticar falhas, você terminou. Se não, a lista ainda não está completa.

Com uma chamada curl executável, um cliente Python reutilizável e esta lista de verificação, o kimi-k3.1-pro está de fato integrado — e não apenas conectado.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API