Pular para o conteúdo principal

Tutorial da API Claude Fable 5.1: construa um agente de desenvolvedor de longa execução em Python

Aprenda a usar o mais novo modelo da Anthropic para criar um agente em Python que lê um repositório Flask antes de planejar uma mudança. Adicione atualizações de progresso, ferramentas de arquivo somente leitura e controles de custo.
Atualizado 3 de set. de 2026  · 15 min lido

Explorar com IA

ChatGPTClaudePerplexity

Quando testo um novo modelo via chamada de API, a primeira resposta quase não diz nada. Meu primeiro teste com o Fable 5.1 trouxe uma estrutura válida e um plano genérico. Eu queria saber o que acontece quando a conversa cresce: a aplicação consegue manter o histórico intacto, inspecionar arquivos sem ler fora do projeto, relatar o progresso e mostrar de onde veio o custo?

Nosso panorama do Claude Fable 5.1 cobre o lançamento, os benchmarks e comparações mais amplas entre modelos. Aqui, vamos começar com uma pequena chamada em Python e construir o loop do agente ao redor dela. O agente final recebe um pedido de funcionalidade, lê um projeto Flask e retorna um plano atrelado aos arquivos que ele de fato inspecionou.

Vamos ver como:

  • Fazer uma chamada à API do Claude Fable 5.1 e ler blocos de conteúdo com segurança
  • Definir o esforço de raciocínio e alterá-lo no meio da conversa (beta)
  • Restringir uma instrução de sistema a um único turno (beta)
  • Devolver um plano estruturado com Pydantic
  • Adicionar ferramentas de repositório somente leitura com limite na raiz do projeto
  • Rodar um loop de ferramentas em vários turnos
  • Ler as atualizações de progresso do agente entre chamadas de ferramenta (beta)
  • Manter válidos os blocos de thinking com histórico apenas-anexar
  • Fazer cache de contexto repetido e estimar o custo do pedido nas tarifas publicadas
  • Lidar com recusas e expor o agente via FastAPI

Os recursos em beta usam headers com data; confira na documentação da Anthropic antes de publicar.

Introdução aos Modelos Claude

Aprenda a trabalhar com o Claude usando a API da Anthropic para resolver tarefas do mundo real e criar aplicativos com inteligência artificial.
Explore O Curso

Quanto custa rodar o Claude Fable 5.1 em um agent loop?

Um agente reenvia o mesmo prompt de sistema, definições de ferramentas e contexto do repositório a cada turno, então a tarifa que pesa na sua conta é a de leitura de cache, não a tarifa de entrada.

O Fable 5.1 custa US$ 10 por milhão de tokens de entrada e US$ 50 por milhão de tokens de saída, igual ao Fable 5. Leituras de cache custam US$ 0,25 por milhão (antes era US$ 1) e escritas de cache de cinco minutos seguem em US$ 12,50 por milhão. Nosso guia do Claude Fable 5.1 traz a tabela completa e as estimativas de economia da Anthropic.

Ler um prefixo em cache é barato. Escrever não é, custa 50 vezes a leitura, então o loop só compensa quando um prefixo é relido várias vezes. Mais adiante, o detalhamento de custos mostra como isso apareceu em uma execução real e qual categoria realmente dominou.

O limite de tokens vem do modelo, não do seu orçamento. O Fable 5.1 oferece uma janela de contexto de 1M tokens com até 128K tokens de saída por resposta, e max_tokens é um limite rígido para thinking mais texto de resposta juntos. Em esforço alto, você precisa de espaço para ambos — por isso o loop abaixo define 16.000 em vez de algo mais "redondo".

Retenção de dados, Priority Tier e marca d'água

Alguns detalhes de acesso importam antes de escrever código. Dois deles barram a requisição na hora:

  • O Fable 5.1 exige retenção de dados por 30 dias e não está disponível com retenção zero, a menos que a Anthropic autorize. Uma requisição de um workspace incompatível retorna 400 invalid_request_error sem outra pista.

  • O modelo não é compatível com Priority Tier. O Fable 5 é, o que pega muita gente na migração.

  • A saída de texto do Fable 5.1 traz a marca d'água de texto da Anthropic. Não adiciona tokens nem exige mudanças no pedido.

Use o Claude Fable 5.1 via API para criar um agente de desenvolvedor ciente do repositório

Nosso fluxo tem duas etapas:

  1. Um loop de inspeção com limites lê arquivos permitidos do projeto.
  2. Uma requisição final usando saídas estruturadas transforma esse contexto em um plano.

O projeto de exemplo é uma pequena API JSON em Flask para salvar e buscar favoritos, com uma factory da app, três blueprints, um módulo de config, models e uma suíte de pytest. Usei rate limiting como tarefa guia porque o agente precisa inspecionar a configuração da app, rotas, config e testes antes de identificar os arquivos e testes necessários. O código completo e o projeto de exemplo estão no repositório no GitHub.

