Hoppa till huvudinnehållet

Claude Fable 5.1 API-handledning: Bygg en långkörande utvecklaragent i Python

Lär dig hur du använder Anthropics senaste flaggskeppsmodell för att bygga en Python-agent som läser ett Flask-repo innan den planerar en ändring. Lägg till framstegsuppdateringar, skrivskyddade filverktyg och kostnadskontroller.
Uppdaterad 3 sep. 2026  · 15 min läsa

Utforska med AI

ChatGPTClaudePerplexity

När jag testar en ny modell via ett API-anrop säger det första svaret mig väldigt lite. Min första körning med Fable 5.1 gav en giltig struktur och en allmän plan. Jag ville veta vad som händer när konversationen växer: kan applikationen behålla sin historik intakt, inspektera filer utan att läsa utanför projektet, rapportera framsteg och visa var kostnaden kom ifrån?

Vår översikt av Claude Fable 5.1 täcker lansering, benchmarktester och bredare modelljämförelser. Här börjar vi med ett litet Python-anrop och bygger agentloopen runt det. Den slutliga agenten tar emot en funktionsförfrågan, läser ett Flask-projekt och returnerar en plan kopplad till filer den faktiskt inspekterade.

Vi går igenom hur du:

  • Gör ett API-anrop till Claude Fable 5.1 och läser innehållsblock säkert
  • Ställer in resonemangsinsats och ändrar den mitt i en konversation (beta)
  • Begränsar en systeminstruktion till en enda vända (beta)
  • Returnerar en strukturerad plan med Pydantic
  • Lägger till skrivskyddade repo-verktyg med en projektrotsgräns
  • Kör en verktygsslinga över flera vändor
  • Läser agentens framsteg mellan verktygsanrop (beta)
  • Håller thinking-block giltiga med historik som bara får appendas
  • Cachar upprepad kontext och uppskattar förfrågningskostnad enligt publicerade priser
  • Hanterar avslag och exponerar agenten via FastAPI

Betafunktionerna använder daterade headers, så jämför dem med Anthropics dokumentation innan du skeppar.

Vad kostar det att köra Claude Fable 5.1 i en agentloop?

En agent skickar om samma systemprompt, verktygsdefinitioner och repokontext vid varje vända, så den taxa som avgör din nota är cacheläsningen, inte indatahastigheten.

Fable 5.1 kostar $10 per miljon indata-token och $50 per miljon utdata-token, oförändrat från Fable 5. Cacheläsningar kostar $0,25 per miljon, ned från $1, och femminuters cache-skrivningar ligger kvar på $12,50 per miljon. Vår guide till Claude Fable 5.1 har hela pristabellen och Anthropics egna besparingsestimat.

Att läsa ett cachat prefix är billigt. Att skriva det är inte det, till 50 gånger läshastigheten, så loopen lönar sig först när ett prefix läses tillbaka flera gånger. Kostnadsuppdelningen senare visar hur det föll ut i en verklig körning, och vilken kategori som faktiskt dominerade.

Taket för token kommer från modellen, inte din budget. Fable 5.1 ger dig ett kontextfönster på 1 miljon token med upp till 128K utdatatoken per svar, och max_tokens är en hård gräns för thinking plus svarstext tillsammans. Vid hög effort behöver du utrymme för båda, vilket är varför agentloopen nedan sätter 16 000 i stället för något prydligare.

Datalagring, prioritetstier och vattenmärkning

Några åtkomstdetaljer spelar roll innan du skriver kod. Två av dem stoppar dina förfrågningar direkt:

  • Fable 5.1 kräver 30 dagars datalagring och är inte tillgänglig med noll lagring om inte Anthropic godkänner åtkomst. En förfrågan från en inkompatibel arbetsyta returnerar en 400 invalid_request_error utan annan hint.

  • Modellen stöds inte på Priority Tier. Fable 5 gör det, så detta fångar folk vid migrering.

  • Textutdata från Fable 5.1 har Anthropics textvattenmärke. Det tillför inga token och kräver inga ändringar i förfrågan.

Använd Claude Fable 5.1 via API för att bygga en repo-medveten utvecklaragent

