Pular para o conteúdo

Streaming

Como o Streaming Funciona

Defina stream: true na sua requisição de chat completion e o gateway Floopy retorna a resposta como Server-Sent Events (SSE). Cada evento contém um objeto chat.completion.chunk com conteúdo incremental, entregue assim que o provider o gera.

O gateway faz proxy dos frames SSE diretamente do provider upstream para o seu client sem atraso de buffering. Sua aplicação recebe tokens no momento em que são produzidos, proporcionando aos usuários uma experiência responsiva, estilo máquina de escrever.

Nenhuma alteração de código além de stream: true é necessária — o gateway cuida do resto.

Exemplos de Código

import { OpenAI } from "openai";
const client = new OpenAI({
baseURL: "https://api.floopy.ai/v1",
apiKey: process.env.FLOOPY_API_KEY,
});
const stream = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Explain quantum computing in simple terms." }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) process.stdout.write(content);
}

Formato da Resposta

Cada frame SSE é um objeto JSON prefixado com data:. O stream termina com um sentinel data: [DONE]:

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant"},"index":0}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"},"index":0}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"delta":{"content":" there"},"index":0}]}
data: [DONE]

O primeiro chunk geralmente contém o campo role. Os chunks subsequentes carregam o content incremental. Seu client deve concatenar os valores de content para reconstruir a resposta completa.

O Que é Cacheado

Respostas de streaming são totalmente compatíveis com cache. O gateway armazena os chunks internamente conforme chegam e, uma vez que o stream é concluído, monta a resposta completa e a armazena no cache — exatamente como se fosse uma requisição sem streaming.

Em futuros cache hits, a resposta completa é retornada como uma única resposta sem streaming (ou re-dividida em frames SSE, dependendo se a nova requisição define stream: true). O header Floopy-Cache-Bucket-Max-Size funciona da mesma forma — cada resposta armazenada conta como uma entrada no bucket.

Streaming e o Firewall

As verificações do firewall são executadas antes do streaming começar. O firewall baseado em LLM (com short-circuit pelo cache de vereditos no Qdrant) avalia o prompt de entrada enquanto a requisição ainda está armazenada no gateway. Se o prompt for classificado como unsafe, um erro 400 é retornado e o stream nunca é aberto.

Uma vez que o stream começa, ele não é interrompido pelo firewall. A resposta flui diretamente do provider para o seu client sem inspeção adicional.

Streaming e Observabilidade

O gateway monta a resposta completa a partir de todos os chunks após o término do stream. Os seguintes dados são registrados no ClickHouse como uma única linha em request_response_rmt:

  • Texto completo da resposta — o conteúdo concatenado de todos os chunks.
  • Total de tokens — tokens do prompt e tokens de completion conforme reportado no campo usage do chunk final (quando o provider inclui).
  • Latência — medida desde o primeiro byte enviado ao provider até o último chunk recebido.
  • Custo — calculado a partir das contagens de tokens e da precificação do modelo.
  • Time to first token (TTFT) — o intervalo entre o envio da requisição e o recebimento do primeiro chunk com conteúdo.

Tudo isso aparece nos logs do dashboard junto com requisições sem streaming, sem necessidade de filtragem especial.

Casos Extremos

CenárioComportamento
Timeout de inatividadeSe nenhum novo frame SSE chegar por 30 segundos (configurável), o gateway fecha a conexão e registra uma resposta parcial.
Tamanho máximo do bufferO buffer interno é limitado a 1 MB por padrão. Se a resposta montada exceder esse limite, o stream é encerrado e a resposta parcial é registrada.
Client desconectaO gateway detecta a conexão fechada e cancela a requisição ao provider upstream para evitar desperdício de tokens. A resposta parcial é registrada.
Erro do provider durante o streamSe o provider enviar um evento de erro durante o streaming, o gateway o encaminha ao client e registra o erro junto com qualquer conteúdo parcial recebido.

O timeout de inatividade e o tamanho máximo do buffer podem ser ajustados em Settings > Gateway ou via variáveis de ambiente.