Diagrama de um pedido de funcionalidade passando por um agente Claude Fable 5.1, uma allowlist de caminhos e um projeto de exemplo antes de retornar um plano estruturado

As requisições chegam aos arquivos por um único limite. Imagem do autor.

O agente pode usar só três ferramentas: list_project_files, read_project_file e get_project_metadata. O Claude nunca acessa o filesystem diretamente. Ele pede um caminho e seu código decide se é permitido.

Configurando a API do Claude Fable 5.1 em Python

Comece com um ambiente Python separado e mantenha a chave da API no servidor.

Pré-requisitos

Você precisa de Python 3.10 ou superior e uma chave da API da Anthropic com acesso a claude-fable-5-1.

Para criar uma chave de API, acesse o Claude Console, abra a página de chaves, clique em Create key e copie a chave. Boas práticas: dê um nome que indique o uso, defina uma data de expiração e armazene a chave com segurança.

Instale o SDK e adicione a chave da API

Crie um ambiente virtual e instale os pacotes:

python -m venv .venv
source .venv/bin/activate          # macOS ou Linux
.venv\Scripts\Activate.ps1         # Windows PowerShell
pip install anthropic==1.3.0 pydantic fastapi uvicorn python-dotenv

Mantenha o SDK fixado porque recursos beta mudam com frequência. As atualizações de progresso exigem pelo menos 1.1.0, e os exemplos usam 1.3.0.

Coloque a chave em um .env file e adicione .env ao .gitignore antes do primeiro commit. Ela deve ficar em um servidor sob seu controle, nunca no navegador ou em repositório acessível. Expor a chave pode permitir uso não autorizado da API e cobranças em entrada, saída e cache.

ANTHROPIC_API_KEY=sk-ant-your-key-here

Com isso, o client encontra a chave automaticamente.

Faça sua primeira chamada à API do Claude Fable 5.1 em Python

Envie o menor pedido de API possível antes de construir algo em cima dele.

Envie a primeira requisição

Inicialize o client, envie uma mensagem do usuário e imprima os metadados da resposta:

from anthropic import Anthropic
from dotenv import load_dotenv

load_dotenv()

client = Anthropic()
MODEL = "claude-fable-5-1"

response = client.messages.create(
    model=MODEL,
    max_tokens=512,
    messages=[{"role": "user", "content": "Reply in one sentence to confirm the API connection is working."}],
)

text = next((b.text for b in response.content if b.type == "text"), None)
print(text if text is not None else f"No text returned ({response.stop_reason})")
print(f"Model: {response.model}")
print(f"Stop reason: {response.stop_reason}")
print(f"Input tokens: {response.usage.input_tokens}")
print(f"Output tokens: {response.usage.output_tokens}")
print(f"Request ID: {response._request_id}")

Terminal exibindo uma resposta da API do Claude Fable 5.1 com ID do modelo, motivo de parada, contagem de tokens e ID da requisição

A primeira chamada retorna texto e metadados. Imagem do autor.

A chamada next(...) seleciona o primeiro bloco de texto. O thinking adaptativo está sempre ligado e não pode ser desativado, então a resposta pode começar com um bloco de thinking; enviar thinking: {"type": "disabled"} retorna 400 em vez de desligar. Quando o primeiro bloco é de thinking, response.content[0].text gera exceção.

A solução é filtrar por tipo de bloco, em vez de assumir posição fixa. Registre também response._request_id, já que o suporte da Anthropic usa para rastrear a requisição.

Aqui está o pedido usado nos exemplos de planejamento e esforço. Ele exige que o agente inspecione vários arquivos:

feature_request = (
    "Add rate limiting to the public API endpoints so one client cannot exhaust "
    "the search endpoint or brute force the token endpoint."
)

Mantenha esse texto igual ao comparar níveis de esforço e contagem de tokens. Assim, os resultados refletem as configurações da API, não um prompt diferente.

Defina o esforço de raciocínio com output_config

Defina o esforço via output_config. Aceita low, medium, high, xhigh e max. O padrão da API é high.

response = client.messages.create(
    model=MODEL,
    max_tokens=8192,
    output_config={"effort": "high"},
    messages=[{"role": "user", "content": feature_request}],
)

O esforço pode afetar uso de tokens, comportamento de ferramentas e latência. Rodei o mesmo pedido três vezes em quatro níveis de esforço; a tabela mostra as médias:

Esforço

Segundos

Tokens de thinking

Tokens totais de saída

Custo

low

7,7

111

173

US$ 0,0093

medium

8,1

129

186

US$ 0,0099

high

7,9

136

199

US$ 0,0106

