Lernpfad
Wenn ich ein neues Modell per API aufrufe, sagt mir die erste Antwort fast nichts. Mein erster Lauf mit Fable 5.1 lieferte eine gültige Struktur und einen generischen Plan. Mich interessierte, was passiert, wenn die Unterhaltung wächst: Kann die Anwendung ihre Historie intakt halten, Dateien prüfen, ohne außerhalb des Projekts zu lesen, Fortschritt melden und zeigen, wo die Kosten herkommen?
Unser Überblick zu Claude Fable 5.1 behandelt den Launch, Benchmarks und breitere Modellvergleiche. Hier starten wir mit einem kleinen Python-Call und bauen den Agentenloop darum herum. Der finale Agent nimmt eine Feature-Anfrage entgegen, liest ein Flask-Projekt und liefert einen Plan zurück, der an Dateien gebunden ist, die er tatsächlich inspiziert hat.
Wir schauen uns an, wie du:
- Einen Claude Fable 5.1 API-Call machst und Inhaltsblöcke sicher ausliest
- Den Reasoning-Aufwand setzt und mitten im Gespräch änderst (Beta)
- Eine Systemanweisung auf eine einzelne Runde begrenzt (Beta)
- Einen strukturierten Plan mit Pydantic zurückgibst
- Read-only-Repository-Tools mit Projektwurzel-Grenze hinzufügst
- Einen mehrstufigen Tool-Loop betreibst
- Die Fortschrittsupdates des Agenten zwischen Tool-Aufrufen liest (Beta)
- Thinking-Blöcke mit Append-only-Historie gültig hältst
- Wiederholten Kontext cachest und die Anfragekosten zu veröffentlichten Tarifen abschätzt
- Verweigerungen behandelst und den Agenten über FastAPI bereitstellst
Die Beta-Features nutzen datierte Header. Prüfe sie vor dem Go-live gegen die Anthropic-Dokumentation.
Einführung in Claude-Modelle
Was kostet es, Claude Fable 5.1 in einem Agentenloop auszuführen?
Ein Agent sendet in jeder Runde denselben System-Prompt, Tool-Definitionen und Repository-Kontext erneut. Entscheidend für deine Rechnung ist deshalb der Cache-Read-Tarif, nicht der Input-Tarif.
Fable 5.1 kostet 10 $ pro Million Input-Tokens und 50 $ pro Million Output-Tokens, unverändert gegenüber Fable 5. Cache-Reads kosten 0,25 $ pro Million (vorher 1 $), und Fünf-Minuten-Cache-Writes bleiben bei 12,50 $ pro Million. Unser Fable 5.1-Guide enthält die komplette Tarifübersicht und Anthonpics eigene Einsparschätzungen.
Einen gecachten Präfix zu lesen ist günstig. Ihn zu schreiben nicht: Er kostet das 50-Fache eines Reads. Der Loop zahlt sich also erst aus, wenn ein Präfix mehrfach gelesen wird. Die spätere Kostenaufschlüsselung zeigt ein Realbeispiel und welche Kategorie tatsächlich überwog.
Die Token-Grenzen kommen vom Modell, nicht von deinem Budget. Fable 5.1 bietet dir ein Kontextfenster von 1 Mio. Tokens mit bis zu 128 K Output-Tokens pro Antwort, und max_tokens ist ein hartes Limit für Denken plus Antworttext zusammen. Bei hohem Aufwand brauchst du Luft für beides, daher setzt der Agentenloop unten 16.000 statt einer „runden“ Zahl.
Datenaufbewahrung, Prioritätsstufe und Wasserzeichen
Einige Zugangsdetails sind wichtig, bevor du Code schreibst. Zwei davon blockieren Anfragen direkt:
-
Fable 5.1 erfordert 30-tägige Datenaufbewahrung und ist mit Zero Retention nicht verfügbar, außer Anthropic schaltet es frei. Eine Anfrage aus einem inkompatiblen Workspace liefert einen 400-
invalid_request_errorohne weiteren Hinweis. -
Das Modell wird auf Priority Tier nicht unterstützt. Fable 5 schon, was beim Umstieg oft überrascht.
-
Fable 5.1-Textausgaben tragen Anthropics Textwasserzeichen. Es erzeugt keine Tokens und erfordert keine Änderungen an der Anfrage.
Claude Fable 5.1 per API nutzen, um einen repository-bewussten Entwickleragenten zu bauen
Unser Workflow hat zwei Phasen:
- Ein begrenzter Inspektionsloop liest erlaubte Projektdateien.
- Eine finale Anfrage mit strukturierten Ausgaben verwandelt diesen Kontext in einen Plan.
Das Beispielprojekt ist eine kleine Flask-JSON-API zum Speichern und Suchen von Bookmarks, mit App-Factory, drei Blueprints, einem Config-Modul, Modellen und einer Pytest-Suite. Ich nutze Rate Limiting als laufende Aufgabe, weil der Agent App-Setup, Routen, Config und Tests inspizieren muss, bevor er die nötigen Dateien und Tests bestimmen kann. Vollständiger Code und Projekt findest du im GitHub-Repository.