Vårt arbetsflöde har två steg:

  1. En begränsad inspektionsslinga läser tillåtna projektfiler.
  2. En slutlig förfrågan med strukturerade svar förvandlar den kontexten till en plan. 

Exempelprojektet är ett litet Flask JSON-API för att spara och söka bokmärken, med en app-faktori, tre blueprints, en config-modul, modeller och en pytest-svit. Jag använder begränsning av förfrågningshastighet som löpande uppgift eftersom agenten måste inspektera app-setup, routes, config och tester innan den kan identifiera nödvändiga filer och tester. Komplett kod och exempelprojekt finns i GitHub-repot.

Diagram över en funktionsförfrågan som passerar genom en Claude Fable 5.1-agent, en tillåtslista för sökvägar och ett exempelprojekt innan den returnerar en strukturerad plan

Förfrågningar når filer genom en enda gräns. Bild av författaren.

Agenten kan bara använda tre verktyg: list_project_files, read_project_file och get_project_metadata. Claude kommer aldrig åt filsystemet direkt. Den ber om en sökväg, och din kod avgör om den sökvägen är tillåten.

Konfigurera Claude Fable 5.1 API i Python

Börja med en separat Python-miljö och behåll API-nyckeln på servern.

Förutsättningar

Du behöver Python 3.10 eller nyare och en Anthropic API-nyckel med åtkomst till claude-fable-5-1

För att skapa en API-nyckel, logga in i Claude Console, öppna sidan för API-nycklar, klicka på Create key och kopiera sedan nyckeln. Det är god praxis att ge den ett namn som hjälper dig minnas syftet, välja ett utgångsdatum och lagra nyckeln säkert.

Installera SDK och lägg till API-nyckeln

Skapa en virtuell miljö och installera paketen:

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

Behåll SDK:n låst eftersom betafunktioner ändras ofta. Framstegsuppdateringar kräver minst 1.1.0, och exemplen använder 1.3.0.

Lägg nyckeln i en .env-fil och lägg till .env i .gitignore innan din första commit. Den hör hemma på en server du kontrollerar, aldrig i en webbläsare eller ett åtkomligt repo. Att exponera den kan möjliggöra obehörig API-användning och kostnader för indata, utdata och cacheoperationer.

ANTHROPIC_API_KEY=sk-ant-your-key-here

Med det på plats hittar klienten nyckeln själv.

Gör ditt första API-anrop till Claude Fable 5.1 i Python

Skicka den minsta möjliga API-förfrågan innan du bygger något ovanpå den.

Skicka den första API-förfrågan

Initiera klienten, skicka ett användarmeddelande och skriv ut svarens metadata:

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 som visar ett API-svar från Claude Fable 5.1 med modell-ID, stop reason, tokenräkningar och request-ID

Första anropet returnerar text plus metadata. Bild av författaren.

Anropet next(...) väljer det första textblocket. Adaptivt tänkande är alltid på och kan inte stängas av, så ett svar kan börja med ett thinking-block; att skicka thinking: {"type": "disabled"} ger en 400 i stället för att stänga av det. När ett thinking-block kommer först, utlöser response.content[0].text ett undantag.

Lösningen är att filtrera på blocktyp i stället för att anta en fast position. Logga response._request_id också, eftersom Anthropic-support använder det för att spåra en förfrågan.

Här är förfrågan som används i planerings- och effort-exemplen. Den kräver att agenten inspekterar flera filer:

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

Behåll den texten oförändrad när du jämför effort-nivåer och tokenantal. Resultaten beskriver då API-inställningarna i stället för en annan prompt.

Ställ in resonemangsinsats med output_config

Ställ in effort via output_config. Den accepterar low, medium, high, xhigh och max. API-standard är high.

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

Effort kan påverka tokenanvändning, verktygsbeteende och latens. Jag körde samma funktionsförfrågan tre gånger på var och en av fyra effort-nivåer; tabellen visar medelvärden:

Effort

Sekunder

Thinking-token

Totala utdataton

Kostnad

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

Thinking-token ingår i totala utdataton, så addera inte kolumnerna. I dessa körningar låg low, medium och high nära varandra i latens och kostnad.