xhigh

20,0

151

1.764

US$ 0,0888

Os tokens de thinking já estão incluídos no total de saída — não some as colunas. Nessas execuções, low, medium e high ficaram próximos em latência e custo.

xhigh levou duas vezes e meia mais tempo, gerou quase nove vezes os tokens de saída e custou oito vezes mais.

Conclusão: comece com high, baixe para medium em passos rotineiros e suba só quando seus testes mostrarem ganho mensurável. Em low o modelo pode responder de memória em vez de chamar uma ferramenta de busca. Se o turno precisa de informação nova, diga isso ou eleve o nível.

Restrinja o escopo do agente com um prompt de sistema

O prompt de sistema define o comportamento do agente:

SYSTEM_PROMPT = """You are a senior engineer who turns feature requests into implementation plans for an existing codebase.

Stay inside the requested feature. Do not propose unrelated refactors, dependency upgrades, or style changes.

If a file or dependency you need does not exist, say so plainly instead of inventing it.

Write in plain sentences and do not use em dashes.

Finish with concrete guidance: what changes, where, in what order, what could break, and which tests to add."""

A orientação de prompts da Anthropic aponta que o modelo pode expandir demais a tarefa ou parar cedo. O prompt manda manter o foco e terminar com orientação concreta. Um schema cuida do formato da saída depois.

Retorne um plano estruturado com Pydantic

Defina o plano com Pydantic para sua aplicação validar e repassar a outros componentes:

from pydantic import BaseModel, Field

class FeaturePlan(BaseModel):
    summary: str = Field(description="One or two sentences on what will be built.")
    implementation_steps: list[str]
    files_to_modify: list[str]
    risks: list[str]
    tests: list[str]

response = client.messages.parse(
    model=MODEL,
    max_tokens=8192,
    system=SYSTEM_PROMPT,
    messages=[{"role": "user", "content": feature_request}],
    output_format=FeaturePlan,
)

if response.stop_reason == "refusal":
    category = (
        response.stop_details.category
        if response.stop_details and response.stop_details.category
        else "unspecified"
    )
    print(f"Declined: {category}")
elif response.parsed_output is None:
    print(f"No plan. Stop reason: {response.stop_reason}")
else:
    print(response.parsed_output.summary)

messages.parse() converte o modelo Pydantic em um schema JSON, envia, valida a resposta e retorna um objeto tipado em parsed_output. Saídas estruturadas estão geralmente disponíveis, então não há header beta aqui. Confira stop_reason primeiro, pois uma recusa (ver adiante) ignora o schema e não há o que parsear.

Aquele resultado genérico da introdução teve um mérito: não citou arquivos que não pôde ver. Um schema valida estrutura, não fundamentação factual.

Claude Fable 5.1 vs. Fable 5: mudanças de migração na API

Antes de adicionar ferramentas, considere as restrições de ferramenta forçada, compatibilidade de blocos de thinking e histórico apenas-anexar.

  • O Fable 5.1 rejeita seleção forçada de ferramentas. A seção do loop de ferramentas abaixo mostra o erro e a configuração auto usada no lugar.

  • Blocos de thinking são compatíveis em um só sentido. O Fable 5.1 lê blocos de modelos Claude anteriores, mas nenhum modelo anterior lê seus blocos.

Quando um roteador ou fallback move a conversa para um modelo mais antigo, a API remove os blocos incompatíveis antes do modelo alvo vê-los. O restante do histórico fica, mas o modelo antigo precisa planejar sem esses blocos.

Editar turnos anteriores invalida os blocos de thinking posteriores. Isso pode quebrar corte de histórico e sumarização no cliente.

O guia de migração traz todas as mudanças.

Adicione ferramentas de repositório somente leitura

Agora dê ao modelo contexto do repositório via ferramentas somente leitura.

Defina as ferramentas somente leitura

A camada de ferramentas tem duas partes: as funções Python que impõem regras de acesso e os schemas que o Claude pode chamar.

Restrinja caminhos à raiz do projeto

Somente leitura não é sinônimo de seguro. Um modelo pode pedir ../../.env tão fácil quanto config.py, então o bloqueio deve estar no seu código, não no prompt:

def _resolve(self, relative_path: str) -> Path:
    relative = Path(relative_path)
    if relative.is_absolute() or relative.drive:
        raise ToolError(f"path is outside the project root: {relative_path}")

    cursor = self.root
    for part in relative.parts:
        cursor /= part
        if cursor.is_symlink():
            raise ToolError(f"symlinks are not followed: {relative_path}")

    candidate = (self.root / relative).resolve()

    # After resolving "..", the path still has to sit under the allowed root.
    if candidate != self.root and self.root not in candidate.parents:
        raise ToolError(f"path is outside the project root: {relative_path}")
    if candidate.name in DENY_NAMES:
        raise ToolError(f"reading {candidate.name} is not allowed")

    return candidate

