Diagnóstico de cache
Diagnostique falhas inesperadas no cache de prompt comparando requisições consecutivas e identificando exatamente onde o prefixo do prompt divergiu.
O cache de prompt ("prompt caching") reduz significativamente a latência e o custo, mas apenas quando o início do seu prompt é idêntico, byte a byte, a uma requisição recente. Uma ferramenta reordenada, um timestamp interpolado no seu prompt do sistema ou uma edição em uma mensagem anterior podem invalidar o cache silenciosamente. Sem o diagnóstico de cache, o único sinal é usage.cache_read_input_tokens caindo para zero, sem nenhuma indicação do que mudou.
O diagnóstico de cache ("cache diagnostics") preenche essa lacuna. Passe o id da sua resposta anterior, e a API compara as duas requisições e informa onde elas divergiram (o modelo, o prompt do sistema, as ferramentas ou o histórico de mensagens), para que você possa corrigir a causa raiz em vez de adivinhar.
Como o diagnóstico de cache funciona
Quando o cabeçalho beta está presente, a API armazena uma "fingerprint" (impressão digital) leve de cada requisição, indexada pelo id da resposta. Na sua próxima requisição, inclua esse id como diagnostics.previous_message_id. A API reconstrói a fingerprint da nova requisição, compara-a com a armazenada e anexa um objeto diagnostics à resposta descrevendo o primeiro ponto de divergência.
A comparação diz respeito à estrutura da requisição, independentemente de o cache ter sido efetivamente atingido. Consulte Lendo o diagnóstico junto com o uso para saber como combinar o resultado de diagnostics com usage.cache_read_input_tokens.
As fingerprints contêm apenas hashes e estimativas de contagem de tokens (nunca o conteúdo bruto do prompt), são retidas por um tempo limitado, têm escopo restrito à sua organização e workspace, e não são usadas para nenhuma outra finalidade.
Uso básico
Envie o cabeçalho beta em cada turno. No primeiro turno, passe "previous_message_id": null para aderir sem uma mensagem anterior com a qual comparar. Nos turnos subsequentes, passe o id da resposta anterior.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# Turno 1: opte por participar com previous_message_id=None
r1 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[{"role": "user", "content": "Summarize section 1."}],
diagnostics={"previous_message_id": None},
betas=["cache-diagnosis-2026-04-07"],
)
# Turno 2: referencie o id da resposta anterior
r2 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
)
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")Streaming
Em respostas com streaming, diagnostics aparece no evento message_start.
# Turno 2: faça streaming, referenciando o id da resposta anterior
with client.beta.messages.stream(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
r2 = stream.get_final_message()
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")O evento message_start carrega o campo diagnostics completo; consulte Formato da resposta para ver os valores possíveis.
Encadeando o diagnóstico em um loop de conversa
Em uma conversa de múltiplos turnos, leve adiante o id da resposta mais recente como previous_message_id em cada turno. A primeira iteração passa null para aderir; cada iteração subsequente passa o id da resposta anterior.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
messages = []
prev_id = None
for i, user_message in enumerate(
["Summarize section 1.", "Now section 2.", "Now section 3."]
):
messages.append({"role": "user", "content": user_message})
r = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=messages,
diagnostics={"previous_message_id": prev_id},
betas=["cache-diagnosis-2026-04-07"],
)
if r.diagnostics is not None and r.diagnostics.cache_miss_reason is not None:
print(f"Turn {i + 1} cache_miss_reason: {r.diagnostics.cache_miss_reason.type}")
messages.append({"role": "assistant", "content": r.content})
prev_id = r.idFormato da resposta
O campo diagnostics no Message da resposta tem quatro estados possíveis:
| Valor | Significado |
|---|---|
| campo ausente | A requisição não incluiu diagnostics, ou o cabeçalho beta estava ausente. |
null | Ou previous_message_id era null (primeiro turno, nada para comparar), ou uma comparação foi executada e não encontrou divergência. |
{"cache_miss_reason": null} | A comparação ainda estava em execução quando a resposta foi serializada. Isso pode acontecer quando a resposta começa muito rapidamente. Trate como inconclusivo e verifique o próximo turno. |
{"cache_miss_reason": {...}} | Um cache_miss_reason está anexado. Para os tipos *_changed, isso identifica o primeiro ponto de divergência; previous_message_not_found e unavailable são casos em que nenhuma comparação foi produzida. |
Quando cache_miss_reason não é nulo, ele tem esta aparência:
{
"id": "msg_01Xyz...",
"type": "message",
"role": "assistant",
"content": [{ "type": "text", "text": "..." }],
"usage": {
"input_tokens": 42,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 41850,
"output_tokens": 210
},
"diagnostics": {
"cache_miss_reason": {
"type": "system_changed",
"cache_missed_input_tokens": 41850
}
}
}Tipos de motivo de falha de cache
cache_miss_reason é uma união discriminada por type. A resposta informa apenas a divergência mais antecipada, então corrija-a primeiro; divergências posteriores podem estar ocultas atrás dela.
| Tipo | O que significa | O que mudar |
|---|---|---|
model_changed | O model difere da requisição anterior (por exemplo, um roteador, teste A/B ou fallback selecionou um modelo diferente). O cache é por modelo. | Mantenha o modelo constante dentro de uma conversa em cache. |
system_changed | O parâmetro system difere. Normalmente um timestamp, ID de requisição ou outro valor por requisição foi interpolado no prompt do sistema. | Torne o prompt do sistema uma constante estável em bytes e mova os dados dinâmicos para a primeira mensagem user após o seu ponto de interrupção de cache. |
tools_changed | O array tools difere: ferramentas foram adicionadas, removidas ou reordenadas entre turnos, ou o JSON de input_schema das ferramentas foi serializado de forma não determinística. | Envie a mesma lista de ferramentas em cada turno, em uma ordem fixa, com schemas serializados de forma determinística (por exemplo, ordene as chaves). |
messages_changed | O modelo, o system e as tools coincidem, mas uma entrada anterior em messages foi alterada, reordenada ou removida em vez de apenas receber acréscimos. Normalmente o histórico da conversa foi truncado ou editado, ou turnos do assistente e blocos tool_result foram re-serializados de forma diferente no reenvio. | Trate o histórico como somente de acréscimo (append-only); devolva o content do assistente e os resultados de ferramentas literalmente. |
previous_message_not_found | Não existe fingerprint armazenada para o previous_message_id fornecido. Isso não é evidência de que sua requisição mudou. Normalmente a requisição anterior não carregava o cabeçalho beta, veio de um workspace diferente, ou passou tempo demais desde que foi enviada. | Envie o cabeçalho beta em cada turno e mantenha turnos consecutivos próximos no tempo. |
unavailable | As informações de diagnóstico não estavam disponíveis para esta requisição. Isso inclui o caso em que model, system e tools coincidem, mas outro parâmetro de requisição que afeta o prompt (tool_choice, thinking, context_management, output_config, output_format ou o conjunto de cabeçalhos anthropic-beta ativos) difere, e conversas muito longas em que a divergência está além do horizonte de comparação. Sua requisição foi processada normalmente. | Mantenha constantes os parâmetros de requisição que afetam o prompt durante toda a vida de uma conversa em cache. Se persistir, aplique as verificações manuais em Solução de problemas comuns na página de cache de prompt. |
Lendo o diagnóstico junto com o uso
diagnostics responde "minha requisição mudou?", enquanto usage.cache_read_input_tokens responde "o cache foi atingido?". Combiná-los indica onde procurar.
Esta matriz se aplica a turnos em que você passou um previous_message_id real. No primeiro turno (previous_message_id: null), diagnostics é sempre null e cache_read_input_tokens normalmente é zero porque o cache está sendo gravado, não lido; nenhuma solução de problemas é necessária. A matriz também não se aplica quando cache_miss_reason é null (a comparação ainda está pendente; verifique o próximo turno) ou quando seu type é previous_message_not_found ou unavailable (nenhuma comparação foi produzida).
| Resultado do diagnóstico | Tokens lidos do cache | Interpretação |
|---|---|---|
null | alto | Funcionando como esperado. Seu prefixo é estável e o cache foi atingido. |
null | baixo ou zero | Suas requisições coincidem, mas a entrada de cache não estava mais disponível. Considere reduzir os intervalos entre turnos ou usar o TTL de cache de 1 hora. |
cache_miss_reason é um tipo *_changed | baixo ou zero | Bug seu. A requisição mudou; corrija a causa indicada por type. |
cache_miss_reason é um tipo *_changed | alto | Raro. Uma mudança ocorreu no final do prompt, mas um ponto de interrupção cache_control anterior ainda foi atingido. Vale corrigir, mas o impacto é baixo. |
Limitações
- Beta: Os nomes e a semântica dos campos podem mudar enquanto este recurso estiver em beta.
- Somente Claude API: Não disponível no Amazon Bedrock nem no Google Cloud.
- Retenção limitada: As fingerprints para consulta de
previous_message_idexpiram após um curto período. Execute comparações de diagnóstico entre requisições próximas no tempo. - Mesmo workspace: A requisição anterior deve ter sido executada na mesma organização e workspace. Para verificar, compare o cabeçalho de resposta
anthropic-workspace-idnas duas respostas. - Horizonte de comparação: Para conversas muito longas em que a única mudança está profundamente na lista de mensagens, a resposta pode ser
unavailableem vez de uma localização precisa. - Melhor esforço: O diagnóstico nunca bloqueia nem faz sua requisição falhar. Se as informações de diagnóstico não estiverem disponíveis, a resposta retorna
unavailable, oucache_miss_reason: nullquando a comparação ainda estava em execução.
Retenção de dados
O diagnóstico de cache é elegível para ZDR (qualificado). A Anthropic não armazena o texto bruto dos seus prompts nem as saídas do Claude para este recurso.
A fingerprint armazenada para cada requisição consiste apenas em hashes criptográficos e estimativas de contagem de tokens, indexada pelo id da resposta e com escopo restrito à sua organização e workspace. As fingerprints expiram após um curto período e não são usadas para nenhuma outra finalidade.
Para a elegibilidade ZDR em todos os recursos, consulte API e retenção de dados.
Veja também
Compatibility
| Supported platforms |
|
|---|
Was this page helpful?