Oito segundos encarando um spinner matam a conversão. Os mesmos oito segundos em chunks dão sensação de resposta imediata. Streaming de respostas de IA reduz a latência percebida de 8s para menos de 1s porque o primeiro token chega rápido e o resto flui. Server-Sent Events entrega isso com menos complexidade que WebSockets na maioria dos casos.
SSE: HTTP com eventos
SSE usa text/event-stream como content type, eventos separados por linha em branco e reconexão automática no EventSource do navegador. Cada evento cabe em poucos bytes; proxies e balanceadores lidam com o fluxo sem strain. Conexões ociosas morrem em proxy intermediário. Um comentário de keepalive (: ping a cada 15s) mantém o caminho aberto. LLM flui do servidor ao cliente; SSE cobre tudo com um request HTTP comum.
Quando WebSockets compensam
- Fluxo bidirecional real: agentes de voz, sessões colaborativas, interrupção do usuário no meio da fala
- Latência de mensagem abaixo de 100ms muda a experiência percebida
- Multiplexação de várias streams lógicas numa conexão única
Streaming no backend
O servidor encaminha os deltas do provedor conforme chega e descarrega buffers sem esperar acumular. O nginx segura chunks por padrão e queima a experiência: proxy_buffering off; na location ou X-Accel-Buffering: no na resposta resolvem. Compressão gzip em respostas parciais também retém bytes; desative nesse endpoint.
Cancelamento
O usuário clicou em stop? O cliente aborta o fetch, o servidor detecta a conexão fechada (request.on('close') no Express, cancelamento de generator no FastAPI) e encerra a chamada upstream. Provedores cobram pelos tokens gerados até o corte; o corte precisa acontecer dos dois lados. Registre o cancelamento nos logs com o ID da sessão. Sem essa cadeia, toda sessão abandonada paga tokens que ninguém leu.
Erros no meio do stream
O provedor derruba a conexão após metade da resposta. Envie o que chegou mais um evento final de erro estruturado; o cliente renderiza o parcial com marcador de falha e botão de regenerar. Quando o provedor suporta continuação, regenere a partir do último chunk recebido. Silêncio até o timeout é a alternativa ruim.
Notas por framework
- Next.js: route handlers streameam
ReadableStreamsem biblioteca extra - Express: headers
Content-Type: text/event-stream,Cache-Control: no-cache,Connection: keep-alive, comres.flush()após cada chunk - FastAPI:
StreamingResponsede fábrica consumindo generators async
Curtiu o conteúdo?
Construo produtos web e soluções com IA do jeito certo — arquitetura sólida, código sustentável e entrega real.
Vamos conversar