Rejeite caminhos absolutos e componentes symlink, depois resolva o caminho e confirme que segue sob a raiz do projeto. Pedir ../.env retorna "path is outside the project root". O erro de ferramenta retornado permite o agente continuar com arquivos permitidos.

Defina schemas de ferramenta estritos

A classe leitora controla o que o Python pode abrir. O Claude também precisa de schemas JSON descrevendo as três ações que pode pedir:

EMPTY_SCHEMA = {
    "type": "object",
    "properties": {},
    "additionalProperties": False,
}

TOOLS = [
    {
        "name": "list_project_files",
        "description": "List readable text files in the project.",
        "input_schema": EMPTY_SCHEMA,
        "strict": True,
    },
    {
        "name": "read_project_file",
        "description": "Read one text file relative to the project root.",
        "input_schema": {
            "type": "object",
            "properties": {"path": {"type": "string"}},
            "required": ["path"],
            "additionalProperties": False,
        },
        "strict": True,
    },
    {
        "name": "get_project_metadata",
        "description": "Read project metadata and dependency manifests.",
        "input_schema": EMPTY_SCHEMA,
        "strict": True,
    },
]

strict verifica os argumentos quando o modelo escolhe uma ferramenta. Não força a chamada — o que importa no Fable 5.1.

Rode o loop de ferramentas em vários turnos

Comece com o loop base: envie as ferramentas, verifique stop_reason, rode o que foi pedido, anexe os resultados e repita.

MAX_AGENT_TURNS = 8
reader = ProjectReader("sample_project")
messages = [{"role": "user", "content": feature_request}]

for turn in range(1, MAX_AGENT_TURNS + 1):
    response = client.messages.create(
        model=MODEL,
        max_tokens=16000,
        system=SYSTEM_PROMPT,
        tools=TOOLS,
        messages=messages,
    )

    if response.stop_reason == "refusal":
        return declined(response.stop_details.category)
    if response.stop_reason == "max_tokens":
        return cutoff()
    if response.stop_reason != "tool_use":
        messages.append({"role": "assistant", "content": response.content})
        break

    messages.append({"role": "assistant", "content": response.content})
    results = []
    for block in response.content:
        if block.type != "tool_use":
            continue
        output, is_error = reader.run(block.name, block.input)
        results.append({
            "type": "tool_result",
            "tool_use_id": block.id,
            "content": output,
            "is_error": is_error,
        })

    messages.append({"role": "user", "content": results})
else:
    return turn_limit()

MAX_AGENT_TURNS limita pedidos do modelo, não gastos; se preciso, imponha um limite de custo separado. O loop trata refusal, max_tokens e tool_use diretamente; outros motivos encerram a inspeção. O campo is_error avisa ao modelo que um caminho foi negado, para ele escolher outra ação.

Por que forçar a ferramenta retorna 400

No Fable 5, você podia forçar a primeira chamada com tool_choice: {"type": "any"}. O Fable 5.1 retorna este erro antes de executar:

tool_choice: type "tool" and "any" are not supported for this model.

Chamadas forçadas pulariam o thinking sempre ligado. Deixe tool_choice em auto, use schemas estritos e cite as ferramentas no prompt quando um passo precisar delas.

O Fable 5.1 às vezes faz uma chamada de ferramenta por turno, enquanto o Fable 5 agrupava várias. Isso adiciona idas e vindas. Inclua no prompt: “Solicite arquivos independentes no mesmo turno em vez de um por turno.” Em um teste, nove arquivos independentes foram agrupados, mas a contagem varia.

Transmita respostas e atualizações de progresso do Claude Fable 5.1

O streaming de texto emite conteúdo conforme é gerado; as atualizações de progresso cobrem as pausas entre chamadas de ferramenta.

Transmita respostas de texto

O projeto completo usa context_system() para combinar o SYSTEM_PROMPT a um resumo do projeto antes de iniciar o stream:

with client.messages.stream(
    model=MODEL,
    max_tokens=8192,
    system=context_system(),
    messages=[{"role": "user", "content": feature_request}],
) as stream:
    for chunk in stream.text_stream:
        print(chunk, end="", flush=True)
    final = stream.get_final_message()

print(f"\nOutput tokens: {final.usage.output_tokens}")

get_final_message() traz a mensagem montada com uso e motivo de parada quando o stream termina. Chunks não garantem JSON completo — espere a mensagem final para fazer o parse.

Mostre progresso entre chamadas de ferramenta

O streaming de texto não cobre atrasos durante as chamadas de ferramenta. O Fable 5.1 pode escrever pequenas atualizações de progresso antes das chamadas. No padrão de thinking.display como "omitted", os blocos de thinking específicos de progresso ficam vazios, embora o modelo possa produzir um texto de abertura normal.