xhigh tog två och en halv gånger så lång tid, gav nästan nio gånger fler utdataton och kostade åtta gånger så mycket. 

Slutsats: Börja på high, gå ner till medium för rutinmoment, och använd högre nivåer bara när dina egna tester visar en mätbar förbättring. Vid low kan modellen svara ur minnet i stället för att anropa ett hämtningsverktyg. Om en vända behöver färsk information, säg det eller höj nivån.

Begränsa agentens räckvidd med en systemprompt

Systemprompten definierar agentens beteende:

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

Anthropics promptrekommendationer noterar att modellen kan utvidga uppgiften eller sluta för tidigt. Prompten säger åt den att hålla sig inom scope och avsluta med konkreta råd. Ett schema hanterar utdataformatet senare.

Returnera en strukturerad plan med Pydantic

Definiera planen med Pydantic så att din applikation kan validera den och skicka den vidare till annan kod:

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() konverterar Pydantic-modellen till ett JSON-schema, skickar det, validerar svaret och returnerar ett typat objekt i parsed_output. Strukturerade svar är allmänt tillgängliga, så ingen beta-header behövs. Kontrollera stop_reason först eftersom ett avslag, som behandlas senare, hoppar över schemat och lämnar dig inget att parsa.

Det där generiska resultatet från inledningen gjorde en sak rätt: det namngav inga filer som det inte kunde se. Ett schema validerar struktur, inte faktisk förankring.

Claude Fable 5.1 vs. Fable 5: ändringar vid API-migrering

Innan du lägger till verktyg, ta höjd för begränsningar kring tvingade verktyg, kompatibilitet för thinking-block och historik som bara får appendas.

  • Fable 5.1 avvisar tvingat verktygsval. Verktygsslingan nedan visar felet och auto-konfigurationen som används i stället.

  • Thinking-block är kompatibla bara i en riktning. Fable 5.1 läser block från tidigare Claude-modeller, men ingen tidigare modell kan läsa dess block. 

När en router eller fallback flyttar konversationen till en äldre modell, tar API:et bort inkompatibla block innan målmodellen ser dem. Återstående historik ligger kvar, men den äldre modellen måste planera utan dessa block.

Att redigera tidigare vändor ogiltigförklarar thinking-blocken som kom efter dem. Det kan bryta historiktrimning och klientsidesammanfattning.

Migrationsguiden täcker hela uppsättningen ändringar.

Lägg till skrivskyddade repo-verktyg

Ge nu modellen repokontext genom skrivskyddade verktyg.

Definiera de skrivskyddade verktygen

Verktygslagret har två delar: Python-funktionerna som upprätthåller åtkomstreglerna och de scheman Claude kan anropa.

Begränsa sökvägar till projektroten

Skrivskyddat är inte samma sak som säkert. En modell kan be om ../../.env lika lätt som config.py, så skyddet hör hemma i din kod snarare än din 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

Avvisa absoluta sökvägar och symlänk-komponenter, lös sedan upp sökvägen och bekräfta att den förblir under projektroten. Att begära ../.env returnerar ”path is outside the project root.” Det returnerade verktygsfelet låter agenten fortsätta med tillåtna filer.

Definiera strikta verktygsscheman

Läsarklassen styr vad Python får öppna. Claude behöver också JSON-scheman som beskriver de tre åtgärderna den kan begära:

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 kontrollerar argumenten när modellen väljer ett verktyg. Det tvingar inte ett verktygsanrop, vilket spelar roll för Fable 5.1.

Kör verktygsslingan över flera vändor

Börja med basloopen: skicka verktygen, inspektera stop_reason, kör det som begärdes, lägg till resultaten och upprepa.

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 begränsar modellens förfrågningar, inte spenderingen, så upprätta en separat kostnadsgräns vid behov. Loopen hanterar refusal, max_tokens och tool_use direkt; andra stoppskäl avslutar inspektionssteget. Fältet is_error berättar för modellen att en sökväg avvisades, så den kan välja en annan åtgärd.

Varför tvingat verktygsval returnerar 400

I Fable 5 kunde du tvinga första anropet med tool_choice: {"type": "any"}. Fable 5.1 returnerar detta fel innan förfrågan körs:

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

