Message threads no Claude: menos latência em agentes

Message threads é o novo recurso da Claude API que mantém a conversa no servidor por alguns minutos, para que cada turno envie apenas as mensagens novas.
O recurso entrou em beta pública em 1º de novembro de 2026. O objetivo é reduzir o tempo até o primeiro token em agentes com sessões longas.
A seguir, você entende como o recurso funciona e como usar o SDK. Também verá quais campos enviar e quais limitações exigem atenção.
O que são message threads na Claude API
A Messages API sempre foi sem estado, ou seja, cada requisição precisa carregar a conversa completa.
Com message threads, o servidor guarda a conversa por um curto período e reconstrói o histórico antes de chamar o modelo.
Na prática, você adiciona um único parâmetro, thread, à requisição da Messages API.
A resposta continua sendo a mensagem de sempre, então o restante da sua aplicação não muda.
Além disso, o primeiro turno envia tudo: as mensagens, o system e as tools.
Depois disso, cada turno envia somente o que surgiu desde a última resposta, junto com o id dessa resposta.
Por que reenviar a conversa inteira custa caro
Um agente de código pode fazer centenas de requisições em uma única sessão.
Sem thread, cada uma dessas requisições reenvia todas as mensagens anteriores e todos os resultados de ferramentas.
Além do upload, a API valida e tokeniza a conversa inteira de novo a cada turno.
Por isso, quando o contexto chega a centenas de milhares de tokens, esse trabalho repetido atrasa o início da resposta.
Com message threads, quase todo esse processamento passa a cobrir apenas o turno novo.
De acordo com a Anthropic, o recurso já vem ativado para a maioria dos usuários do Claude Code.
Nesse cenário, requisições entre 500 mil e 1 milhão de tokens tiveram queda de cerca de 35% na mediana do tempo até o primeiro token.
Contudo, existe um ponto que costuma gerar confusão: o consumo de tokens continua igual.
O Claude ainda lê a conversa completa em todos os turnos. Por isso, o ganho está na latência e no tamanho da requisição, não na fatura.
Como message threads funcionam: create, continue e replay
Em message threads, o ciclo de vida de uma thread tem três operações.
Primeiro você cria, em seguida continua turno a turno e, quando a thread some, você reenvia tudo.
Criar a thread
Para criar message threads, a primeira requisição é igual à que você faz hoje, com a conversa completa, o system e as tools.
A diferença é o campo "thread": {"type": "create"}, que pede à API para guardar a conversa e a resposta do Claude sob o id da resposta.
Continuar a thread
Com message threads, nos turnos seguintes você envia apenas as mensagens novas e o campo thread com o tipo continue e o previous_message_id.
Nesse caso, o system e as tools ficam de fora, porque a thread mantém os valores da criação.
Então cada nova resposta traz um id diferente, que vira a base do turno seguinte.
Reenviar quando a thread expira
O armazenamento de message threads funciona no modelo de melhor esforço.
Ela expira 5 minutos após a última requisição, e a API a apaga em no máximo 1 hora após o último uso.
Quando a API não consegue mais continuar, a requisição continue retorna um erro 404.
Nesse momento, você envia a conversa completa em uma nova requisição create e segue a partir do novo id.
Por isso, a sua aplicação continua sendo a fonte da verdade da conversa.
Guarde a sua própria cópia de cada mensagem e construa o caminho de replay desde o início. Afinal, nenhuma resposta informa se a API guardou aquele turno.
Usando message threads com o SDK
O SDK oferece um helper que monta as requisições de message threads para você.
Você cria o helper com os mesmos campos de uma requisição da Messages API e depois envia um turno de cada vez.
import anthropic
client = anthropic.Anthropic()
# Cria o helper; esta chamada ainda não envia nenhuma requisição
thread = client.beta.messages.thread(
model="claude-opus-5-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="You are a support agent for Acme. Keep replies short.",
)
# Turno 1: o helper cria a thread e envia a conversa completa
thread.send({"role": "user", "content": "Hi! I have a question about an order."})
# Turno 2: o helper continua a thread e envia só a mensagem nova
second = thread.send(
{"role": "user", "content": "How long does standard shipping usually take?"}
)
for block in second.content:
if block.type == "text":
print(block.text)
Nesse exemplo, o helper adiciona o header beta, cria a thread no primeiro turno e continua no segundo.
Ele também guarda a conversa completa em memória enquanto o objeto de message threads existe.
Contudo, ele não salva essa cópia em nenhum outro lugar. Então, uma conversa que precisa sobreviver ao processo exige persistência própria.
O cache_control de nível superior é opcional e pede prompt caching em cada turno, como você verá adiante.
Enviando o campo thread manualmente
Se você prefere montar as requisições por conta própria, com cURL ou com o método create comum do SDK, basta adicionar o campo thread.
Além disso, toda requisição de message threads precisa do header beta message-threads-2026-08-12.
import anthropic
client = anthropic.Anthropic()
# Turno 1: envia a conversa completa e cria a thread
first = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="You are a support agent for Acme. Keep replies short.",
messages=[{"role": "user", "content": "Hi! I have a question about an order."}],
thread={"type": "create"},
betas=["message-threads-2026-08-12"],
)
# Turno 2: envia só a mensagem nova e o id da resposta anterior
# system e tools ficam de fora, porque a thread já guarda os dois
second = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
messages=[
{"role": "user", "content": "How long does standard shipping usually take?"}
],
thread={"type": "continue", "previous_message_id": first.id},
betas=["message-threads-2026-08-12"],
)
Repare que o segundo turno repete o model e o cache_control, mas não repete o system.
Essa diferença segue uma regra de message threads, explicada na próxima seção.
O que enviar em cada requisição de message threads
A documentação divide os campos em três grupos, e errar o grupo gera erro 400.
| Grupo | Campos | Regra |
|---|---|---|
| Só na criação | system, tools |
Enviar apenas no create; no continue, mesmo como null, retorna erro 400 |
| Fixos | model, tool_choice, thinking, mcp_servers, context_management, output_config, skills do container, cache_control de nível superior e os valores de anthropic-beta |
Enviar em toda requisição com o mesmo valor da criação |
| Livres | max_tokens, stop_sequences, stream, metadata, service_tier e os demais |
Podem mudar de um turno para outro |
Quando um campo fixo muda, a API responde com o código thread_fingerprint_mismatch e cita os campos diferentes.
Para mudar um campo de criação ou um campo fixo, o caminho é iniciar uma nova thread com a conversa completa.
Também vale lembrar que a API não guarda as URLs dos servidores MCP, os tokens de autorização nem o id do container.
Então envie mcp_servers e container em toda requisição que os utiliza.
Outro cuidado: a API não compara as mensagens novas com as que já tem.
Se você reenviar uma mensagem antiga, ela pode aparecer duas vezes na conversa, ou a requisição pode falhar.
Message threads também só aceitam acréscimos, e cada id de resposta pode ser continuado uma única vez.
Por isso, para editar ou ramificar uma mensagem antiga, você precisa criar uma thread nova.
Prompt caching com message threads
Message threads não fazem cache do prompt automaticamente.
Em outras palavras, o prompt caching funciona exatamente como sem thread, e você continua escolhendo onde ficam os breakpoints.
Para fazer cache de cada turno, envie o cache_control de nível superior em todas as requisições da thread.
Assim, a API aplica o breakpoint ao último bloco cacheável das mensagens, e cada turno lê o histórico do cache e grava o turno novo.
Existem, porém, algumas regras específicas para breakpoints manuais:
- Breakpoints enviados na criação continuam valendo se estiverem em
tools, emsystemou em um bloco anterior ao último. - Você não consegue mover nem remover um breakpoint depois de enviado, porque o
continuenão reenvia mensagens antigas. - Cada requisição com
threadaceita no máximo 4 breakpoints, e ocache_controlde nível superior conta como um. - No replay, remova os breakpoints das mensagens antigas e mantenha um no último bloco.
Se você passar do limite de 4, a API retorna erro 400 com o código thread_unsupported_request.
Se o seu agente depende de cache para controlar custo, vale revisar o Guia completo do Claude Code. Ele mostra os comandos de custo e estratégia.
Streaming e recuperação de erros
Message threads funcionam com streaming, mas o momento de continuar importa.
O id da resposta chega no evento message_start, porém você só deve continuar depois do evento message_stop.
Se o stream de um continue cair antes do fim, envie a mesma requisição de novo.
Caso essa nova tentativa falhe com thread_already_continued ou thread_continue_in_flight, faça o replay da conversa completa.
Isso acontece porque a conexão pode ter caído enquanto o servidor ainda gerava a resposta, ou depois que ele já a tinha salvo.
De fato, o replay é sempre seguro.
Erros específicos de message threads
Os erros de message threads abaixo acontecem antes do modelo rodar, então a requisição não consome tokens.
| Status | Código | Significado | O que fazer |
|---|---|---|---|
| 404 | thread_not_found |
A API não consegue continuar a thread | Enviar a conversa completa em um novo create |
| 400 | thread_fingerprint_mismatch |
Um campo fixo difere do valor guardado | Manter o valor ou criar outra thread |
| 400 | thread_already_continued |
O id já foi continuado |
Continuar do id mais recente ou fazer replay |
| 400 | thread_continue_in_flight |
Outro continue do mesmo id ainda está rodando |
Esperar terminar ou fazer replay |
| 400 | thread_unsupported_request |
Recurso ou configuração não suportados | Remover o recurso ou enviar sem thread |
O erro 404 merece atenção especial, porque a resposta não diz o motivo.
Entre as causas estão a expiração e uma resposta gerada por modelo de fallback. Uma chave de API diferente da que criou a thread também provoca o erro, assim como a primeira imagem em uma conversa sem imagens.
Além disso, um modelo inexistente também retorna 404, então confira o error.details.error_code antes de fazer replay.
Se o 404 continuar logo depois do replay, a API pode não conseguir guardar aquela conversa, por exemplo quando ela é muito grande.
Nesse caso, envie sem thread, ou crie o helper com unsupported_request_behavior igual a continue_unthreaded.
Recusas, fallbacks e compactação
Quando uma resposta termina com stop_reason: "refusal", não continue a thread.
A API pode já guardar o turno recusado, e um continue não consegue removê-lo.
O correto é criar uma thread nova, deixando de fora ou reformulando o turno que causou a recusa.
Com fallback no servidor, message threads exigem uma decisão na criação: você envia fallbacks em todas as requisições da thread ou em nenhuma.
Como a thread mantém um único modelo, a API não guarda turnos escritos por um modelo de fallback.
Então, ao encontrar uma entrada fallback_message em usage.iterations, você envia a conversa completa em um novo create.
A compactação em message threads segue a mesma lógica de acréscimo.
Como não dá para trocar turnos antigos por um resumo, você gera o resumo no seu código. Depois, envia esse resumo como mensagem comum em uma nova thread.
Limitações e retenção de dados de message threads
Message threads não suportam Message Batches, contagem de tokens nem compactação sob demanda.
Context editing também fica de fora, com exceção de clear_thinking_20251015 usando keep: "all".
Organizações com HIPAA readiness habilitado ou com Inference hooks ligados também não conseguem usar o recurso.
Além disso, não existe API para listar, ler ou apagar uma thread.
Quanto aos dados, a API guarda a thread em memória, criptografada com uma chave gerenciada pelo servidor, e nunca a grava em armazenamento durável.
Ainda assim, message threads não são elegíveis para ZDR, o que pesa para empresas com exigências rígidas de retenção.
A thread também guarda arquivos por referência, então mantenha disponíveis todos os arquivos que a conversa usa.
Por fim, message threads não alteram preços nem limites de requisição.
O recurso está na Claude API e no Claude Platform on AWS. Ele também está no Claude in Microsoft Foundry e no Claude Models on Google Cloud.
Para os detalhes completos, consulte a documentação oficial da Anthropic.
Quando usar message threads
Message threads rendem mais em sessões ativas, nas quais a latência importa e o contexto cresce rápido.
A Anthropic destaca três cenários principais:
- Agentes de código de longa duração: cada resultado de ferramenta ou edição de arquivo aumenta a conversa.
- Agentes de computer use: as capturas de tela ficam na thread em vez de subir de novo a cada turno.
- Fluxos com muitos documentos e imagens: as requisições ficam bem menores.
Em resumo, quanto mais contexto o agente carrega, maior tende a ser a redução do tempo até o primeiro token.
Por outro lado, conversas curtas ou com pausas maiores que 5 minutos ganham pouco, porque a thread expira e o replay volta a enviar tudo.
Também não faz sentido usar message threads em processamento em lote, já que o Message Batches não aceita o campo thread.
Vale notar que o tool runner beta do SDK já usa uma thread por padrão.
Nesse caso, ele também adota continue_unthreaded, ou seja, volta a enviar sem thread quando a API não consegue guardar a conversa.
Se você preferir desligar esse comportamento, basta criar o runner com thread=False.
Além disso, o helper oferece métodos úteis para o dia a dia, como thread.fork() para copiar a conversa e thread.params para iniciar uma thread nova.
Com thread.update(...), você altera campos livres para os próximos turnos sem enviar nenhuma requisição.
Conclusão sobre message threads
Message threads resolvem um problema concreto de agentes longos: o custo de latência de reenviar e reprocessar a conversa inteira a cada turno.
Com um único parâmetro, a requisição passa a carregar só o que é novo. Assim, o tempo até o primeiro token fica menor e mais estável.
No entanto, o recurso exige disciplina.
Sua aplicação precisa manter a cópia da conversa, respeitar os campos fixos e controlar os breakpoints de cache. Além disso, o replay deve ser tratado como caminho normal.
Portanto, a recomendação para adotar message threads é começar pelo helper do SDK, que já cuida do header, do replay e das recusas.
Assim, você ganha a redução de latência sem reescrever o loop do seu agente.
FAQ
Message threads reduzem o custo em tokens?
Não. O Claude continua lendo a conversa completa a cada turno, então o consumo de tokens e os preços seguem iguais.
Por quanto tempo uma thread fica disponível?
Ela expira 5 minutos após a última requisição, e a API a apaga em no máximo 1 hora após o último uso.
Preciso guardar o histórico da conversa na minha aplicação?
Sim. Sua aplicação continua sendo a fonte da verdade e precisa da cópia completa para fazer o replay quando a thread expirar.
Posso mudar o system prompt no meio de uma thread?
Não. Para mudar system ou tools, você precisa criar uma nova thread com a conversa completa.
Message threads funcionam com streaming?
Sim, mas você só deve continuar a thread depois de receber o evento message_stop.
Qual header beta é obrigatório?
Toda requisição da thread precisa do header message-threads-2026-08-12, que o helper do SDK adiciona automaticamente.