Przejdź do głównej treści

Samouczek API Claude Fable 5.1: Zbuduj długodziałającego agenta deweloperskiego w Pythonie

Naucz się używać najnowszego flagowego modelu Anthropic do zbudowania agenta Pythona, który czyta repozytorium Flask przed zaplanowaniem zmiany. Dodaj aktualizacje postępu, narzędzia tylko-do-odczytu i kontrolę kosztów.
Zaktualizowano 3 wrz 2026  · 15 min Czytać

Eksploruj z AI

ChatGPTClaudePerplexity

Gdy testuję nowy model przez wywołanie API, pierwsza odpowiedź mówi mi niewiele. Mój pierwszy run Fable 5.1 zwrócił poprawną strukturę i ogólny plan. Chciałem wiedzieć, co się dzieje, gdy rozmowa się rozrośnie: czy aplikacja utrzyma spójną historię, obejrzy pliki bez czytania poza projektem, będzie raportować postęp i pokaże, skąd wziął się koszt?

Nasz przegląd Claude Fable 5.1 omawia premierę, benchmarki i szersze porównania modeli. Tutaj zaczniemy od małego wywołania w Pythonie i zbudujemy wokół niego pętlę agenta. Końcowy agent przyjmuje prośbę o funkcję, czyta projekt Flask i zwraca plan powiązany z plikami, które faktycznie przejrzał.

Omówimy, jak:

  • Wykonać wywołanie API Claude Fable 5.1 i bezpiecznie czytać bloki treści
  • Ustawić poziom rozumowania (effort) i zmienić go w trakcie rozmowy (beta)
  • Ograniczyć instrukcję systemową do jednej tury (beta)
  • Zwrócić ustrukturyzowany plan z Pydantic
  • Dodać narzędzia repozytorium tylko do odczytu z granicą katalogu głównego projektu
  • Uruchomić wieloturę pętli narzędzi
  • Czytać aktualizacje postępu agenta między wywołaniami narzędzi (beta)
  • Utrzymać poprawność bloków myślenia dzięki historii tylko-do-dopisania
  • Cache’ować powtarzający się kontekst i szacować koszt żądania po opublikowanych stawkach
  • Obsługiwać odmowy i wystawić agenta przez FastAPI

Funkcje beta używają datowanych nagłówków, więc sprawdź je w dokumentacji Anthropic przed wdrożeniem.

Ile kosztuje uruchamianie Claude Fable 5.1 w pętli agenta?

Agent wysyła ten sam system prompt, definicje narzędzi i kontekst repozytorium przy każdej turze, więc stawką rozliczeniową decydującą o rachunku jest odczyt z cache, a nie stawka wejściowa.

Fable 5.1 kosztuje $10 za milion tokenów wejściowych i $50 za milion tokenów wyjściowych, bez zmian względem Fable 5. Odczyty z cache kosztują $0.25 za milion, w dół z $1, a pięciominutowe zapisy do cache pozostają przy $12.50 za milion. Nasz przewodnik po Claude Fable 5.1 zawiera pełną tabelę stawek i szacunki oszczędności Anthropic.

Czytanie zcache’owanego prefiksu jest tanie. Zapisy nie — kosztują 50 razy więcej niż odczyty, więc pętla opłaca się dopiero, gdy prefiks jest odczytywany wielokrotnie. Rozbicie kosztów później pokazuje, jak to wyszło w realnym uruchomieniu i która kategoria faktycznie dominowała.

Limit tokenów wynika z modelu, nie z budżetu. Fable 5.1 daje 1M-tokenowe okno kontekstu z maks. 128K tokenów wyjścia na odpowiedź, a max_tokens to twardy limit łącznie dla myślenia i tekstu odpowiedzi. Przy wysokim effort potrzebujesz miejsca na oba, dlatego poniższa pętla agenta ustawia 16 000 zamiast „ładniejszej” wartości.

Retencja danych, warstwa priorytetowa i znakowanie wodne

