Se você já sabe Python e quer que sua aplicação converse com um modelo de linguagem, o caminho recomendado não é montar requisições HTTP na mão: é usar o SDK oficial da Anthropic (`anthropic`), que já resolve autenticação, streaming, novas tentativas em caso de falha e tipagem das respostas. Este guia mostra como instalar, autenticar, fazer a primeira chamada, lidar com respostas longas via streaming, tratar erros de forma específica e estimar o custo de uma chamada antes de enviá-la.
Por que usar o SDK oficial em vez de HTTP puro
É possível chamar a API da Anthropic com `requests` ou `httpx` diretamente, mas o SDK oficial cobre, sem código extra, três coisas que todo tutorial de API de LLM precisa resolver: novas tentativas automáticas quando o servidor responde com erro temporário, um cliente de streaming que já acumula o texto para você e exceções tipadas (uma classe Python para cada tipo de erro) em vez de você precisar interpretar códigos HTTP manualmente. Use HTTP cru apenas se a linguagem do seu projeto não tiver SDK oficial.
Instalação e autenticação
Instale o pacote oficial e exponha sua chave de API como variável de ambiente — nunca a escreva direto no código-fonte:
pip install anthropic
export ANTHROPIC_API_KEY="sua-chave-aqui"Com a variável de ambiente definida, o cliente resolve a credencial sozinho:
import anthropic
# Resolve a credencial automaticamente a partir de ANTHROPIC_API_KEY
client = anthropic.Anthropic()
# Só passe a chave explicitamente se precisar injetar uma chave específica
# client = anthropic.Anthropic(api_key="sua-chave-aqui")Sua primeira chamada à API
O ponto de entrada é `client.messages.create()`. O parâmetro `model` recebe o identificador do modelo Claude que você quer usar — como os IDs de modelo mudam com o tempo, confira sempre a lista atual na documentação oficial antes de fixar um valor em produção.
response = client.messages.create(
model="claude-opus-5", # confira o ID de modelo vigente na documentação
max_tokens=1024,
messages=[
{"role": "user", "content": "Explique o que é uma API REST em uma frase."}
]
)
# response.content é uma LISTA de blocos (texto, uso de ferramenta, etc.)
# sempre confira o .type antes de acessar .text
for block in response.content:
if block.type == "text":
print(block.text)A resposta nunca é uma string simples: é uma lista de blocos de conteúdo. Esse é o erro mais comum de quem vem de outras APIs — tentar ler `response.text` direto e receber um `AttributeError`.
Streaming: evitando timeout em respostas longas
Pedir uma resposta longa (um relatório, um trecho de código extenso) sem streaming corre o risco de estourar o tempo limite da conexão antes que o modelo termine de gerar tudo. Streaming entrega o texto em pedaços conforme é gerado, o que resolve o problema de timeout e permite mostrar a resposta em tempo real na interface.
with client.messages.stream(
model="claude-opus-5",
max_tokens=4096,
messages=[{"role": "user", "content": "Escreva um resumo sobre streaming de APIs."}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
# Mesmo usando streaming, dá para pegar a mensagem completa no final
final_message = stream.get_final_message()
print(f"\n\nTokens de saída: {final_message.usage.output_tokens}")Tratando erros de forma específica
Um `except Exception` genérico esconde a diferença entre um erro que vale a pena tentar de novo (limite de requisições, instabilidade momentânea do servidor) e um erro que só vai se repetir até você corrigir a chamada (chave inválida, parâmetro errado). O SDK expõe uma exceção Python para cada categoria — encadeie do mais específico para o mais genérico:
import anthropic
try:
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Olá"}]
)
except anthropic.AuthenticationError:
print("Chave de API inválida, revogada ou expirada.")
except anthropic.RateLimitError as e:
retry_after = e.response.headers.get("retry-after", "60")
print(f"Limite de requisições atingido. Tente novamente em {retry_after}s.")
except anthropic.APIStatusError as e:
if e.status_code >= 500:
print(f"Erro no servidor ({e.status_code}). Pode tentar de novo.")
else:
print(f"Erro na requisição: {e.message}")
except anthropic.APIConnectionError:
print("Falha de rede ao tentar falar com a API.")- 400 (invalid_request_error) — algo no formato ou conteúdo da requisição está errado; corrija antes de tentar de novo.
- 401 (authentication_error) — chave de API ausente, malformada, revogada ou expirada.
- 429 (rate_limit_error) — você excedeu o limite de requisições; espere e tente novamente.
- 5xx / 529 (overloaded_error) — instabilidade temporária do lado do servidor; costuma valer a pena tentar de novo.
Novas tentativas automáticas (retry e backoff)
O SDK já tenta de novo, sozinho, erros de conexão, 408, 409, 429 e respostas 5xx, com espera crescente entre as tentativas — por padrão, duas tentativas extras. Isso significa que, se você configurar um timeout de 30 segundos, o tempo total de espera em caso de falha persistente pode chegar perto de `timeout × (max_retries + 1)`. Ajuste esse comportamento por cliente ou por chamada:
# Por cliente
client = anthropic.Anthropic(max_retries=5)
# Por chamada, sem alterar o cliente original
response = client.with_options(timeout=20.0, max_retries=5).messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Olá"}]
)Contando tokens antes de enviar (e estimando custo)
A cobrança é feita por token — de entrada e de saída — e cada modelo tem seu próprio preço por milhão de tokens, que muda com o tempo; consulte a página oficial de preços para os valores vigentes em vez de fixar um número em código ou neste texto. O que não muda é o mecanismo: dá para contar os tokens de uma mensagem antes de enviá-la, o que é útil para estimar custo ou verificar se o conteúdo cabe no limite de contexto do modelo.
count = client.messages.count_tokens(
model="claude-opus-5",
messages=[{"role": "user", "content": "Texto que você quer medir antes de enviar."}]
)
print(f"Tokens de entrada estimados: {count.input_tokens}")Depois da chamada, o custo real de entrada e saída fica disponível em `response.usage.input_tokens` e `response.usage.output_tokens` — vale logar os dois para acompanhar gasto ao longo do tempo.
Onde isso costuma quebrar
- Tratar `response.content` como texto direto em vez de percorrer a lista de blocos e checar `.type`.
- Ignorar `stop_reason`: se vier `"max_tokens"`, a resposta foi cortada no meio — o `max_tokens` da chamada precisa subir, ou é preciso continuar a geração.
- Reenviar só a última mensagem em uma conversa: a API é stateless, então cada chamada precisa levar o histórico completo da conversa em `messages`.
- Fazer uma chamada sem streaming pedindo uma resposta longa e tomar timeout perto dos 10 minutos de limite padrão do cliente.
- Capturar só `Exception` genérica e perder a diferença entre erro temporário (vale re-tentar) e erro de configuração (não adianta re-tentar sem corrigir).
Próximos passos
Com a chamada básica, o streaming e o tratamento de erro no lugar, os próximos ganhos práticos vêm de entender como o texto é convertido em tokens e por que isso limita quanto contexto cabe em uma conversa — veja [Tokens e janela de contexto em LLMs: o guia completo](/artigo/tokens-janela-de-contexto-llm) — e de dar a esse código a capacidade de chamar funções externas durante a conversa, o próximo passo natural depois de dominar chamadas simples, coberto em [O que é MCP (Model Context Protocol)? Guia completo](/artigo/o-que-e-mcp-model-context-protocol-guia-completo).
Este guia usa a API da Anthropic (Claude) como exemplo, mas o padrão — autenticar por variável de ambiente, tratar erros por tipo, usar streaming em respostas longas e contar tokens antes de enviar — se repete em praticamente qualquer SDK de LLM.
Perguntas frequentes
Sim, a API é paga por uso: você é cobrado por tokens de entrada e de saída, com preço por milhão de tokens que varia conforme o modelo escolhido. Consulte a página oficial de preços da Anthropic para os valores vigentes, já que eles mudam ao longo do tempo.