← Voltar ao curso
Nível 3 — Automação e escala · Módulo 3.7 — Claude API e agentes sob medida

3.7.4 · Features: caching, citations, thinking

5 min de vídeo TEC

Objetivo: ao final, o consultor usa prompt caching sem invalidá-lo por acidente, entrega resposta ancorada na fonte com citations, e controla profundidade de raciocínio por effort em vez de budget_tokens.

O que você precisa levar desta aula

  1. Prompt caching é casamento de prefixo. Ordem fixa (toolssystemmessages), e qualquer byte diferente invalida tudo depois dele — data, UUID e JSON não ordenado no prefixo destroem o cache sem que nada falhe. Confira em usage.cache_read_input_tokens.
  2. Citations transforma resposta em entregável auditável: cada trecho volta amarrado ao pedaço exato da fonte. Não convive com structured outputs na mesma chamada — a combinação retorna 400.
  3. budget_tokens retorna 400 nos modelos atuais. O controle de profundidade de raciocínio é output_config.effort (lowmax) com adaptive thinking, e o conteúdo do raciocínio só volta com display: "summarized".

Prompt caching

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=16000,
    system=[
        {
            "type": "text",
            "text": CATALOGO_RICEFW_MERIDIANO,      # ~40 mil tokens, estável
            "cache_control": {"type": "ephemeral"},  # marca o fim do prefixo estável
        }
    ],
    messages=[{"role": "user", "content": pergunta}],  # varia a cada chamada
)

print(response.usage.cache_creation_input_tokens)  # gravou
print(response.usage.cache_read_input_tokens)      # leu (é o que você quer ver > 0)
print(response.usage.input_tokens)                 # pagou integral
Item Valor
Custo de leitura ~0,1× do preço de entrada
Custo de gravação 1,25× (TTL de 5 min) · 2× (TTL de 1 hora)
Ponto de equilíbrio 2 chamadas com TTL de 5 min · 3 com TTL de 1 hora
Máximo de marcações 4 por requisição
Prefixo mínimo 512 tokens no Opus 5 · 1024 no Opus 4.8 e Sonnet 5
Ordem de montagem toolssystemmessages

Prefixo abaixo do mínimo não cacheia e não avisacache_creation_input_tokens volta zero e pronto.

O que destrói o cache sem avisar

Padrão no prefixo Por quê
datetime.now() no system prompt Prefixo diferente em toda chamada
UUID ou id de requisição no começo Idem
json.dumps(d) sem sort_keys=True Serialização não determinística
Nome ou id do usuário no system prompt Um cache por usuário; nada é compartilhado
Bloco condicional (if flag: system += ...) Cada combinação vira um prefixo distinto
Lista de tools montada por usuário Tools são a posição zero — invalida tudo
Trocar de modelo no meio Cache é por modelo

A regra de arquitetura que resolve quase tudo: congele o system prompt e a lista de tools; ponha o que varia depois da última marcação. Data, modo, nome do usuário e contexto dinâmico vão para a mensagem do usuário, não para o system.

E o diagnóstico é sempre o mesmo: se cache_read_input_tokens fica zero entre chamadas que deveriam compartilhar prefixo, compare os bytes das duas requisições. O invalidador está lá.

Citations

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=16000,
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "document",
                "source": {"type": "text", "media_type": "text/plain", "data": TEXTO_FS_17},
                "title": "FS RICEFW 17 — Relatório de Pendências de Faturamento",
                "citations": {"enabled": True},
            },
            {"type": "text", "text": "Quais regras de alçada esta FS define para liberação?"},
        ],
    }],
)

for bloco in response.content:
    if bloco.type == "text":
        print(bloco.text)
        for c in (bloco.citations or []):
            print(f"    ↳ {c.document_title}: “{c.cited_text}”")

Como funciona:

Por que isso importa em consultoria: um entregável com citação é verificável pelo cliente sem confiar em você. A afirmação "a FS 17 exige dupla aprovação acima de 50 mil" vira "a FS 17 exige dupla aprovação acima de 50 mil — página 12, trecho citado". A segunda sobrevive a uma auditoria; a primeira sobrevive até alguém conferir.

E note a ligação com a aula 3.4.2: lá o problema era resumo fluente que omite. Citations é o mecanismo que ataca isso na origem — cada afirmação carrega o ponteiro para a fonte, e o revisor confere a fonte em vez de julgar a redação.

Thinking