Anfragen erreichen Dateien durch eine einzige Grenze. Bild: Autor.
Der Agent darf nur drei Tools nutzen: list_project_files, read_project_file und get_project_metadata. Claude greift nie direkt auf das Dateisystem zu. Es fragt nach einem Pfad, und dein Code entscheidet, ob der Pfad erlaubt ist.
Einrichtung der Claude Fable 5.1 API in Python
Starte mit einer separaten Python-Umgebung und bewahre den API-Schlüssel auf dem Server auf.
Voraussetzungen
Du brauchst Python 3.10 oder neuer und einen Anthropic API-Schlüssel mit Zugriff auf claude-fable-5-1.
Um einen API-Schlüssel zu erstellen, melde dich in der Claude Console an, öffne die API-Keys-Seite, klicke auf Create key und kopiere den Schlüssel. Gib ihm am besten einen sprechenden Namen, wähle ein Ablaufdatum und lagere den Schlüssel sicher.
SDK installieren und API-Key hinzufügen
Erstelle eine virtuelle Umgebung und installiere die Pakete:
python -m venv .venv
source .venv/bin/activate # macOS oder Linux
.venv\Scripts\Activate.ps1 # Windows PowerShell
pip install anthropic==1.3.0 pydantic fastapi uvicorn python-dotenv
Pinne das SDK, da sich Beta-Features häufig ändern. Fortschrittsupdates benötigen mindestens 1.1.0, die Beispiele nutzen 1.3.0.
Lege den Schlüssel in eine .env-Datei und füge .env vor dem ersten Commit zu .gitignore hinzu. Er gehört auf einen Server unter deiner Kontrolle, niemals in den Browser oder ein zugängliches Repository. Ein geleakter Schlüssel kann unautorisierte API-Nutzung und Kosten über Input, Output und Cache auslösen.
ANTHROPIC_API_KEY=sk-ant-your-key-here
Damit findet der Client den Schlüssel automatisch.
Deinen ersten Claude Fable 5.1 API-Call in Python machen
Sende die kleinstmögliche API-Anfrage, bevor du etwas darauf aufbaust.
Die erste API-Anfrage senden
Initialisiere den Client, sende eine User-Nachricht und gib die Response-Metadaten aus:
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}")