Tvingade anrop skulle hoppa över det alltid påslagna tänkandet. Låt tool_choice stå på auto, använd de strikta scheman som definierats ovan, och nämn verktygen i prompten när ett steg behöver ett.

Fable 5.1 gör ibland ett verktygsanrop per vända, medan Fable 5 batchade flera. Det ger extra rundor. Lägg till den här raden i prompten: ”Begär oberoende filer i samma vända i stället för en per vända.” En provkörning batchade nio oberoende filförfrågningar, även om antalet varierar.

Strömma svar och framstegsuppdateringar från Claude Fable 5.1

Textströmning skickar ut svarsinnehåll allt eftersom det genereras; framstegsuppdateringar täcker uppehåll mellan verktygsanrop.

Strömma textsvar

Hela projektet använder context_system() för att kombinera SYSTEM_PROMPT med en projektsammanfattning innan strömmen startas:

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() ger dig det sammansatta meddelandet med användning och stop reason när strömmen tömts. Strömmande bitar garanterar inte komplett JSON, så vänta på det slutliga meddelandet innan du parsar.

Visa framsteg mellan verktygsanrop

Textströmning täcker inte fördröjningar under verktygsanrop. Fable 5.1 kan skriva korta framstegsuppdateringar före verktygsanrop. Under standardvärdet thinking.display "omitted"är de framstegsspecifika thinking-blocken tomma, även om modellen fortfarande kan producera en vanlig textinledning.

Med display: "updates" och beta-headern thinking-display-updates-2026-08-18 definierar API-dokumentationen en läsbar framstegsuppdatering som ett icke-tomt thinking-block medan resonemanget förblir dolt. I livekörningarna för detta projekt var fältet thinking tomt och den läsbara statusen kom som ett vanligt text -block omedelbart före tool_use. Hjälparen kontrollerar därför båda blocktyperna, och loopen anropar den bara på vändor som slutar med 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

Framstegsmeddelandena beskriver filerna modellen planerar att läsa: ”Jag läser appens kopplingar, config, extensions, de publika och auth-rutterna och de befintliga testerna, eftersom det är där rate limiting skulle kopplas in.” Visa de meddelandena och ignorera tomma block.

Terminal som visar en Claude Fable 5.1-agentloop med tokenanvändning per vända, framstegsmeddelanden och batchade filläsningar

Agenten läser filer och rapporterar framsteg. Bild av författaren.

Fable 5.1 skriver färre sådana än Fable 5 gjorde, särskilt vid högre effort. Om ditt gränssnitt kräver regelbundna uppdateringar, be om en inledande rad, framstegsmeddelanden och en avslutande sammanfattning.

Ändra effort i Claude Fable 5.1 mitt i konversationen

Nästa funktion är riktigt smidig. Som vi alla vet behöver repo-agenten inte samma resonemangsdjup på varje vända.

Ändra effort mellan vändor

I en agentloop, sänk effort för rutinmässiga hämtningar och höj den igen för den slutliga planeringsvändan.

Med beta-headern mid-conversation-output-config-2026-07-01 kan du append:a ett systemmeddelande som bara ändrar effort-nivån:

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

Den nya nivån gäller från nästa användarvända, inte mitt i den aktuella, och den ogiltigförklarar inte prompt-cachen. Att ändra den övergripande output_config.effort mellan förfrågningar ogiltigförklarar den däremot. 

Agenten behåller toppnivåinställningen på high, append:ar en per-meddelande- medium -instruktion före rutinmässig hämtning och append:ar en high -instruktion före slutlig plan. Ett parat test använde 18 utdataton på lägre effort jämfört med 76 på tidigare inställning. Se det som ett exempel, inte en förväntad minskning.

Tillämpa en systeminstruktion på en vända

Använd en vändescope:ad instruktion för att blockera ytterligare filläsningar under slutlig planering.