Kilka szczegółów dostępowych ma znaczenie, zanim napiszesz kod. Dwa z nich zablokują twoje żądania od razu:

  • Fable 5.1 wymaga 30-dniowej retencji danych i nie jest dostępny przy zerowej retencji, chyba że Anthropic przyzna dostęp. Żądanie z niekompatybilnego workspace zwróci 400 invalid_request_error bez innej wskazówki.

  • Model nie jest wspierany w Priority Tier. Fable 5 jest, więc to łapie osoby migrujące.

  • Wyjście tekstowe Fable 5.1 ma znak wodny Anthropic. Nie dodaje tokenów i nie wymaga zmian w żądaniu.

Użyj Claude Fable 5.1 przez API, aby zbudować agenta deweloperskiego świadomego repozytorium

Nasz workflow ma dwa etapy:

  1. Ograniczona pętla inspekcji czyta dozwolone pliki projektu.
  2. Końcowe żądanie z ustrukturyzowanymi wynikami przekształca ten kontekst w plan. 

Przykładowy projekt to małe Flask JSON API do zapisywania i wyszukiwania zakładek, z fabryką aplikacji, trzema blueprintami, modułem config, modelami i zestawem pytest. Jako bieżące zadanie używam limitowania zapytań (rate limiting), bo agent musi sprawdzić setup aplikacji, trasy, konfigurację i testy, zanim wskaże wymagane pliki i testy. Pełny kod i próbny projekt znajdziesz w repozytorium GitHub.

Diagram przepływu prośby o funkcję przez agenta Claude Fable 5.1, allowlistę ścieżek i przykładowy projekt, a następnie zwrot ustrukturyzowanego planu

Żądania docierają do plików przez jedną granicę. Obraz: autor.

Agent może używać tylko trzech narzędzi: list_project_files, read_project_file i get_project_metadata. Claude nigdy nie sięga bezpośrednio do systemu plików. Prosi o ścieżkę, a twój kod decyduje, czy jest dozwolona.

Konfiguracja API Claude Fable 5.1 w Pythonie

Zacznij od osobnego środowiska Pythona i trzymaj klucz API na serwerze.

Wymagania wstępne

Potrzebujesz Pythona 3.10 lub nowszego oraz klucza Anthropic API z dostępem do claude-fable-5-1

Aby utworzyć klucz API, zaloguj się do Claude Console, otwórz stronę kluczy API, kliknij Create key, a następnie skopiuj klucz. Najlepiej nadać mu nazwę pomagającą zapamiętać cel, wybrać datę wygaśnięcia i bezpiecznie go przechowywać.

Zainstaluj SDK i dodaj klucz API

Utwórz środowisko wirtualne i zainstaluj paczki:

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

Trzymaj SDK przypięte, bo funkcje beta często się zmieniają. Aktualizacje postępu wymagają co najmniej 1.1.0, a przykłady używają 1.3.0.

Umieść klucz w .env i dodaj .env do .gitignore przed pierwszym commitem. Klucz należy trzymać na kontrolowanym przez ciebie serwerze, nigdy w przeglądarce ani dostępnym repozytorium. Jego ujawnienie może umożliwić nieautoryzowane użycie API i naliczanie kosztów za wejście, wyjście i operacje cache.

ANTHROPIC_API_KEY=sk-ant-your-key-here

Z tym na miejscu klient sam znajdzie klucz.

Wykonaj pierwsze wywołanie API Claude Fable 5.1 w Pythonie

Wyślij jak najmniejsze żądanie API, zanim zbudujesz na nim cokolwiek dalej.

Wyślij pierwsze żądanie API

Zainicjalizuj klienta, wyślij jedną wiadomość użytkownika i wydrukuj metadane odpowiedzi:

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 pokazujący odpowiedź API Claude Fable 5.1 z ID modelu, powodem zatrzymania, licznikami tokenów i ID żądania

Pierwsze wywołanie zwraca tekst plus metadane. Obraz: autor.

Wywołanie next(...) wybiera pierwszy blok tekstowy. Adaptacyjne myślenie jest zawsze włączone i nie da się go wyłączyć, więc odpowiedź może zaczynać się blokiem myślenia; wysłanie thinking: {"type": "disabled"} zwróci 400 zamiast je wyłączyć. Gdy blok myślenia jest pierwszy, response.content[0].text zgłosi wyjątek.