Erster Call liefert Text plus Metadaten. Bild: Autor.
Der next(...)-Aufruf wählt den ersten Textblock. Adaptive Thinking ist immer aktiv und kann nicht deaktiviert werden, daher kann eine Antwort mit einem Thinking-Block beginnen; thinking: {"type": "disabled"} zu senden führt zu 400 statt zur Deaktivierung. Wenn ein Thinking-Block zuerst kommt, wirft response.content[0].text eine Exception.
Lös die Reihenfolge-Annahme auf, indem du nach Block-Typ filterst. Logge auch response._request_id, da der Anthropic-Support sie zur Nachverfolgung nutzt.
Hier ist die Anfrage, die ich in den Planungs- und Aufwandsbeispielen nutze. Sie verlangt, dass der Agent mehrere Dateien prüft:
feature_request = (
"Add rate limiting to the public API endpoints so one client cannot exhaust "
"the search endpoint or brute force the token endpoint."
)
Lass diesen Text unverändert, wenn du Aufwand und Token-Zahlen vergleichst. So beschreiben die Ergebnisse die API-Einstellungen und nicht einen anderen Prompt.
Reasoning-Aufwand mit output_config setzen
Setze den Reasoning-Aufwand über output_config. Er akzeptiert low, medium, high, xhigh und max. Der API-Standard ist high.
response = client.messages.create(
model=MODEL,
max_tokens=8192,
output_config={"effort": "high"},
messages=[{"role": "user", "content": feature_request}],
)
Aufwand kann Tokenverbrauch, Tool-Verhalten und Latenz beeinflussen. Ich habe dieselbe Feature-Anfrage dreimal auf vier Aufwandsstufen laufen lassen; die Tabelle zeigt die Mittelwerte:
|
Aufwand |
Sekunden |
Thinking-Tokens |
Output-Tokens gesamt |
Kosten |
|---|---|---|---|---|
|
|
7,7 |
111 |
173 |
$0.0093 |
|
|
8,1 |
129 |
186 |
$0.0099 |
|
|
7,9 |
136 |
199 |
$0.0106 |
|
|
20,0 |
151 |
1.764 |
$0.0888 |
Thinking-Tokens sind in den Output-Tokens enthalten. Addiere sie also nicht. In diesen Läufen blieben low, medium und high bei Latenz und Kosten nah beieinander.
xhigh dauerte zweieinhalbmal so lang, erzeugte fast neunmal so viele Output-Tokens und kostete das Achtfache.
Fazit: Starte mit high, senke bei Routine-Schritten auf medium und nutze höhere Stufen nur, wenn deine Tests messbar bessere Ergebnisse zeigen. Bei low kann das Modell aus dem Gedächtnis antworten, statt ein Retrieval-Tool zu nutzen. Wenn eine Runde frische Informationen braucht, sag es oder erhöhe den Aufwand.
Den Scope des Agenten mit einem System-Prompt einschränken
Der System-Prompt definiert das Verhalten des Agenten:
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 Prompting-Leitfaden weist darauf hin, dass das Modell die Aufgabe ausweiten oder zu früh stoppen kann. Der Prompt hält es im Scope und fordert ein konkretes Abschlussbriefing. Das Ausgabeformat übernimmt später ein Schema.
Einen strukturierten Plan mit Pydantic zurückgeben
Definiere den Plan mit Pydantic, damit deine Anwendung ihn validieren und an anderen Code weitergeben kann:
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() wandelt das Pydantic-Modell in ein JSON-Schema, sendet es, validiert die Antwort und liefert ein typisiertes Objekt in parsed_output. Strukturierte Ausgaben sind allgemein verfügbar, es ist also kein Beta-Header nötig. Prüfe zuerst stop_reason, denn eine Verweigerung, weiter unten erklärt, umgeht das Schema und hinterlässt nichts zum Parsen.
Das generische Ergebnis aus der Einleitung machte eines richtig: Es nannte keine Dateien, die es nicht sehen konnte. Ein Schema validiert Struktur, nicht die inhaltliche Fundierung.
Claude Fable 5.1 vs. Fable 5: API-Migrationsänderungen
Bevor du Tools hinzufügst, berücksichtige erzwungene Tool-Einschränkungen, Thinking-Block-Kompatibilität und Append-only-Historie.
-
Fable 5.1 lehnt erzwungene Tool-Auswahl ab. Der Tool-Loop unten zeigt den Fehler und die
auto-Konfiguration als Ersatz. -
Thinking-Blöcke sind nur in eine Richtung kompatibel. Fable 5.1 liest Blöcke früherer Claude-Modelle, aber kein früheres Modell liest seine Blöcke.
Wenn ein Router oder Fallback das Gespräch auf ein älteres Modell verlegt, entfernt die API die inkompatiblen Blöcke, bevor das Zielmodell sie sieht. Der Rest der Historie bleibt, aber das ältere Modell plant ohne diese Blöcke.
Das Bearbeiten früherer Runden macht nachfolgende Thinking-Blöcke ungültig. Das kann History-Trimming und Client-seitige Zusammenfassungen stören.
Der Migrationsleitfaden deckt alle Änderungen ab.
Read-only-Repository-Tools hinzufügen
Gib dem Modell jetzt Repository-Kontext über Read-only-Tools.
Die Read-only-Tools definieren
Die Tool-Schicht hat zwei Teile: die Python-Funktionen, die Zugriffsregeln durchsetzen, und die Schemas, die Claude aufrufen kann.
Pfade auf die Projektwurzel beschränken
Read-only ist nicht automatisch sicher. Ein Modell kann genauso ../../.env wie config.py anfragen, daher gehört die Absicherung in deinen Code – nicht in den 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
Lehne absolute Pfade und Symlink-Komponenten ab, löse den Pfad auf und bestätige, dass er unter der Projektwurzel bleibt. Die Anfrage ../.env ergibt „path is outside the project root“. Der Tool-Fehler erlaubt dem Agenten, mit erlaubten Dateien fortzufahren.
Strikte Tool-Schemas definieren
Die Reader-Klasse steuert, was Python öffnen darf. Claude braucht außerdem JSON-Schemas, die die drei Aktionen beschreiben:
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 prüft die Argumente, wenn das Modell ein Tool wählt. Es erzwingt keinen Tool-Call – wichtig bei Fable 5.1.
Den mehrstufigen Tool-Loop ausführen
Starte mit dem Basisloop: Tools senden, stop_reason prüfen, Ausgefordertes ausführen, Ergebnisse anhängen, wiederholen.
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 begrenzt Modell-Anfragen, nicht Ausgaben. Erzwinge bei Bedarf zusätzlich ein Kostenlimit. Der Loop behandelt refusal, max_tokens und tool_use direkt; andere Stop-Reasons beenden die Inspektionsphase. Das Feld is_error signalisiert dem Modell, dass ein Pfad abgelehnt wurde, damit es eine Alternative wählen kann.
Warum erzwungene Tool-Wahl einen 400er liefert
Unter Fable 5 konntest du den ersten Call mit tool_choice: {"type": "any"} erzwingen. Fable 5.1 liefert diesen Fehler, bevor die Anfrage ausgeführt wird:
tool_choice: type "tool" and "any" are not supported for this model.
Erzwungene Aufrufe würden das stets aktive Thinking überspringen. Lass tool_choice auf auto, nutze die strikten Schemas oben, und nenne Tools im Prompt, wenn ein Schritt eines braucht.
Fable 5.1 ruft teils nur ein Tool pro Runde auf, während Fable 5 mehrere bündelte. Das erzeugt mehr Round-Trips. Füge diese Zeile in den Prompt ein: „Fordere unabhängige Dateien in derselben Runde an statt jeweils einzeln“. Ein Beispieldurchlauf bündelte neun unabhängige Dateianfragen, die Anzahl variiert jedoch.
Claude Fable 5.1 Antworten und Fortschritt streamen
Text-Streaming liefert Inhalte, während sie generiert werden; Fortschrittsupdates decken Pausen zwischen Tool-Aufrufen ab.
Textantworten streamen
Das vollständige Projekt nutzt context_system() , um SYSTEM_PROMPT mit einer Projektzusammenfassung zu kombinieren, bevor der Stream startet:
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() liefert dir nach dem Drain den zusammengesetzten Message-Block mit Usage und Stop-Reason. Streaming-Chunks müssen kein vollständiges JSON enthalten, warte daher mit dem Parsen auf die Final-Message.
Fortschritt zwischen Tool-Aufrufen anzeigen
Text-Streaming deckt Verzögerungen während Tool-Aufrufen nicht ab. Fable 5.1 kann vor Tool-Aufrufen kurze Fortschrittsupdates schreiben. Unter dem Standard thinking.display von "omitted" bleiben die progress-spezifischen Thinking-Blöcke leer, auch wenn das Modell einen normalen Texteinstieg schreiben kann.
Mit display: "updates" und dem Beta-Header thinking-display-updates-2026-08-18 definiert die API-Doku ein lesbares Fortschrittsupdate als nichtleeren thinking-Block bei verborgenem Reasoning. In meinen Läufen blieb thinking leer und der lesbare Status kam als normaler text -Block direkt vor tool_use. Der Helper prüft daher beide Blocktypen, und der Loop ruft ihn nur in Runden auf, die mit tool_use enden:
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
Die Fortschrittsmeldungen beschreiben die Dateien, die das Modell lesen will: „Ich lese die App-Verdrahtung, Config, Extensions, die Public- und Auth-Routen sowie die vorhandenen Tests, denn dort würde Rate Limiting andocken.“ Zeige diese Nachrichten an und ignoriere leere Blöcke.