Com display: "updates" e o header beta thinking-display-updates-2026-08-18 , a documentação da API define uma atualização legível como um bloco thinking não vazio enquanto o raciocínio fica oculto. Nas execuções deste projeto, o campo thinking ficou vazio e o status legível veio como um bloco text imediatamente antes de tool_use. O helper, portanto, verifica ambos tipos, e o loop só chama quando o turno termina em tool_use:

PROGRESS_BETA = "thinking-display-updates-2026-08-18"

response = client.beta.messages.create(
    model=MODEL,
    max_tokens=16000,
    betas=[PROGRESS_BETA],
    thinking={"type": "adaptive", "display": "updates"},
    system=SYSTEM_PROMPT,
    tools=TOOLS,
    messages=messages,
)

def status_lines(response) -> list[str]:
    lines = []
    for block in response.content:
        if block.type == "thinking":
            text = (block.thinking or "").strip()
        elif block.type == "text":
            text = (block.text or "").strip()
        else:
            continue
        if text:
            lines.append(text)
    return lines

As mensagens de progresso descrevem os arquivos que o modelo planeja ler: "Vou ler o wiring da app, config, extensions, rotas públicas e de auth, e os testes existentes, que são onde o rate limiting se encaixa." Mostre essas mensagens e ignore blocos vazios.

Terminal mostrando um loop de agente Claude Fable 5.1 com uso de tokens por turno, mensagens de progresso e leituras de arquivo em lote

O agente lê arquivos enquanto reporta progresso. Imagem do autor.

O Fable 5.1 escreve menos dessas mensagens que o Fable 5, especialmente em esforço alto. Se sua interface precisa de atualizações frequentes, peça uma linha de abertura, mensagens de progresso e um recap de encerramento.

Altere o esforço do Claude Fable 5.1 no meio da conversa

O próximo recurso é bem legal. Como sabemos, o agente de repositório não precisa do mesmo nível de raciocínio em todo turno.

Altere o esforço entre turnos

Em um agent loop, reduza o esforço em turnos de recuperação rotineira e suba de novo no turno final de planejamento.

Com o header beta mid-conversation-output-config-2026-07-01 você pode anexar uma mensagem de sistema que só muda o nível de esforço:

EFFORT_BETA = "mid-conversation-output-config-2026-07-01"

messages.append({"role": "system", "content": [], "output_config": {"effort": "low"}})
messages.append({"role": "user", "content": "Summarize the repository evidence in five words."})

response = client.beta.messages.create(
    model=MODEL,
    max_tokens=4096,
    betas=[EFFORT_BETA],
    output_config={"effort": "high"},
    messages=messages,
)

O novo nível vale a partir do próximo turno do usuário, não no meio do turno atual, e não invalida o cache do prompt. Alterar o output_config.effort de nível superior entre requisições invalida.

O agente mantém a configuração de topo em high, anexa uma diretiva por mensagem medium antes da recuperação rotineira e anexa high antes do plano final. Um teste pareado usou 18 tokens de saída com esforço menor versus 76 no ajuste anterior. Trate como exemplo, não como redução garantida.

Aplique uma instrução de sistema a um turno

Use uma instrução com escopo de turno para bloquear novas leituras de arquivo durante o planejamento final.

Defina clear_at: "next_user_message" em uma mensagem de sistema com o header beta mid-conversation-system-clear-at-2026-08-21 . A API trata o texto como instrução de sistema para o turno atual e para de renderizá-lo após a próxima mensagem do usuário. Ele permanece em messages, então o histórico anterior não muda, o cache segue batendo e a mensagem "limpa" não custa tokens de entrada.

SCOPED_SYSTEM_BETA = "mid-conversation-system-clear-at-2026-08-21"

messages.append({"role": "system", "content": [], "output_config": {"effort": "high"}})
messages.append({"role": "user", "content": "Write the implementation plan now."})
messages.append({
    "role": "system",
    "content": (
        "For this turn only: do not request more files. Base the plan on what "
        "you have already read, and name only paths you actually opened."
    ),
    "clear_at": "next_user_message",
})

response = client.beta.messages.create(
    model=MODEL,
    max_tokens=16000,
    betas=[EFFORT_BETA, SCOPED_SYSTEM_BETA],
    tool_choice={"type": "none"},
    output_config={"format": {"type": "json_schema", "schema": plan_schema()}},
    system=agent_system(),
    tools=TOOLS,
    messages=messages,
)

tool_choice={"type": "none"} impede que a requisição final chame outra ferramenta. A instrução com escopo limita o plano a arquivos já inspecionados. Não adicione lembrete e o apague no pedido seguinte — essa edição invalida blocos de thinking posteriores.

