Como os Server-Sent Events Potencializam as Respostas de Streaming da Claude
Quando você chama a Claude Messages API sem streaming, você envia uma requisição e espera.
Nada retorna até que toda a resposta seja gerada.
Para uma resposta longa, essa espera pode ser de vários segundos de tela em branco.
O streaming muda o mecanismo de entrega, não o conteúdo: em vez de uma grande resposta no final, a Claude envia a mesma resposta como uma sequência de eventos pequenos e tipados por uma única conexão aberta, à medida que as palavras são geradas.
Entender o transporte por trás do streaming - Server-Sent Events - e a forma dos eventos que ele carrega é a base para todo o resto nesta seção, desde a impressão de tokens à medida que chegam até a construção de uma UI de chat ao vivo e o streaming de chamadas de ferramentas.
Resumo
- Ideia Central: A API de streaming da Claude envia a resposta como uma sequência ordenada de eventos SSE tipados por uma conexão HTTP, em vez de um único blob JSON no final.
- Por que Importa: Permite que um aplicativo comece a renderizar a saída no momento em que os primeiros tokens existem, em vez de bloquear a interface do usuário até que a geração seja concluída.
- Conceitos Chave: Server-Sent Events, stream de eventos,
message_start,content_block_delta,text_delta,message_delta,message_stop. - Quando Usar: Qualquer interface voltada para o usuário onde a latência percebida importa - UIs de chat, assistentes de codificação, geração de documentos ao vivo e qualquer resposta longa que o usuário esteja assistindo ativamente.
- Limitações / Trade-offs: O streaming adiciona complexidade no lado do cliente (estado parcial, tratamento de erros, reconexões) e não é compatível com alguns padrões de cache ou processamento em lote que desejam a resposta completa como uma unidade.
- Tópicos Relacionados: o modelo de requisição/resposta da Messages API, uso de ferramentas, pensamento estendido, o helper de streaming do SDK Python.
Fundamentos
Server-Sent Events (SSE) é um padrão web de longa data para streaming unidirecional, do servidor para o cliente, sobre HTTP puro.
Um cliente abre uma requisição HTTP normal, mas em vez do servidor enviar uma resposta e fechar a conexão, o servidor mantém a conexão aberta e escreve uma sequência de pequenos frames de texto nela ao longo do tempo.
Cada frame é prefixado com data: e separado por linhas em branco - é deliberadamente simples, mais simples que WebSockets, porque só precisa fluir em uma direção: do servidor para o cliente.
A Messages API da Claude usa exatamente esse mecanismo quando você solicita stream=true (ou usa o helper de streaming do SDK).
Em vez de um corpo de resposta HTTP contendo a mensagem finalizada, a conexão permanece aberta e o servidor escreve uma série de eventos, cada um um pequeno objeto JSON descrevendo uma peça incremental da resposta.
Uma analogia útil: uma resposta não-streaming é como esperar que uma carta inteira seja impressa e depois entregue a você.
Uma resposta de streaming é como observar alguém digitar essa mesma carta na sua frente, linha por linha, através de uma janela que informa exatamente que tipo de coisa foi digitada - um título, uma frase, uma assinatura.
Os tipos de eventos são o que tornam isso útil: cada um nomeia precisamente o que mudou, para que o código do cliente nunca precise adivinhar.
import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Explique SSE em um parágrafo."}],
) as stream:
for event in stream:
print(event.type) # message_start, content_block_delta, ..., message_stopEsse loop é a forma que todo consumidor de streaming adota: abre um stream, recebe uma sequência de eventos tipados e reage a cada tipo de forma diferente.
Mecânicas e Interações
A sequência de eventos para uma resposta de texto típica segue um esqueleto fixo:
message_start
content_block_start (index 0, type: text)
content_block_delta (text_delta, "Olá")
content_block_delta (text_delta, " mundo")
content_block_delta (text_delta, "!")
content_block_stop (index 0)
message_delta (stop_reason, totais de uso)
message_stop
message_start chega primeiro e carrega o shell de metadados da mensagem - seu id, model e uso inicial (próximo de zero) - antes que qualquer bloco de conteúdo exista.
Entre isso e message_stop, a resposta é construída a partir de um ou mais blocos de conteúdo, cada um aberto com content_block_start e fechado com content_block_stop.
Uma única resposta pode conter múltiplos blocos de conteúdo em sequência - por exemplo, um bloco thinking seguido por um bloco text, ou um bloco text seguido por um bloco tool_use - e cada um é identificado por seu index para que um cliente possa rastrear o estado parcial de vários blocos independentemente.
A saída real token por token chega como eventos content_block_delta aninhados dentro do par start/stop de um bloco.
Para um bloco de texto, o delta.type do delta é text_delta e seu delta.text é o próximo fragmento de texto - concatenar todos os text_delta para um bloco, em ordem, reconstrói o texto completo desse bloco.
content_block_delta é um envelope genérico, no entanto - o delta.type dentro dele varia de acordo com o tipo de bloco que está sendo transmitido: text_delta para prosa, input_json_delta para os argumentos de uma chamada de ferramenta e thinking_delta para pensamento estendido, cada um carregando uma carga útil parcial diferente que é montada de forma diferente.
message_delta chega uma vez, perto do final, e carrega campos de nível de mensagem que não eram conhecidos até a geração ser concluída - stop_reason (por que o modelo parou) e totais de token em execução usage.
message_stop é o evento final e sinaliza que o stream está completo; nenhum outro evento seguirá para esta resposta.
Um erro de raciocínio comum é esperar que um content_block_delta seja igual a um token, ou que um text_delta seja um limite de palavra limpo.
Nenhum dos dois é garantido - um delta pode ser uma palavra parcial, vários tokens, ou até mesmo dividido no meio de uma sequência de caracteres para texto multibyte - então o código do cliente deve tratar os deltas como fragmentos opacos para concatenar, nunca como unidades para analisar individualmente.
Considerações Avançadas e Aplicações
O modelo de eventos escala para as capacidades mais avançadas da Claude sem alterar sua forma, o que o torna componível.
Uma chamada de ferramenta transmite sua input como uma string JSON construída incrementalmente em muitos eventos input_json_delta - a string parcial não é um JSON válido até que o bloco seja fechado, então um cliente deve armazenar em buffer cada delta para esse bloco e só tentar analisar quando content_block_stop disparar para ele. Veja Tratando JSON Parcial Durante Chamadas de Ferramentas Transmitidas para o padrão de acumulação.
Pensamento estendido, quando habilitado, transmite seu raciocínio como um bloco de conteúdo separado usando eventos thinking_delta, antes do bloco text - uma UI pode renderizar esse bloco de forma distinta (por exemplo, um painel de "raciocínio" recolhido) em vez de misturá-lo ao texto da resposta. Veja Transmitindo Blocos de Pensamento Estendido para o Frontend.
Como as chamadas de ferramentas são transmitidas pelos mesmos tipos de eventos que o texto, um cliente pode observar um único stream para ambos: renderizar texto à medida que ele chega, e no momento em que um content_block_start relata type: "tool_use", saber que é hora de acumular argumentos em vez de exibi-los - esta é a base para combinar streaming com o loop de uso de ferramentas.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Requisição não-streaming | Código cliente mais simples; uma análise de um único objeto JSON | O usuário espera pela resposta completa antes de ver qualquer coisa | Tarefas em segundo plano, geração em lote, chamadas de servidor para servidor sem visualizador ao vivo |
| Streaming SSE | Renderiza a saída à medida que é gerada; menor latência percebida | Requer tratamento de tipos de evento, buffer de estado parcial, lógica de reconexão | UIs de chat, assistentes de codificação, qualquer interface que um usuário esteja assistindo em tempo real |
| Streaming + uso de ferramentas | Mesma responsividade, mais chamadas de ferramentas no meio da resposta | Deve distinguir blocos de texto de blocos tool_use, buffer de deltas JSON | Loops de agente onde o usuário deve ver raciocínio/texto antes que um resultado de ferramenta retorne |
No nível de transporte, SSE é executado sobre a mesma conexão HTTP que qualquer outra chamada de API, portanto, herda modos de falha de rede comuns - proxies que armazenam saída em buffer, balanceadores de carga com timeouts ociosos e conexões que simplesmente caem no meio da resposta.
O código de produção deve tratar o stream como não confiável: armazenar em buffer o que chegou, detectar uma queda e decidir se retoma ou reinicia a requisição. Veja Melhores Práticas de Streaming para os padrões concretos.
Conceitos Equivocados Comuns
- "Cada evento SSE é um token." Na prática, um
text_deltapode abranger múltiplos tokens ou ser um fragmento sub-token - nunca assuma uma granularidade fixa, sempre concatene. - "O stream envia a mensagem inteira e eu a filtro no lado do cliente." O servidor faz a geração incremental; o cliente só vê o que foi gerado até agora, não a mensagem completa com antecedência.
- "
content_block_deltasempre significa texto." É um envelope genérico - seudelta.typeinterno determina se étext_delta,input_json_deltaouthinking_delta. - "Streaming é uma API diferente." É a mesma Messages API e o mesmo corpo de requisição, com
stream=true(ou o helper de streaming do SDK) mudando apenas como a resposta é entregue. - "Uma conexão interrompida no meio do stream ainda fornece uma mensagem parcial válida." Uma interrupção pode ocorrer em qualquer limite de byte; o cliente deve lidar com um bloco incompleto graciosamente, não assumir que recebeu um prefixo limpo.
FAQs
O que "SSE" realmente significa e é específico da Claude?
Server-Sent Events. É um padrão web geral (não uma invenção da Anthropic) para streaming unidirecional, do servidor para o cliente, sobre HTTP, também usado por muitas outras APIs e frameworks web.
Preciso analisar manualmente o formato do wire SSE?
Não. O gerenciador de contexto client.messages.stream(...) do SDK oficial anthropic Python analisa os frames SSE para você e produz objetos de evento tipados - você trabalha com event.type e event.delta, não com linhas data: brutas.
Qual é o primeiro evento que verei em qualquer stream?
message_start. Ele carrega o shell da mensagem - id, modelo, role - antes que qualquer bloco de conteúdo tenha começado.
Como sei quando toda a resposta está concluída?
O evento message_stop é sempre o último. Entre message_delta (que carrega stop_reason e uso final) e message_stop, a resposta está efetivamente completa.
Uma única resposta pode transmitir mais de um bloco de conteúdo?
Sim. Uma resposta pode conter múltiplos blocos em sequência - por exemplo, um bloco thinking, depois um bloco text, depois um bloco tool_use - cada um com seu próprio par content_block_start/content_block_stop e index.
É garantido que `text_delta` quebre em limites de palavras?
Não. Trate cada delta como um fragmento de texto opaco e concatene-os em ordem; nunca assuma que começa ou termina em um limite de espaço em branco ou palavra.
Qual é a diferença entre `content_block_delta` e `message_delta`?
content_block_delta carrega conteúdo incremental dentro de um bloco (texto, JSON de ferramenta ou pensamento). message_delta carrega informações de nível de mensagem que só são conhecidas quando a geração está terminando, como stop_reason e uso cumulativo de tokens.
Como uma chamada de ferramenta transmitida se parece diferente do texto transmitido?
O content_block_start do bloco relata type: "tool_use" em vez de type: "text", e seus deltas chegam como input_json_delta (uma string JSON crescente) em vez de text_delta.
Por que não consigo analisar o delta de argumentos de uma chamada de ferramenta delta por delta?
Cada input_json_delta é um fragmento de uma string JSON em construção - não é um JSON válido por si só. Você deve acumular cada fragmento para esse bloco e analisar a string unida somente após o fechamento do bloco.
O streaming muda o que o modelo gera?
Não. O corpo da requisição e a saída do modelo são os mesmos de qualquer forma - o streaming muda apenas o mecanismo de entrega, não o conteúdo gerado.
O que acontece se a conexão cair no meio do stream?
Você recebe todos os eventos que chegaram antes da queda e nenhum message_stop. Clientes de produção precisam detectar isso (por exemplo, um timeout sem novos eventos) e decidir se tentam novamente a requisição, pois o próprio SSE não garante a entrega dos eventos restantes.
O streaming é necessário para que o uso de ferramentas ou o pensamento estendido funcionem?
Não, ambos funcionam em requisições não-streaming também. O streaming é puramente uma escolha de mecanismo de entrega que, quando habilitado, também expõe o conteúdo de ferramentas e pensamento incrementalmente.
Relacionados
- Fundamentos de Respostas de Streaming - o primeiro exemplo executável de consumo deste stream de eventos.
- Referência de Tipos de Eventos de Streaming - uma tabela de consulta para cada tipo de evento e seus campos.
- Tratando JSON Parcial Durante Chamadas de Ferramentas Transmitidas - acumulando
input_json_deltacom segurança. - Transmitindo Blocos de Pensamento Estendido para o Frontend - tratando
thinking_delta. - Streaming de Respostas com o SDK Python - o helper de streaming do SDK com mais detalhes.
Versões da Stack: Escrito contra a linha de modelos Claude atual em ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão), e Claude Haiku 4.5 - e o SDK oficial
anthropicPython (última versão 0.x). Nomes de modelos, versões de SDK e preços mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.