Sätt clear_at: "next_user_message" på ett systemmeddelande med beta-headern mid-conversation-system-clear-at-2026-08-21 . API:et behandlar dess text som en systeminstruktion för den aktuella vändan och slutar sedan rendera den efter nästa användarmeddelande. Den ligger kvar i messages, så den tidigare historiken ändras inte, cachen fortsätter matcha och det rensade meddelandet kostar inga indata-token.

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"} hindrar den slutliga förfrågan från att anropa ett annat verktyg. Den scope:ade instruktionen begränsar planen till filer agenten redan inspekterat. Lägg inte till en påminnelse och radera den i nästa förfrågan. Den redigeringen ogiltigförklarar senare thinking-block.

Åtgärda 400-fel för thinking-block i Claude Fable 5.1

Ett fel The block is bound to a different conversation betyder att historiken före ett thinking-block ändrades. Varje thinking-block i Fable 5.1 är bundet till exakt den systemprompt, de verktygsdefinitioner och de meddelanden som föregick det.

Resultatet beror på när ditt konto skapades. 

  • Konton skapade den 31 augusti 2026 eller senare får en 400 som säger att blocket är bundet till en annan konversation. 

  • För tidigare konton registrerar API:et mismatchen men agerar på den först när förfrågan sätter thinking.block_binding.prefix_mismatch_behavior

Du kan upptäcka detta med beta-headern thinking-binding-controls-2026-08-01, thinking.block_binding.prefix_mismatch_behavior satt till "drop_block", och arrayen input_transformations. En redigerad historik visas som reason: "prefix_binding_mismatch". Kör den här kontrollen en gång mot din integration.

Följande operationer utlöser mismatchen:

  • Redigera, ändra ordning på eller ta bort en tidigare vända och behålla de senare

  • Injicera text per förfrågan i en tidigare vända och ta bort den i nästa förfrågan

  • Ändra innehållet eller ordningen för toppnivå-system-prompten eller tools-arrayen mitt i konversationen

  • Servera olika bytes från en bild- eller dokument-URL i en senare förfrågan

Var och en av dessa har en ersättning som håller bindningarna intakta:

  • Lägg till instruktioner med systemmeddelanden mitt i konversationen i stället för att redigera system

  • Ändra verktyg med verktygsändringar mitt i konversationen i stället för att ändra toppnivåarrayen. 

  • Trimma historik med serverside-kontextredigering eller komprimering som inte räknas som redigeringar. 

  •  Skicka tillbaka thinking-block oförändrade.

Att flytta cache_control markörer och ändra effort på förfrågenivå är båda säkra och ogiltigförklarar inte bindningar för thinking-block. Däremot startar ändring av toppnivåns effort om prompt-cachningen, så använd per-meddelande-effort när det cachade prefixet ska ligga kvar.

Prompt-caching och kostnad för Claude Fable 5.1 API

Följande körning separerar färska indata, cache-skrivningar, cache-läsningar och utdata-kostnader.

Lägg till automatisk prompt-caching

Prompt-caching minskar kostnaden för kontext som upprepas över vändor. Den växande historiken ändrar var brytpunkten ska ligga, så automatisk caching passar enklare här.

Ett toppnivåfält cache_control flyttar brytpunkten till det senaste cachningsbara blocket vid varje förfrågan:

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

Ett cachningsbart prefix kortare än 512 token cachas inte i Fable 5.1, även när det markeras med cache_control. API:et behandlar det normalt och returnerar noll för båda cache-räknarna. Att skriva ett prefix på 583 token kostade $0,0073; att läsa det nästa vända kostade $0,00015. Den andra vändan behövde fortfarande skriva sin nya del till cachen, så en cacheträff tog inte bort alla indatakostnader.

Uppskatta cachemedveten API-kostnad

response.usage rapporterar färska indata, cache-skapande, cache-läsningar och utdata separat. Prissätt alla fyra räknarna var för sig; att bara summera in- och utdata döljer cache-skrivkostnaden och överdriver priset för cacheträffar.

Här är kostnadsuppdelningen från en hel körning som läste 12 filer över tre vändor och producerade en slutlig plan:

Radpost

Token

Uppskattad kostnad

Andel

Utdata

5 713

$0.2857

59,4%

Cache-skrivningar

15 426

$0.1928

40,1%

Färska indata

50

$0.0005

0,1%

Cache-läsningar

6 549

$0.0016

0,3%

Totalt

27 738

$0.4806