Agent liest Dateien und meldet Fortschritt. Bild: Autor.
Fable 5.1 schreibt davon weniger als Fable 5, besonders bei höherem Aufwand. Wenn deine Oberfläche regelmäßige Updates braucht, bitte um eine Eröffnungszeile, Fortschrittsmeldungen und ein Abschluss-Recap.
Claude Fable 5.1 Aufwand mitten im Gespräch ändern
Das nächste Feature ist ziemlich elegant. Wie wir wissen, braucht der Repository-Agent nicht in jeder Runde dieselbe Reasoning-Tiefe.
Aufwand zwischen Runden ändern
Senke im Agentenloop den Aufwand für Routine-Retrieval und erhöhe ihn für die finale Planungsrunde.
Mit dem Beta-Header mid-conversation-output-config-2026-07-01 kannst du eine Systemnachricht anhängen, die nur die Aufwandsstufe ändert:
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,
)
Die neue Stufe gilt ab der nächsten User-Runde, nicht innerhalb der laufenden Runde, und sie macht den Prompt-Cache nicht ungültig. Das Ändern von output_config.effort auf Top-Level zwischen Anfragen hingegen schon.
Der Agent behält die Top-Level-Einstellung high, hängt vor Routine-Retrieval eine per-Message-Direktive medium an und vor dem finalen Plan wieder high. Ein Paarvergleich ergab 18 Output-Tokens bei niedrigerem Aufwand vs. 76 zuvor. Werte dies als Beispiel, nicht als Erwartungswert.
Eine Systemanweisung nur für eine Runde anwenden
Nutze eine rundenbegrenzte Anweisung, um während der finalen Planung weitere Dateilesen zu blockieren.
Setze clear_at: "next_user_message" auf eine Systemnachricht mit dem Beta-Header mid-conversation-system-clear-at-2026-08-21. Die API behandelt ihren Text in dieser Runde als Systeminstruktion und rendert ihn nach der nächsten User-Nachricht nicht mehr. In messages bleibt sie erhalten, sodass die frühere Historie unverändert bleibt, der Cache weiter matched und die gelöschte Nachricht keine Input-Tokens kostet.
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"} verhindert, dass der finale Request weitere Tools aufruft. Die Scoped-Instruktion begrenzt den Plan auf Dateien, die der Agent bereits inspiziert hat. Füge keine Erinnerung ein und lösche sie in der nächsten Anfrage. Diese Bearbeitung macht spätere Thinking-Blöcke ungültig.
Claude Fable 5.1 Thinking-Block-400-Fehler beheben
Ein Fehler The block is bound to a different conversation bedeutet, dass sich die Historie vor einem Thinking-Block geändert hat. Jeder Fable 5.1-Thinking-Block ist exakt an System-Prompt, Tool-Definitionen und vorangehende Messages gebunden.
Das Ergebnis hängt vom Erstellungsdatum deines Accounts ab.
-
Accounts ab dem 31. August 2026 erhalten einen 400er, der sagt, der Block sei an eine andere Unterhaltung gebunden.
-
Bei älteren Accounts zeichnet die API das Mismatch auf, handelt aber erst, wenn die Anfrage
thinking.block_binding.prefix_mismatch_behaviorsetzt.
Du kannst das mit dem Beta-Header thinking-binding-controls-2026-08-01, thinking.block_binding.prefix_mismatch_behavior auf "drop_block" und dem Array input_transformations erkennen. Eine bearbeitete Historie erscheint als reason: "prefix_binding_mismatch". Führe diesen Check einmal gegen deine Integration aus.
Folgende Operationen lösen das Mismatch aus:
-
Bearbeiten, Umordnen oder Entfernen einer früheren Runde bei Beibehaltung späterer
-
Pro-Anfrage-Text in eine frühere Runde injizieren und in der nächsten wieder entfernen
-
Ändern von Inhalt oder Reihenfolge des Top-Level-
system-Prompts oder destools-Arrays mitten im Gespräch -
Spätere Anfragen liefern andere Bytes für ein Bild- oder Dokument-URL
Dafür gibt es Alternativen, die die Bindungen intakt halten:
-
Füge Anweisungen mit Mid-Conversation-Systemnachrichten hinzu statt
systemzu bearbeiten. -
Ändere Tools mit Mid-Conversation-Tool-Changes statt das Top-Level-Array zu ändern.
-
Kürze Historie mit serverseitigem Context Editing oder Compaction, die nicht als Edits zählen.
-
Gib Thinking-Blöcke unverändert zurück.
Das Verschieben von cache_control Markern und das Ändern des Request-Level-Aufwands sind sicher und machen Thinking-Block-Bindungen nicht ungültig. Das Ändern des Top-Level-Aufwands startet jedoch das Prompt-Caching neu. Nutze daher per-Message-Aufwand, wenn der gecachte Präfix bestehen bleiben soll.
Prompt-Caching und Claude Fable 5.1 API-Kosten
Der folgende Lauf trennt frischen Input, Cache-Writes, Cache-Reads und Output-Kosten.
Automatisches Prompt-Caching hinzufügen
Prompt-Caching senkt die Kosten für Kontext, der sich über Runden wiederholt. Da die wachsende Historie den Breakpoint verschiebt, passt automatisches Caching hier besser.
Ein Top-Level-cache_control-Feld verschiebt den Breakpoint auf jeden Request zum letzten cachebaren Block:
response = client.beta.messages.create(
model=MODEL,
cache_control={"type": "ephemeral"},
system=system,
tools=TOOLS,
messages=messages,
# Other request fields...
)
Ein cachebarer Präfix unter 512 Tokens wird in Fable 5.1 nicht gecacht, selbst wenn er mit cache_control markiert ist. Die API verarbeitet ihn normal und liefert bei beiden Cache-Zählern null. Das Schreiben eines Präfixes mit 583 Tokens kostete 0,0073 $, das Lesen in der nächsten Runde 0,00015 $. Die zweite Runde musste ihren neuen Teil trotzdem in den Cache schreiben – ein Cache-Hit eliminiert also nicht alle Input-Kosten.
Cache-bewusste API-Kosten schätzen
response.usage meldet frischen Input, Cache-Erstellung, Cache-Reads und Output getrennt. Bepreise alle vier Zähler einzeln; nur Input und Output zu addieren verschleiert Cache-Writes und überschätzt Cache-Reads.
Hier ist die Kostenaufschlüsselung eines vollständigen Laufs, der über drei Runden 12 Dateien las und einen finalen Plan erzeugte:
|
Posten |
Tokens |
Geschätzte Kosten |
Anteil |
|---|---|---|---|
|
Output |
5.713 |
$0.2857 |
59,4% |
|
Cache-Writes |
15.426 |
$0.1928 |
40,1% |
|
Frischer Input |
50 |
$0.0005 |
0,1% |
|
Cache-Reads |
6.549 |
$0.0016 |
0,3% |
|
Summe |
27.738 |
$0.4806 |
100% |
Cache-Reads machten hier weniger als ein halbes Prozent aus. Zu Fable 5s alten Tarifen hätte der Lauf etwa 0,4855 $ statt 0,4806 $ gekostet. Die Einsparungen wachsen, wenn jede Runde deutlich mehr Kontext wiederverwendet.
In diesem Lauf entfielen knapp 60% auf Output und rund 40% auf Cache-Writes. Beim Fünf-Minuten-Tarif kostet ein Cache-Write-Token das 50-Fache eines Cache-Read-Tokens. Bei einer Stunde kostet der Write das 80-Fache.
Claude Fable 5.1 Verweigerungen und Fallbacks behandeln
Eine Verweigerung und eine fehlgeschlagene Anfrage erfordern unterschiedliches Anwendungsverhalten.
Verweigerungen vor dem Parsen erkennen
Eine Verweigerung vor Output kommt als HTTP 200 mit stop_reason: "refusal", leerem Inhalt und stop_details. Die Kategorie kann null sein. Eine spätere Verweigerung im Stream kann nach Teil-Output kommen, den die Anwendung verwerfen sollte. Ein try/except um den Call fängt keinen dieser Fälle.
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})."
Behandle es als Anwendungszustand. Wenn eine erlaubte Anfrage unklar ist, schreibe sie präziser. Baue keine Retry-Logik, deren Zweck es ist, den Klassifizierer zu umgehen.