Rozwiązaniem jest filtrowanie po typie bloku zamiast zakładać stałą pozycję. Loguj też response._request_id, bo wsparcie Anthropic używa go do śledzenia żądania.

Oto żądanie użyte w tych przykładach planowania i effort. Wymaga, by agent przejrzał kilka plików:

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

Trzymaj ten tekst bez zmian podczas porównywania poziomów effort i liczby tokenów. Wyniki będą wtedy opisywać ustawienia API, a nie inny prompt.

Ustaw poziom rozumowania przez output_config

Ustaw effort poprzez output_config. Akceptuje low, medium, high, xhigh i max. Domyślne API to high.

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

Effort może wpływać na użycie tokenów, zachowanie narzędzi i opóźnienie. Puściłem tę samą prośbę o funkcję po trzy razy na każdym z czterech poziomów effort; tabela pokazuje średnie:

Effort

Sekundy

Tokeny myślenia

Łącznie tokenów wyjścia

Koszt

low

7.7

111

173

$0.0093

medium

8.1

129

186

$0.0099

high

7.9

136

199

$0.0106

xhigh

20.0

151

1,764

$0.0888

Tokeny myślenia są wliczone w łączne tokeny wyjścia, więc nie sumuj tych kolumn. W tych runach low, medium i high były zbliżone pod względem opóźnienia i kosztu.

xhigh trwało dwa i pół raza dłużej, wygenerowało prawie dziewięć razy więcej tokenów wyjściowych i kosztowało osiem razy więcej. 

Wniosek: Zacznij od high, obniż do medium dla rutynowych kroków, a wyższe poziomy używaj tylko, gdy twoje testy pokazują mierzalną poprawę. Przy low model może odpowiedzieć z pamięci zamiast wywołać narzędzie retrieval. Jeśli tura potrzebuje świeżych informacji, powiedz to lub podnieś poziom.

Ogranicz zakres agenta promptem systemowym