Corrija erros 400 de thinking blocks no Claude Fable 5.1

Um erro The block is bound to a different conversation significa que o histórico antes de um bloco de thinking foi alterado. Todo bloco de thinking do Fable 5.1 é atrelado exatamente ao prompt de sistema, definições de ferramentas e mensagens anteriores.

O resultado depende de quando sua conta foi criada.

  • Contas criadas em ou após 31 de agosto de 2026 recebem 400 dizendo que o bloco está vinculado a outra conversa.

  • Para contas anteriores, a API registra o desencontro, mas só age quando o pedido define thinking.block_binding.prefix_mismatch_behavior.

Você pode detectar isso com o header beta thinking-binding-controls-2026-08-01, thinking.block_binding.prefix_mismatch_behavior como "drop_block" e o array input_transformations. Um histórico editado aparece como reason: "prefix_binding_mismatch". Rode essa checagem uma vez na sua integração.

As operações abaixo disparam o desencontro:

  • Editar, reordenar ou remover um turno anterior mantendo os posteriores

  • Injetar texto por requisição em um turno anterior e removê-lo na próxima

  • Mudar o conteúdo ou a ordem do system de topo ou do array de tools no meio da conversa

  • Servir bytes diferentes de uma URL de imagem ou documento em uma requisição posterior

Cada caso tem um substituto que mantém os vínculos:

  • Adicione instruções com mensagens de sistema no meio da conversa, em vez de editar system.

  • Altere ferramentas com mudanças mid-conversation em vez de trocar o array de topo.

  • Resuma histórico com edição de contexto/compaction no servidor, que não contam como edição.

  • Passe os blocos de thinking de volta sem alterações.

Mover marcadores de cache_control e mudar esforço no nível da requisição são seguros e não invalidam vínculos de thinking. No entanto, mudar o esforço de topo reinicia o cache de prompt — use esforço por mensagem quando o prefixo em cache deve permanecer.

Cache de prompt e custo da API Claude Fable 5.1

A execução abaixo separa custos de entrada nova, escrita de cache, leitura de cache e saída.

Adicione cache de prompt automático

O cache de prompt reduz o custo de contexto que se repete entre turnos. Com o histórico crescendo, o ponto de corte muda, então o cache automático encaixa melhor aqui.

Um campo cache_control de topo move o ponto até o bloco mais recente cacheável a cada pedido:

response = client.beta.messages.create(
    model=MODEL,
    cache_control={"type": "ephemeral"},
    system=system,
    tools=TOOLS,
    messages=messages,
    # Other request fields...
)

Um prefixo cacheável menor que 512 tokens não é cacheado no Fable 5.1, mesmo marcado com cache_control. A API processa normalmente e retorna zero nos contadores de cache. Escrever um prefixo de 583 tokens custou US$ 0,0073; lê-lo no turno seguinte custou US$ 0,00015. O segundo turno ainda precisou escrever sua parte nova no cache, então um hit de cache não elimina todo custo de entrada.

Estime o custo da API com cache

response.usage reporta entrada nova, criação de cache, leituras de cache e saída separadamente. Precifique os quatro contadores; somar só entrada e saída esconde escrita de cache e superestima o preço dos hits.

Aqui está o detalhamento de uma execução que leu 12 arquivos em três turnos e produziu um plano final:

Item

Tokens

Custo estimado

Participação

Saída

5.713

US$ 0,2857

59,4%

Escritas de cache

15.426

US$ 0,1928

40,1%

Entrada nova

50

US$ 0,0005

0,1%

Leituras de cache

6.549

US$ 0,0016

0,3%

Total

27.738

US$ 0,4806

100%

Leituras de cache representaram menos de meio por cento desta estimativa. Na tarifa antiga do Fable 5, a execução teria custado cerca de US$ 0,4855 em vez de US$ 0,4806. A economia cresce quando cada turno reutiliza muito mais contexto.

Nesta execução, a saída gerou quase 60% do custo e as escritas de cache ~40%. Na janela de cinco minutos usada aqui, um token de escrita custa 50× um token de leitura. Em uma hora, 80×.

Lide com recusas e fallbacks do Claude Fable 5.1

Uma recusa e uma falha de requisição exigem comportamentos diferentes na aplicação.

Detecte recusas antes de parsear a saída

Uma recusa antes da saída chega como HTTP 200 com stop_reason: "refusal", conteúdo vazio e stop_details. A categoria pode ser nula. Uma recusa no meio de um stream pode seguir uma saída parcial, que a aplicação deve descartar. Um try/except não pega nenhum dos casos.

response = client.messages.create(model=MODEL, max_tokens=8192, messages=messages)