100%

Cacheläsningar utgjorde en bråkdel av mindre än en halv procent av detta estimat. Med Fable 5:s gamla taxa hade körningen kostat cirka $0,4855 i stället för $0,4806. Besparingarna växer när varje vända återanvänder mycket mer kontext.

I denna körning stod utdata för nästan 60% av estimatet, och cache-skrivningar för cirka 40%. Vid femminuterstaxan som används här kostar en cache-skrivtoken 50 gånger så mycket som en cache-lästoken. En en-timmes cache-skrivning kostar 80 gånger så mycket.

Hantera avslag och fallbacks i Claude Fable 5.1

Ett avslag och en misslyckad förfrågan kräver olika applikationsbeteende.

Upptäck avslag innan du parsar utdata

Ett avslag före utdata kommer som HTTP 200 med stop_reason: "refusal", tomt innehåll och stop_details. Dess kategori kan vara null. Ett avslag senare i en ström kan följa på partiell utdata, som applikationen bör kassera. Ett try/except runt anropet fångar inte något av fallen.

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

Hantera det som ett applikationstillstånd. Om en tillåten förfrågan är oklar, skriv om den mer exakt. Bygg inte omförsökslogik vars syfte är att ta sig runt klassificeraren.

Ett avslag kommer som HTTP 200. Bild av författaren.

Konfigurera serverside-fallback

Serverside-fallback kan försöka igen med en avslagen förfrågan på en annan modell, med fallbacks: "default" och beta-headern server-side-fallback-2026-07-01 . Tillåtna mål för Fable 5.1 är Opus 4.8 och Opus 5

Standardfallback körs bara när avslagskategorin har ett rekommenderat mål. Ett testat reasoning_extraction -avslag utlöste inte fallback; inspektera usage.iterations i stället för att anta att varje avslag kommer att försöka igen. Som nämnts tidigare, att gå till en äldre modell tar också bort Fable 5.1:s thinking-block.

Serva Claude Fable 5.1-agenten med FastAPI

Den lokala agenten kan nu serva samma arbetsflöde via ett HTTP-API.

Skapa plan-endpointen

Om du bara behöver ett lokalt skript kan du hoppa över det här avsnittet. För en webbservice, använd FastAPI med AsyncAnthropic. Skapa en klient för processen i en lifespan-hanterare. Importera schemat och promptarna från den befintliga agentmodulen.

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

Observera att anroparen skickar ett projektnamn, inte en sökväg. resolve_project() mappar det till en av ett litet antal tillåtna rötter, så en förfrågan kan inte be servern läsa var som helst. Denna tjänst mappar avslag till 422 som ett applikationsval. Claude-API:t returnerar dem som HTTP 200.

Kör den med uvicorn app:app --reload. Den interaktiva dokumentationen finns på http://localhost:8000/docs.

Endpointen returnerar en plan med en uppskattad kostnad. Video av författaren.

Endpointen /plan/stream kör inspektionen i en bakgrundsuppgift, lägger framstegs- och verktygshändelser på en asyncio.Queue och skickar ut dem via StreamingResponse. När strömmen stängs avbryter generatorn bakgrundsuppgiften. Streamlit-gränssnittet i repot renderar samma händelseström.

Streamlit visar agentens liveframsteg. Video av författaren.

Checklista för driftsättning av Claude Fable 5.1-agent

Begränsningarna och kontrollerna vi byggde tidigare förblir en del av tjänsten. Före driftsättning, lägg till de operativa bitarna som inte syns i en lokal körning.

  • Granska SDK:ns två standardomförsök för 429- och 5xx-svar, och ställ sedan in max_retries och timeouts för att matcha tjänstens latensbudget

  • Sätt en förfrågningstimeout och bekräfta att den befintliga SSE-uppgiftsavbrytningen stoppar pågående arbete när en klient kopplar från

  • Logga modell-ID, SDK-version, request-ID, stoppskäl och fyra tokenkategorier för varje körning

  • Varna vid ökande cache-skrivningar, utdataton, avslag och körningar som når vändetaket

  • Bekräfta att kontots lagringsinställning matchar modellens krav

  • Lås SDK:n och dubbelkolla beta-headers före varje release