Prompt systemowy definiuje zachowanie agenta:

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."""

Wskazówki dotyczące promptów Anthropic zauważają, że model może rozszerzać zadanie albo zatrzymać się zbyt wcześnie. Prompt każe mu trzymać zakres i kończyć konkretnymi wskazówkami. Schemat później zajmie się formatem wyjścia.

Zwróć ustrukturyzowany plan z Pydantic

Zdefiniuj plan w Pydantic, aby twoja aplikacja mogła go zwalidować i przekazać dalej:

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() konwertuje model Pydantic do schematu JSON, wysyła go, waliduje odpowiedź i zwraca obiekt typowany w parsed_output. Ustrukturyzowane wyniki są ogólnie dostępne, więc bez nagłówka beta. Najpierw sprawdź stop_reason, bo odmowa (omówiona dalej) pomija schemat i nie zostawia nic do sparsowania.

Ten ogólny wynik z wstępu miał jedną rzecz dobrze: nie nazwał plików, których nie widział. Schemat waliduje strukturę, nie ugruntowanie faktów.

Claude Fable 5.1 vs. Fable 5: zmiany migracyjne w API

Zanim dodasz narzędzia, uwzględnij ograniczenia wymuszonego wyboru narzędzi, kompatybilność bloków myślenia i historię tylko-do-dopisania.

  • Fable 5.1 odrzuca wymuszone wybieranie narzędzi. Sekcja pętli narzędzi poniżej pokazuje błąd i używaną konfigurację auto.

  • Bloki myślenia są kompatybilne tylko w jedną stronę. Fable 5.1 czyta bloki z wcześniejszych modeli Claude, ale żaden wcześniejszy model nie może czytać jego bloków. 

Gdy router lub fallback przenosi rozmowę do starszego modelu, API usuwa niekompatybilne bloki, zanim model docelowy je zobaczy. Pozostała historia zostaje, ale starszy model musi planować bez tych bloków.

Edycja wcześniejszych tur unieważnia kolejne bloki myślenia. To może zepsuć przycinanie historii i podsumowania po stronie klienta.

Pełen zestaw zmian opisuje przewodnik migracyjny.

Dodaj narzędzia repozytorium tylko do odczytu

Teraz daj modelowi kontekst repozytorium przez narzędzia tylko-do-odczytu.

Zdefiniuj narzędzia tylko-do-odczytu

Warstwa narzędzi ma dwie części: funkcje Pythona egzekwujące zasady dostępu i schematy, które Claude może wywoływać.

Ogranicz ścieżki do katalogu głównego projektu

Tylko-do-odczytu to nie to samo co bezpieczne. Model równie łatwo poprosi o ../../.env co o config.py, więc strażnik należy do twojego kodu, a nie promptu:

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

Odrzuć ścieżki bezwzględne i komponenty symlinków, potem rozwiąż ścieżkę i potwierdź, że pozostaje pod rootem projektu. Prośba o ../.env zwróci „path is outside the project root”. Zwrócony błąd narzędzia pozwala agentowi kontynuować z dozwolonymi plikami.

Zdefiniuj rygorystyczne schematy narzędzi

Klasa reader kontroluje, co Python może otworzyć. Claude potrzebuje też schematów JSON opisujących trzy akcje, o które może prosić:

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 sprawdza argumenty, gdy model wybiera narzędzie. Nie wymusza wywołania narzędzia, co ma znaczenie w Fable 5.1.

Uruchom wieloturę pętli narzędzi

Zacznij od bazowej pętli: wyślij narzędzia, sprawdź stop_reason, uruchom to, o co poproszono, dołącz wyniki i powtórz.

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 ogranicza żądania modelu, nie wydatki, więc egzekwuj osobny limit kosztów, jeśli potrzeba. Pętla obsługuje refusal, max_tokens i tool_use bezpośrednio; inne powody zatrzymania kończą etap inspekcji. Pole is_error mówi modelowi, że ścieżka została odrzucona, więc może wybrać inną akcję.

Dlaczego wymuszony wybór narzędzia zwraca 400

W Fable 5 mogłeś wymusić pierwsze wywołanie przez tool_choice: {"type": "any"}. Fable 5.1 zwraca ten błąd przed wykonaniem żądania:

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

Wymuszone wywołania ominęłyby zawsze włączone myślenie. Zostaw tool_choice na auto, użyj zdefiniowanych wyżej rygorystycznych schematów i nazwij narzędzia w promcie, gdy dany krok ich wymaga.

Fable 5.1 czasem wydaje jedno wywołanie narzędzia na turę, podczas gdy Fable 5 łączył kilka. To dodaje round-tripów. Dodaj tę linię do promptu: „Proś o niezależne pliki w tej samej turze zamiast po jednym na turę.” W przykładowym runie zgrupowano dziewięć niezależnych próśb o pliki, choć liczba się różni.

Streamuj odpowiedzi i aktualizacje postępu Claude Fable 5.1

Streamowanie tekstu emituje treść odpowiedzi w trakcie generowania; aktualizacje postępu obejmują pauzy między wywołaniami narzędzi.

Streamuj odpowiedzi tekstowe

Pełny projekt używa context_system() do połączenia SYSTEM_PROMPT z podsumowaniem projektu przed startem strumienia:

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() daje złożoną wiadomość z użyciem i powodem zatrzymania po opróżnieniu strumienia. Kawałki strumienia nie muszą zawierać kompletnego JSON, więc poczekaj na wiadomość finalną przed parsowaniem.

Pokazuj postęp między wywołaniami narzędzi

Streamowanie tekstu nie obejmuje opóźnień podczas wywołań narzędzi. Fable 5.1 może pisać krótkie aktualizacje postępu przed wywołaniami narzędzi. Przy domyślnym thinking.display równym "omitted", bloki myślenia specyficzne dla postępu są puste, choć model może nadal produkować zwykłe wprowadzenie tekstowe.

Z display: "updates" i nagłówkiem beta thinking-display-updates-2026-08-18 dokumentacja API definiuje czytelną aktualizację postępu jako niepusty blok thinking przy ukrytym rozumowaniu. W rzeczywistych runach dla tego projektu pole thinking pozostawało puste, a czytelny status przychodził jako zwykły blok text bezpośrednio przed tool_use. Pomocnik zatem sprawdza oba typy bloków, a pętla woła go tylko w turach kończących się na 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

Wiadomości o postępie opisują pliki, które model planuje czytać: „Przeczytam okablowanie aplikacji, config, rozszerzenia, publiczne i auth route’y oraz istniejące testy, bo tam wpiąłby się rate limiting.” Wyświetlaj te wiadomości i ignoruj puste bloki.

Terminal pokazujący pętlę agenta Claude Fable 5.1 z użyciem tokenów na turę, wiadomościami o postępie i zgrupowanymi odczytami plików

Agent czyta pliki, raportując postęp. Obraz: autor.

Fable 5.1 pisze ich mniej niż Fable 5, zwłaszcza przy wyższym effort. Jeśli twój interfejs wymaga regularnych aktualizacji, poproś o linijkę otwierającą, wiadomości o postępie i zamykające podsumowanie.

Zmień effort Claude Fable 5.1 w trakcie rozmowy

Kolejna funkcja jest bardzo sprytna. Jak wiemy, agent repozytoryjny nie potrzebuje tego samego poziomu rozumowania w każdej turze.

Zmieniaj effort między turami

W pętli agenta obniż effort dla rutynowego retrieval i podnieś go znowu dla końcowego planowania.

Z nagłówkiem beta mid-conversation-output-config-2026-07-01 możesz dołączyć wiadomość systemową, która zmienia tylko poziom effort:

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,
)

Nowy poziom działa od następnej tury użytkownika, nie w połowie bieżącej, i nie unieważnia cache’u promptu. Zmiana top-level output_config.effort między żądaniami unieważnia go. 

Agent trzyma ustawienie top-level na high, dołącza per-wiadomość dyrektywę medium przed rutynowym retrieval i dołącza high przed finalnym planem. Sprzężony test zużył 18 tokenów wyjścia przy niższym effort vs 76 przy poprzednim ustawieniu. Traktuj to jako przykład, nie gwarantowaną redukcję.

Zastosuj instrukcję systemową do jednej tury

Użyj instrukcji o zasięgu tury, aby zablokować dodatkowe odczyty plików podczas finalnego planowania.

Ustaw clear_at: "next_user_message" na wiadomości systemowej z nagłówkiem beta mid-conversation-system-clear-at-2026-08-21 . API traktuje jej tekst jako instrukcję systemową na bieżącą turę, a potem przestaje ją renderować po następnej wiadomości użytkownika. Zostaje w messages, więc wcześniejsza historia się nie zmienia, cache nadal pasuje, a wyczyszczona wiadomość nie kosztuje tokenów wejścia.

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"} powstrzymuje finalne żądanie przed wywołaniem kolejnego narzędzia. Instrukcja o ograniczonym zasięgu ogranicza plan do plików, które agent już przejrzał. Nie dodawaj przypomnienia i nie usuwaj go w następnym żądaniu. Taka edycja unieważnia późniejsze bloki myślenia.

Napraw błędy 400 bloków myślenia w Claude Fable 5.1

Błąd The block is bound to a different conversation oznacza, że historia przed blokiem myślenia się zmieniła. Każdy blok myślenia Fable 5.1 jest związany z dokładnym promptem systemowym, definicjami narzędzi i wiadomościami, które go poprzedzały.

Wynik zależy od tego, kiedy utworzono twoje konto. 

  • Konta utworzone 31 sierpnia 2026 r. lub później dostają 400 mówiące, że blok jest związany z inną rozmową. 

  • Dla kont utworzonych wcześniej API rejestruje niezgodność, ale działa na nią tylko, gdy żądanie ustawia thinking.block_binding.prefix_mismatch_behavior

Możesz to wykryć nagłówkiem beta thinking-binding-controls-2026-08-01, ustawieniem thinking.block_binding.prefix_mismatch_behavior na "drop_block" oraz tablicą input_transformations. Edytowana historia pojawi się jako reason: "prefix_binding_mismatch". Uruchom to sprawdzenie raz na swojej integracji.

Niezgodność wyzwalają następujące operacje:

  • Edycja, zmiana kolejności lub usunięcie wcześniejszej tury przy zachowaniu późniejszych

  • Wstrzyknięcie tekstu per-żądanie do wcześniejszej tury i usunięcie go przy następnym żądaniu

  • Zmiana treści lub kolejności top-level promptu system lub tablicy tools w trakcie rozmowy

  • Serwowanie innych bajtów spod URL obrazu lub dokumentu w późniejszym żądaniu

Każde z nich ma substytut utrzymujący wiązania:

  • Dodawaj instrukcje wiadomościami systemowymi w trakcie rozmowy zamiast edytować system

  • Zmieniaj narzędzia zmianami narzędzi w trakcie rozmowy zamiast modyfikować tablicę top-level. 

  • Przycinaj historię serwerowym edytowaniem kontekstu lub kompakcją, które nie liczą się jako edycje. 

  •  Przekazuj bloki myślenia bez zmian.

Przenoszenie znaczników cache_control i zmiana effort na poziomie żądania są bezpieczne i nie unieważniają wiązań bloków myślenia. Zmiana effort top-level restartuje jednak cache promptów, więc używaj effort per-wiadomość, gdy cache’owany prefiks ma pozostać.

Cache promptów a koszt API Claude Fable 5.1

Poniższy run rozdziela koszty świeżego wejścia, zapisów cache, odczytów cache i wyjścia.

Dodaj automatyczne cache’owanie promptu

Cache promptów zmniejsza koszt kontekstu, który powtarza się między turami. Rosnąca historia przesuwa punkt podziału, więc automatyczne cache’owanie lepiej tu pasuje.

Pole top-level cache_control przesuwa punkt podziału do najnowszego blokowalnego w cache przy każdym żądaniu:

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

Prefiks krótszy niż 512 tokenów nie jest cache’owany w Fable 5.1, nawet oznaczony cache_control. API przetwarza go normalnie i zwraca zera dla obu liczników cache. Zapis prefiksu 583-tokenowego kosztował $0.0073; odczyt w następnej turze kosztował $0.00015. Druga tura i tak musiała zapisać swoją nową część do cache, więc trafienie w cache nie usuwa całego kosztu wejścia.

Oszacuj koszt API z uwzględnieniem cache

response.usage raportuje osobno świeże wejście, tworzenie cache, odczyty cache i wyjście. Wyceń wszystkie cztery liczniki z osobna; sumowanie tylko wejścia i wyjścia ukrywa koszt zapisu cache i zawyża cenę trafień cache.

Oto rozbicie kosztów z jednego pełnego runu, który przeczytał 12 plików w trzech turach i wygenerował finalny plan:

Pozycja

Tokeny

Szacowany koszt

Udział

Wyjście

5,713

$0.2857

59.4%

Zapisy cache

15,426

$0.1928

40.1%

Świeże wejście

50

$0.0005

0.1%

Odczyty cache

6,549

$0.0016

0.3%

Razem

27,738

$0.4806

100%

Odczyty z cache stanowiły ułamek poniżej połowy procenta tego szacunku. Przy starej stawce Fable 5 run kosztowałby ok. $0.4855 zamiast $0.4806. Oszczędności rosną, gdy każda tura ponownie używa dużo kontekstu.

W tym runie wyjście wygenerowało prawie 60% szacunku, a zapisy cache ok. 40%. Przy pięciominutowej stawce użytej tutaj token zapisu cache kosztuje 50 razy tyle, co token odczytu cache. Godzinny zapis cache kosztuje 80 razy tyle.

Obsługuj odmowy i fallbacki Claude Fable 5.1

Odmowa i nieudane żądanie wymagają różnego zachowania aplikacji.

Wykrywaj odmowy przed parsowaniem wyjścia

Odmowa przed wyjściem przychodzi jako HTTP 200 z stop_reason: "refusal", pustą treścią i stop_details. Kategoria może być null. Odmowa później w strumieniu może nastąpić po częściowym wyjściu, które aplikacja powinna odrzucić. try/except wokół wywołania nie złapie żadnego z tych przypadków.

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})."

Traktuj to jako stan aplikacji. Jeśli dozwolone żądanie jest niejasne, przepisz je precyzyjniej. Nie buduj logiki retry, której celem jest obejście klasyfikatora.

Odmowa przychodzi jako HTTP 200. Obraz: autor.

Skonfiguruj fallback po stronie serwera

Fallback po stronie serwera może ponowić odrzucone żądanie na innym modelu, używając fallbacks: "default" z nagłówkiem beta server-side-fallback-2026-07-01 . Dozwolone cele dla Fable 5.1 to Opus 4.8 i Opus 5

Domyślny fallback działa tylko, gdy kategoria odmowy ma rekomendowany cel. Przetestowana odmowa reasoning_extraction nie wyzwoliła fallbacku; sprawdzaj usage.iterations zamiast zakładać, że każda odmowa się ponowi. Jak wspomniano, przejście na starszy model usuwa też bloki myślenia Fable 5.1.

Wystaw agenta Claude Fable 5.1 przez FastAPI

Lokalny agent może teraz obsłużyć ten sam workflow przez HTTP API.

Utwórz endpoint planu

Jeśli potrzebujesz tylko lokalnego skryptu, pomiń tę sekcję. Dla usługi webowej użyj FastAPI z wariantem AsyncAnthropic. Utwórz jednego klienta dla procesu w handlerze lifespan. Zaimportuj schemat i prompty z istniejącego modułu agenta.

@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))

Zwróć uwagę, że wywołujący wysyła nazwę projektu, nie ścieżkę. resolve_project() mapuje ją na jeden z małego zbioru dozwolonych rootów, więc żądanie nie może kazać serwerowi czytać gdziekolwiek. Ta usługa mapuje odmowy na 422 jako decyzję aplikacji. Samo API Claude zwraca je jako HTTP 200.

Uruchom to przez uvicorn app:app --reload. Interaktywna dokumentacja jest dostępna pod http://localhost:8000/docs.

Endpoint zwraca plan z szacowanym kosztem. Wideo: autor.

Endpoint /plan/stream uruchamia inspekcję w zadaniu w tle, umieszcza zdarzenia postępu i narzędzi na asyncio.Queue i emituje je przez StreamingResponse. Po zamknięciu strumienia generator anuluje zadanie w tle. Interfejs Streamlit w repozytorium renderuje ten sam strumień zdarzeń.

Streamlit pokazuje postęp agenta na żywo. Wideo: autor.

Lista kontrolna wdrożenia agenta Claude Fable 5.1

Limity i sprawdzenia zbudowane wcześniej pozostają częścią usługi. Przed wdrożeniem dodaj elementy operacyjne niewidoczne przy lokalnym uruchomieniu.

  • Przejrzyj domyślne dwa retry SDK dla odpowiedzi 429 i 5xx, następnie ustaw max_retries i timeouty pod budżet opóźnień usługi

  • Ustaw timeout żądania i potwierdź, że istniejące anulowanie zadania SSE zatrzymuje trwające prace po rozłączeniu klienta

  • Loguj ID modelu, wersję SDK, ID żądania, powód zatrzymania i cztery kategorie tokenów dla każdego runu

  • Alarmuj przy wzroście zapisów cache, tokenów wyjścia, odmów i runów dochodzących do limitu tur

  • Potwierdź, że ustawienie retencji konta pasuje do wymogu modelu

  • Przypnij SDK i sprawdzaj nagłówki beta przed każdym wydaniem

Kiedy używać Claude Fable 5.1 zamiast Opus 5 lub Sonnet 5

  • Anthropic poleca Opus 5 jako rozsądny domyślny wybór.
  • Testuj Fable 5.1, gdy Opus 5 nie domaga przy analizie długich repozytoriów, trudnym debugowaniu lub zadaniach agencyjnych z dużym kontekstem.
  • Dla pracy w repozytoriach i codziennych zadań porównaj Sonnet 5 i Opus 5 pod kątem jakości, opóźnień i kosztu.
  • Do klasyfikacji, ekstrakcji, krótkich odpowiedzi i prostszych próśb Sonnet 5 to dobry domyślny wybór; do najłatwiejszych zadań Haiku 4.5 też może być wystarczająco mocny.

Nie wybieraj Fable 5.1 tylko dlatego, że jest nowszy. Pojedyncze żądanie nadal może korzystać z effort i ustrukturyzowanych wyjść; streamowanie też działa. Nie skorzysta z pętli ani cache’owania powtarzanych prefiksów użytych tutaj.

Na koniec

Ogólny plan z mojego pierwszego wywołania stał się użyteczny dopiero po tym, jak agent przeczytał repozytorium. W ukończonym runie przejrzał 12 plików w trzech turach, a wyjście i zapisy cache stanowiły łącznie 99.5% szacowanego kosztu. Zatrzymałbym granicę ścieżek i historię tylko-do-dopisania, a potem przetestował, czy niższy effort zmniejsza koszt bez tego, by model pomijał narzędzia repozytorium.

Jeśli jedna odpowiedź może rozwiązać zadanie, zatrzymaj się na ustrukturyzowanych wyjściach. Użyj pętli narzędzi, gdy odpowiedź musi zależeć od plików repozytorium albo raportować postęp między wywołaniami.

Po szczegóły wyboru modeli polecam nasz kurs Introduction to Claude Models. Dla promptowania i workflowów agentów zobacz nasz kurs Software Development with Cursor.

FAQs

Czy Claude Fable 5.1 czyta obrazy tak samo jak kod?

Tak. Akceptuje obrazy i potrafi czytać wykresy oraz PDF-y. Pominąłem vision w głównym przykładzie, bo plan repozytorium go nie potrzebuje. Gdybym rozszerzał tego agenta o plan zmiany w UI, wysłałbym aktualny zrzut z prośbą o funkcję. Najpierw zmniejsz rozdzielczość, jeśli drobne detale wizualne nie wpływają na zadanie.

Dlaczego mój agent zwolnił po przejściu z Fable 5?

Najpierw sprawdź wyniki narzędzi, zanim obwinisz model. Jeśli instrukcja batchowania z wcześniejszej sekcji już jest, porównaj zarówno ich liczbę, jak i rozmiary. Obecny reader przycina każdy plik do 40 000 bajtów. Jeśli to nadal za dużo, dodaj argumenty zakresu linii lub wyszukiwania, by narzędzie mogło zwracać tylko istotne fragmenty.

Dlaczego Claude Fable 5.1 zwraca 400 invalid_request_error?

Nie rób retry w pierwszej kolejności. invalid_request_error zwykle wskazuje na kształt żądania lub ustawienie konta, które trzeba zmienić. W tym projekcie prawdopodobnymi przyczynami są wymuszony tool_choice, niekompatybilna retencja, edytowany prefiks przy zachowanych blokach myślenia lub pole beta wysłane bez pasującego nagłówka. Napraw wskazaną przyczynę i wyślij żądanie ponownie.

Czy powinienem cache’ować pliki źródłowe czy podsumowanie?

Stosuję taką zasadę: cache’uj pliki źródłowe, gdy dokładny kod ma znaczenie przez kilka tur. Jeśli późniejsze kroki potrzebują tylko architektury lub mapy plików, cache’uj podsumowanie. Podsumowanie kosztuje mniej tokenów, ale może pominąć tę jedną linię, której potrzebuje plan końcowy.

Czy Batch API może uruchomić tego agenta?

Nie sam z siebie. Batch API wysyła pojedyncze żądania Messages; nie uruchamia tej pętli narzędzi po stronie klienta. Użyłbym go do samowystarczalnych przeglądów repozytoriów, gdy nie jest potrzebny postęp na żywo. Uruchomienie pełnej pętli w batchach wymaga twojego kodu, który przetworzy żądania narzędzi z jednej partii przed wysłaniem następnej.

Tematy

Ucz się AI z DataCamp!

Track

Inżynier AI Associate dla programistów

26 godz.
Dowiedz się, jak integrować AI z aplikacjami software’owymi za pomocą API i bibliotek open source. Rozpocznij swoją drogę do zostania inżynierem AI już dziś!
Zobacz szczegółyRight Arrow
Rozpocznij Kurs
Zobacz więcejRight Arrow