if response.stop_reason == "refusal":
    category = (
        response.stop_details.category
        if response.stop_details and response.stop_details.category
        else "unspecified"
    )
    return f"This request was declined ({category})."

Trate como estado da aplicação. Se um pedido permitido estiver confuso, reescreva com mais precisão. Não crie lógica de retry para contornar o classificador.

Uma recusa chega como HTTP 200. Imagem do autor.

Configure fallback no servidor

O fallback no servidor pode tentar um pedido recusado em outro modelo, usando fallbacks: "default" com o header beta server-side-fallback-2026-07-01 . Os alvos permitidos para o Fable 5.1 são Opus 4.8 e Opus 5.

O fallback padrão roda só quando a categoria da recusa tem um alvo recomendado. Uma recusa testada de reasoning_extraction não acionou fallback; inspecione usage.iterations em vez de assumir que toda recusa terá retry. Como dito, mover para um modelo mais antigo também derruba os thinking blocks do Fable 5.1.

Sirva o agente Claude Fable 5.1 com FastAPI

O agente local agora pode expor o mesmo fluxo via HTTP API.

Crie o endpoint de plano

Se você só precisa de um script local, pode pular. Para um serviço web, use FastAPI com AsyncAnthropic. Crie um client por processo num lifespan handler. Importe schema e prompts do módulo do agente existente.

@asynccontextmanager
async def lifespan(_: FastAPI):
    global client
    client = AsyncAnthropic()
    try:
        yield
    finally:
        await client.close()


@app.post("/plan", response_model=PlanResponse)
async def create_plan(body: PlanRequest):
    reader = resolve_project(body.project)
    messages, totals, turns, tool_calls = await inspect(reader, body.feature_request)
    plan, final_usage = await write_plan(messages)
    totals.add(final_usage)
    return PlanResponse(plan=plan, turns=turns, tool_calls=tool_calls, usage=as_usage(totals))

Repare que quem chama envia o nome do projeto, não o caminho. resolve_project() mapeia para um pequeno conjunto de raízes permitidas, impedindo que a requisição leia qualquer lugar do servidor. Este serviço mapeia recusas para 422 por escolha de aplicação. A API do Claude retorna HTTP 200.

Rode com uvicorn app:app --reload. A documentação interativa fica em http://localhost:8000/docs.

O endpoint retorna um plano com custo estimado. Vídeo do autor.

O endpoint /plan/stream roda a inspeção em tarefa de background, coloca eventos de progresso e de ferramentas em uma asyncio.Queue e os emite via StreamingResponse. Quando o stream fecha, o gerador cancela a tarefa. A interface Streamlit no repositório renderiza o mesmo fluxo de eventos.

O Streamlit mostra o progresso ao vivo do agente. Vídeo do autor.

Checklist de deployment do agente Claude Fable 5.1

Os limites e checagens que criamos permanecem no serviço. Antes do deploy, adicione peças operacionais que não aparecem em execução local.

  • Revise os dois retries padrão do SDK para 429 e 5xx, depois ajuste max_retries e timeouts ao orçamento de latência do serviço

  • Defina timeout de requisição e confirme que o cancelamento da tarefa SSE existente interrompe o trabalho ao desconectar o cliente

  • Logue ID do modelo, versão do SDK, ID da requisição, motivo de parada e as quatro categorias de tokens por execução

  • Gere alertas para alta em escritas de cache, tokens de saída, recusas e execuções que batem no limite de turnos

  • Confirme que a retenção da conta combina com a exigência do modelo

  • Fixa o SDK e revise os headers beta antes de cada release

Quando usar o Claude Fable 5.1 em vez de Opus 5 ou Sonnet 5

  • A Anthropic recomenda o Opus 5 como bom padrão.
  • Teste o Fable 5.1 quando o Opus 5 ficar atrás em análise de repositórios longos, depuração difícil ou tarefas agentic com contexto grande.
  • Para trabalho em repositório e tarefas do dia a dia, compare Sonnet 5 e Opus 5 em qualidade, latência e custo.
  • Para classificação, extração, respostas curtas e pedidos simples, o Sonnet 5 é um bom padrão; para as tarefas mais fáceis, o Haiku 4.5 pode ser suficiente.

Não escolha o Fable 5.1 só por ser mais novo. Uma única requisição ainda pode usar esforço e saídas estruturadas; streaming também funciona. Ela não se beneficia do loop ou do cache de prefixo repetido de que falamos aqui.

Considerações finais

O plano genérico da primeira chamada só ficou útil depois que o agente leu o repositório. Na execução completa, ele inspecionou 12 arquivos em três turnos, enquanto saída e escritas de cache responderam por 99,5% do custo estimado. Eu manteria o limite de caminhos e o histórico apenas-anexar, e testaria se reduzir o esforço diminui o custo sem fazer o modelo pular ferramentas do repositório.