När ska du använda Claude Fable 5.1 i stället för Opus 5 eller Sonnet 5

  • Anthropic rekommenderar Opus 5 som ett rimligt standardval.
  • Testa Fable 5.1 när Opus 5 inte räcker för lång repo-analys, svår felsökning eller agentiska uppgifter med stor kontext.
  • För repoarbete och vardagsuppgifter, jämför Sonnet 5 och Opus 5 på kvalitet, latens och kostnad.
  • För klassificering, extraktion, korta svar och enklare förfrågningar är Sonnet 5 ett bra standardval; för de enklaste uppgifterna kan Haiku 4.5 också vara tillräckligt stark.

Välj inte Fable 5.1 bara för att den är nyare. En enskild förfrågan kan fortfarande använda effort och strukturerade svar; strömning fungerar också. Den gynnas inte av loopen eller cachning av upprepade prefix som används här.

Avslutande tankar

Den generiska planen från mitt första anrop blev användbar först efter att agenten läste repot. I den färdiga körningen inspekterade den 12 filer över tre vändor, medan utdata och cache-skrivningar stod för 99,5% av den uppskattade kostnaden. Jag skulle behålla sökvägsgränsen och historik som bara får appendas, och sedan testa om lägre effort minskar kostnaden utan att få modellen att hoppa över repo-verktyg.

Om ett svar kan lösa uppgiften, stanna vid strukturerade svar. Använd verktygsslingan när svaret måste bero på repofiler eller rapportera framsteg mellan anrop.

För detaljer kring modellval rekommenderar jag vår kurs Introduktion till Claude-modeller. För promptning och agentarbetsflöden, se vår kurs Programvaruutveckling med Cursor.

FAQs

Kan Claude Fable 5.1 läsa bilder såväl som kod?

Ja. Den accepterar bildinmatning och kan läsa diagram och PDF:er. Jag lämnade vision utanför huvudexemplet eftersom repoplanen inte behöver det. Om jag skulle utöka denna agent för att planera en UI-ändring skulle jag skicka den aktuella skärmdumpen med funktionsförfrågan. Skala ner den först om små visuella detaljer inte påverkar uppgiften.

Varför blev min agent långsammare efter bytet från Fable 5?

Kontrollera verktygsresultaten innan du skuldbelägger modellen. Om batch-instruktionen från tidigare redan finns, jämför både deras antal och storlek. Den nuvarande läsaren begränsar varje fil till 40 000 byte. Om det fortfarande är för stort, lägg till radintervall- eller sökargument så att verktyget bara kan returnera relevanta avsnitt.

Varför returnerar Claude Fable 5.1 en 400 invalid_request_error?

Försök inte igen först. En invalid_request_error pekar vanligtvis på en form på förfrågan eller kontoinställning som måste ändras. I det här projektet är sannolika orsaker tvingad tool_choice, en inkompatibel lagringsinställning, ett redigerat prefix med bevarat tänkande eller ett betafält skickat utan matchande header. Åtgärda angiven orsak och skicka sedan förfrågan igen.

Ska jag cacha källfiler eller en sammanfattning?

Jag använder denna regel: cacha källfiler när exakt kod spelar roll över flera vändor. Om senare steg bara behöver arkitekturen eller filmappen, cacha en sammanfattning. Sammanfattningen kostar färre token, men den kan utelämna den enda rad som den slutliga planen behöver.

Kan Batch-API:t köra denna agent?

Inte av sig själv. Batch-API:t skickar individuella Messages-förfrågningar; det kör inte denna klientsides verktygsslinga. Jag skulle använda det för självständiga repo-granskningar när liveframsteg inte krävs. Att köra hela loopen i batchar kräver din egen kod för att bearbeta ett batchs verktygsförfrågningar innan nästa skickas.

Ämnen

Lär dig AI med DataCamp!

track

Associate AI Engineer för utvecklare

26 timmar
Lär dig hur du integrerar AI i mjukvaruapplikationer med hjälp av API:er och bibliotek med öppen källkod. Börja din resa mot att bli AI Engineer idag!
Se detaljerRight Arrow
Starta Kursen
Se merRight Arrow