-1

Streaming com APIs de IA (SSE): resposta em tempo real na prática

Se você já usou ChatGPT, já viu streaming em ação: os tokens aparecendo aos poucos. É assim que dá para construir UX de IA decente — e é mais simples do que parece.

O que acontece por baixo

A API usa Server-Sent Events (SSE): o servidor mantém a conexão aberta e vai mandando pedaços da resposta. Com o SDK da OpenAI (compatível com a maioria dos gateways), é só stream=True:

from openai import OpenAI

client = OpenAI(base_url="https://api.exemplo.com/v1", api_key="sua-chave")

resposta = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Explique o que é SSE em 3 frases"}],
    stream=True,
)

for chunk in resposta:
    parte = chunk.choices[0].delta.content
    if parte:
        print(parte, end="", flush=True)
print()

No frontend (JavaScript), consumir o stream exige decodificar o SSE:

O fetch com stream: true devolve os bytes crus — é preciso decodificá-los, separar as linhas data: e parar no marcador de fim [DONE]:

async function main() {
  const resposta = await fetch("https://api.exemplo.com/v1/chat/completions", {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": "Bearer SUA_CHAVE" },
    body: JSON.stringify({
      model: "gpt-4o-mini",
      messages: [{ role: "user", content: "O que é streaming?" }],
      stream: true,
    }),
  });
  if (!resposta.ok) throw new Error(`HTTP ${resposta.status}`);

  const leitor = resposta.body.getReader();
  const decodificador = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await leitor.read();
    if (done) break;
    buffer += decodificador.decode(value, { stream: true });

    const linhas = buffer.split("\n");
    buffer = linhas.pop(); // guarda o resto incompleto do próximo chunk

    for (const linha of linhas) {
      if (!linha.startsWith("data:")) continue;
      const dados = linha.slice(5).trim();
      if (!dados || dados === "[DONE]") return;
      const parte = JSON.parse(dados).choices[0].delta.content ?? "";
      // mostre `parte` na tela, token a token
    }
  }
}

main().catch(console.error); // rode em ambiente com suporte a fetch (navegador moderno ou Node 18+)

Por que isso importa:

  • Percepção de velocidade — o primeiro token chega em frações de segundo; o usuário não espera uma tela congelada enquanto o texto completo é gerado;
  • Menos timeout de leitura — em gerações longas, o cliente não fica esperando a resposta inteira (o que estouraria o timeout de leitura). Atenção: se você usa um proxy reverso (ex.: Nginx), ajuste o proxy_read_timeout para não cortar a conexão SSE;
  • UX profissional — é o padrão de qualquer produto de IA sério.

Cuidado: no servidor (FastAPI/Node), repasse o stream ao frontend em vez de acumular e enviar tudo depois. E sempre trate o fim do stream ([DONE]) e erros de conexão — com retry/backoff, por exemplo.

Streaming é o divisor de águas entre um "protótipo que trava" e um "produto que responde".


Quer testar esses modelos no seu projeto? A ModelKiwi dá acesso a GPT, Claude e Gemini com recarga via PIX (sem cartão internacional) e créditos grátis para começar: https://www.modelkiwi.com. Fale com a gente no WhatsApp: +5521999500402.

Carregando publicação patrocinada...