Eine Verweigerung kommt als HTTP 200. Bild: Autor.
Serverseitiges Fallback konfigurieren
Serverseitiges Fallback kann eine abgelehnte Anfrage auf einem anderen Modell erneut versuchen, mit fallbacks: "default" und dem Beta-Header server-side-fallback-2026-07-01. Erlaubte Ziele für Fable 5.1 sind Opus 4.8 und Opus 5.
Default-Fallback greift nur, wenn die Verweigerungskategorie ein empfohlenes Ziel hat. Eine getestete reasoning_extraction -Verweigerung löste kein Fallback aus. Prüfe usage.iterations statt anzunehmen, jede Verweigerung führe zu einem Retry. Wie erwähnt, gehen beim Wechsel auf ein älteres Modell Fable 5.1-Thinking-Blöcke verloren.
Den Claude Fable 5.1 Agenten mit FastAPI bereitstellen
Der lokale Agent kann denselben Workflow jetzt über eine HTTP-API bereitstellen.
Den Plan-Endpunkt erstellen
Wenn du nur ein lokales Skript brauchst, überspringe diesen Abschnitt. Für einen Web-Service nutze FastAPI mit AsyncAnthropic. Erstelle einen Client pro Prozess in einem Lifespan-Handler. Importiere Schema und Prompts aus dem bestehenden Agentenmodul.
@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))
Beachte: Der Aufrufer sendet einen Projektnamen, keinen Pfad. resolve_project() mappt ihn auf einen kleinen Satz erlaubter Wurzeln, sodass keine beliebigen Serverpfade gelesen werden können. Dieser Service mappt Verweigerungen auf 422 – eine Anwendungsentscheidung. Die Claude-API selbst liefert sie als HTTP 200.
Starte mit uvicorn app:app --reload. Die interaktive Doku findest du unter http://localhost:8000/docs.
Endpoint liefert einen Plan mit geschätzten Kosten. Video: Autor.
Der /plan/stream-Endpunkt führt die Inspektion in einem Hintergrundtask aus, legt Fortschritt und Tool-Events auf eine asyncio.Queue und streamt sie über StreamingResponse. Wenn der Stream endet, stoppt der Generator den Background-Task. Die Streamlit-Oberfläche im Repository rendert denselben Event-Stream.
Streamlit zeigt den Live-Fortschritt des Agenten. Video: Autor.
Claude Fable 5.1 Agent Deployment Checkliste
Die zuvor eingebauten Limits und Checks bleiben Teil des Services. Vor dem Deployment ergänze die betrieblichen Bausteine, die lokal nicht sichtbar sind.
-
Prüfe die zwei Standard-Retries des SDKs für 429- und 5xx-Responses und setze
max_retriessowie Timeouts passend zum Latenzbudget des Services -
Setze ein Request-Timeout und bestätige, dass das bestehende SSE-Task-Canceling laufende Arbeit beendet, wenn der Client trennt
-
Logge Modell-ID, SDK-Version, Request-ID, Stop-Reason und alle vier Token-Kategorien pro Lauf
-
Alarme bei steigenden Cache-Writes, Output-Tokens, Verweigerungen und Läufen, die das Turn-Cap erreichen
-
Bestätige, dass die Retention-Einstellung des Accounts zur Modellanforderung passt
-
Pinne das SDK und prüfe die Beta-Header vor jedem Release erneut
Wann Claude Fable 5.1 statt Opus 5 oder Sonnet 5 nutzen?
- Anthropic empfiehlt Opus 5 als vernünftigen Standard.
- Teste Fable 5.1, wenn Opus 5 bei langer Repository-Analyse, schwierigem Debugging oder agentischen Aufgaben mit großem Kontext schwächelt.
- Für Repository-Arbeit und Alltagsaufgaben vergleiche Sonnet 5 und Opus 5 bei Qualität, Latenz und Kosten.
- Für Klassifikation, Extraktion, kurze Antworten und einfachere Anfragen ist Sonnet 5 eine gute Wahl; für ganz einfache Aufgaben reicht oft auch Haiku 4.5.
Wähle Fable 5.1 nicht nur, weil es neuer ist. Eine einzelne Anfrage kann weiterhin Aufwand und strukturierte Ausgaben nutzen; Streaming funktioniert auch. Vom Loop oder dem hier genutzten Repeated-Prefix-Caching profitiert sie nicht.
Abschließende Gedanken
Der generische Plan aus meinem ersten Call wurde erst nützlich, nachdem der Agent das Repository gelesen hatte. Im finalen Lauf inspizierte er in drei Runden 12 Dateien, während Output und Cache-Writes 99,5% der geschätzten Kosten ausmachten. Ich würde die Pfadgrenze und die Append-only-Historie beibehalten und testen, ob geringerer Aufwand Kosten senkt, ohne dass das Modell Repository-Tools auslässt.
Wenn eine Antwort die Aufgabe allein lösen kann, bleib bei strukturierten Ausgaben. Nutze den Tool-Loop, wenn die Antwort von Repository-Dateien abhängen oder Fortschritt zwischen Aufrufen berichten muss.
Für Details zur Modellwahl empfehle ich unseren Kurs Introduction to Claude Models. Für Prompting und Agent-Workflows sieh dir unseren Kurs Software Development with Cursor an.
FAQs
Kann Claude Fable 5.1 neben Code auch Bilder lesen?
Ja. Es akzeptiert Bildinput und kann Charts und PDFs lesen. Ich habe Vision im Hauptbeispiel weggelassen, weil der Repository-Plan es nicht braucht. Würde ich den Agenten für eine UI-Änderung erweitern, würde ich den aktuellen Screenshot mit der Feature-Anfrage senden. Skaliere ihn vorher herunter, wenn kleine Details nicht relevant sind.
Warum wurde mein Agent nach dem Wechsel von Fable 5 langsamer?
Prüfe zuerst die Tool-Ergebnisse, bevor du das Modell verantwortlich machst. Wenn die Bündelungsanweisung von oben schon enthalten ist, vergleiche Anzahl und Größe der Dateien. Der aktuelle Reader deckelt jede Datei bei 40.000 Bytes. Wenn das zu groß ist, füge Zeilenbereich- oder Suchargumente hinzu, damit das Tool nur relevante Abschnitte zurückgibt.
Warum liefert Claude Fable 5.1 einen 400 invalid_request_error?
Bitte nicht sofort erneut versuchen. Ein invalid_request_error deutet meist auf eine Form der Anfrage oder eine Konto-Einstellung hin, die geändert werden muss. In diesem Projekt sind wahrscheinliche Ursachen erzwungenes tool_choice, eine inkompatible Retention-Einstellung, ein bearbeiteter Präfix bei erhaltenem Thinking oder ein Beta-Feld ohne passenden Header. Behebe die Ursache und sende dann erneut.
Sollte ich Quelldateien oder eine Zusammenfassung cachen?
Meine Regel: Cache Quelltexte, wenn exakter Code über mehrere Runden wichtig ist. Wenn spätere Schritte nur Architektur oder Dateikarte brauchen, cache eine Zusammenfassung. Die ist günstiger, kann aber genau die eine Zeile weglassen, die der finale Plan benötigt.
Kann die Batch-API diesen Agenten ausführen?
Nicht allein. Die Batch-API schickt einzelne Messages-Requests; sie führt nicht diesen Client-seitigen Tool-Loop aus. Ich würde sie für abgeschlossene Repository-Reviews nutzen, wenn kein Live-Fortschritt nötig ist. Den vollständigen Loop in Batches zu fahren, erfordert eigenen Code, der die Tool-Anfragen eines Batches verarbeitet, bevor der nächste gesendet wird.
Ich bin Dateningenieur und Community-Builder und arbeite mit Datenpipelines, Cloud- und KI-Tools. Außerdem schreibe ich praktische, super nützliche Tutorials für DataCamp und angehende Entwickler.