Se uma resposta dá conta da tarefa, pare em saídas estruturadas. Use o loop de ferramentas quando a resposta precisar depender de arquivos do repositório ou informar progresso entre chamadas.

Para detalhes sobre seleção de modelos, recomendo nosso curso Introduction to Claude Models. Para prompting e fluxos com agentes, veja nosso curso Software Development with Cursor.

FAQs

O Claude Fable 5.1 lê imagens além de código?

Sim. Ele aceita imagens e consegue ler gráficos e PDFs. Eu deixei visão de fora do exemplo principal porque o plano do repositório não precisa disso. Se eu fosse estender este agente para planejar uma mudança de UI, enviaria o screenshot atual com o pedido de funcionalidade. Reduza a imagem antes se detalhes visuais pequenos não afetarem a tarefa.

Por que meu agente ficou mais lento após migrar do Fable 5?

Confira os resultados das ferramentas antes de culpar o modelo. Se a instrução de agrupamento já estiver no prompt, compare o número e o tamanho dos arquivos. O leitor atual limita cada arquivo a 40.000 bytes. Se ainda for grande demais, adicione argumentos de faixa de linhas ou busca para a ferramenta retornar só trechos relevantes.

Por que o Claude Fable 5.1 retorna 400 invalid_request_error?

Não dê retry logo de cara. Um invalid_request_error geralmente indica formato do pedido ou configuração da conta que precisa mudar. Neste projeto, as causas mais prováveis são tool_choice forçado, retenção incompatível, prefixo editado mantendo thinking ou campo beta enviado sem o header correspondente. Corrija a causa indicada e envie de novo.

Devo fazer cache dos arquivos-fonte ou de um resumo?

Eu uso esta regra: faça cache dos arquivos-fonte quando o código exato importa em vários turnos. Se etapas posteriores precisarem só da arquitetura ou do mapa de arquivos, faça cache de um resumo. O resumo custa menos tokens, mas pode omitir a linha que o plano final precisa.

A Batch API consegue rodar este agente?

Não por si só. A Batch API envia requisições individuais de Messages; ela não roda este loop de ferramentas no cliente. Eu a usaria para revisões autônomas de repositório quando progresso ao vivo não for necessário. Para rodar o loop completo em lotes, você precisa de código seu processando as ferramentas de um lote antes de enviar o próximo.


Khalid Abdelaty's photo
Author
Khalid Abdelaty
LinkedIn

Sou engenheiro de dados e criador de comunidades que trabalha com pipelines de dados, nuvem e ferramentas de IA, além de escrever tutoriais práticos e de alto impacto para o DataCamp e desenvolvedores iniciantes.

Tópicos

Aprenda IA com a DataCamp!

Programa

Associate AI Engineer para desenvolvedores

26 h
Aprenda a integrar IA em aplicações de software usando APIs e bibliotecas de código aberto. Comece hoje sua jornada para se tornar um AI Engineer!
Ver detalhesRight Arrow
Iniciar Curso
Ver maisRight Arrow
Relacionado

Tutorial

Criando agentes LangChain para automatizar tarefas em Python

Um tutorial abrangente sobre a criação de agentes LangChain com várias ferramentas para automatizar tarefas em Python usando LLMs e modelos de bate-papo usando OpenAI.
Bex Tuychiev's photo

Bex Tuychiev

Tutorial

Primeiros passos com o Claude 3 e a API do Claude 3

Saiba mais sobre os modelos Claude 3, benchmarks de desempenho detalhados e como acessá-los. Além disso, descubra a nova API Python do Claude 3 para geração de texto, acesso a recursos de visão e streaming.
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

Como criar aplicativos LLM com o tutorial LangChain

Explore o potencial inexplorado dos modelos de linguagem grandes com o LangChain, uma estrutura Python de código aberto para criar aplicativos avançados de IA.
Moez Ali's photo

Moez Ali

Tutorial

Tutorial da API de assistentes da OpenAI

Uma visão geral abrangente da API Assistants com nosso artigo, que oferece uma análise aprofundada de seus recursos, usos no setor, orientação de configuração e práticas recomendadas para maximizar seu potencial em vários aplicativos de negócios.
Zoumana Keita 's photo

Zoumana Keita

Tutorial

Tutorial de chamada de função do OpenAI

Saiba como o novo recurso de Chamada de Função da OpenAI permite que os modelos GPT gerem saída JSON estruturada, resolvendo problemas comuns de desenvolvimento causados por saídas irregulares.
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

Tutorial de execução de scripts Python no Power BI

Descubra as diferentes maneiras de usar o Python para otimizar a análise, a visualização e a modelagem de dados no Power BI.
Joleen Bothma's photo

Joleen Bothma

Ver MaisVer Mais