response = client.messages.create(
    model="claude-opus-5",
    max_tokens=16000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "high"},        # low | medium | high | xhigh | max
    messages=[{"role": "user", "content": pergunta_dificil}],
)
Parâmetro Situação hoje
thinking: {"type": "adaptive"} O modo atual. O Claude decide quando e quanto pensar
thinking: {"budget_tokens": N} Removido — retorna 400 nos modelos atuais
output_config.effort low · medium · high · xhigh · max. Padrão: high
thinking.display Padrão "omitted" — blocos vêm vazios. "summarized" devolve o resumo
Prompt "pense passo a passo" Desnecessário e às vezes contraproducente

Como escolher o effort:

Nível Quando
low Classificação, extração, tarefa curta e sensível a latência
medium Passo abaixo do padrão para economizar em volume
high Padrão. Serve para a maioria
xhigh Código e trabalho agêntico difícil
max Só quando correção importa mais que custo

Dois pontos de atenção:

Regra Wayon Entregável analítico produzido por API sobre documento de cliente — análise de escopo, leitura de contrato, comparação de especificações — vai com citations habilitado, e as citações vão junto na entrega. Sem citação, a análise é opinião com aparência de estudo. Aplicação que usa prompt caching sobre documento de cliente monitora cache_read_input_tokens: cache que nunca acontece é custo silencioso que aparece na fatura antes de aparecer no relatório.

📖 Prompt caching · Citations · Adaptive thinking

Quiz — 4 questões

1.Uma aplicação com prompt caching mostra cache_read_input_tokens igual a zero em todas as chamadas, apesar de o system prompt ser "o mesmo". Qual é a causa mais provável?
  • a)Algo variável está dentro do prefixo — data, UUID, id de usuário ou JSON serializado sem ordenar

    Correto. O cache é casamento de prefixo por byte, e essas são as causas clássicas de invalidação silenciosa.

  • b)O cache_control foi colocado no bloco errado e a API ignorou a marcação

    Marcação em bloco não cacheável não zera a leitura em todas as chamadas — o sintoma aponta prefixo instável.

  • c)O TTL de 5 minutos expirou entre as chamadas

    Explicaria falhas ocasionais, não zero constante em toda chamada.

Ver resposta e por quê
a) Correto. O cache é casamento de prefixo por byte, e essas são as causas clássicas de invalidação silenciosa.
b) Marcação em bloco não cacheável não zera a leitura em todas as chamadas — o sintoma aponta prefixo instável.
c) Explicaria falhas ocasionais, não zero constante em toda chamada.
2.Você precisa entregar ao Meridiano uma análise em JSON estrito e com citações ancoradas nas FS. O que fazer?
  • a)Usar os dois recursos na mesma chamada — são independentes

    Não são: output_config.format com citations retorna 400.

  • b)Usar citations e converter a saída para JSON com regex depois

    Funciona por acidente e quebra em produção; há caminho melhor.

  • c)Não é possível na mesma chamada (retorna 400): garanta o formato por instrução e schema em outra etapa, ou abra mão de um dos dois

    Correto. A incompatibilidade é explícita na documentação.

Ver resposta e por quê
a) Não são: output_config.format com citations retorna 400.
b) Funciona por acidente e quebra em produção; há caminho melhor.
c) Correto. A incompatibilidade é explícita na documentação.
3.Um código herdado usa thinking: {"type": "enabled", "budget_tokens": 8000}. O que acontece nos modelos atuais?
  • a)Retorna erro 400 — o controle passou a ser output_config.effort com adaptive thinking

    Correto. É uma das mudanças que o material antigo não reflete.

  • b)Funciona, mas o parâmetro está depreciado e será removido no futuro

    Já foi removido nos modelos atuais — não é aviso de depreciação.

  • c)Funciona e o orçamento é convertido automaticamente para o nível de effort equivalente

    Não há conversão; a requisição é recusada.

Ver resposta e por quê
a) Correto. É uma das mudanças que o material antigo não reflete.
b) Já foi removido nos modelos atuais — não é aviso de depreciação.
c) Não há conversão; a requisição é recusada.
4.Uma interface que exibia o raciocínio do Claude passou a mostrar uma pausa longa e nenhum texto de raciocínio. Qual é a causa? ---
  • a)O effort está baixo demais e o modelo não está pensando

    Com effort baixo haveria menos raciocínio, mas não blocos sistematicamente vazios.

  • b)thinking.display está no padrão "omitted" — os blocos vêm vazios até você pedir "summarized"

    Correto. O padrão mudou em relação a modelos anteriores.

  • c)O raciocínio bruto deixou de existir e só o texto final é retornado

    O raciocínio acontece e é cobrado; o que muda é a visibilidade.

Ver resposta e por quê
a) Com effort baixo haveria menos raciocínio, mas não blocos sistematicamente vazios.
b) Correto. O padrão mudou em relação a modelos anteriores.
c) O raciocínio acontece e é cobrado; o que muda é a visibilidade.