Track
जब मैं किसी नए मॉडल को API कॉल से आज़माता हूँ, तो पहली प्रतिक्रिया बहुत कम बताती है। मेरे पहले Fable 5.1 रन ने एक वैध संरचना और एक सामान्य योजना लौटाई। मैं जानना चाहता था कि बातचीत बढ़ने के बाद क्या होता है: क्या एप्लिकेशन अपना इतिहास जस का तस रख सकता है, प्रोजेक्ट के बाहर पढ़े बिना फाइलें देख सकता है, प्रगति रिपोर्ट कर सकता है, और यह दिखा सकता है कि लागत कहाँ से आई?
हमारा Claude Fable 5.1 ओवरव्यू लॉन्च, बेंचमार्क, और व्यापक मॉडल तुलना को कवर करता है। यहाँ, हम एक छोटे Python कॉल से शुरू करेंगे और उसके आसपास एजेंट लूप बनाएँगे। अंतिम एजेंट एक फीचर रिक्वेस्ट लेता है, एक Flask प्रोजेक्ट पढ़ता है, और उन फाइलों से बंधी एक योजना लौटाता है जिन्हें उसने वास्तव में निरीक्षण किया।
हम यह कवर करेंगे:
- Claude Fable 5.1 API कॉल करें और कंटेंट ब्लॉक्स को सुरक्षित रूप से पढ़ें
- रीज़निंग effort सेट करें, और बातचीत के बीच में बदलें (बीटा)
- एक सिस्टम निर्देश को एक ही टर्न तक सीमित करें (बीटा)
- Pydantic के साथ एक संरचित योजना लौटाएँ
- प्रोजेक्ट रूट सीमा के साथ read-only रिपॉजिटरी टूल्स जोड़ें
- मल्टी-टर्न टूल लूप चलाएँ
- टूल कॉल्स के बीच एजेंट की प्रगति अपडेट पढ़ें (बीटा)
- append-only इतिहास के साथ thinking ब्लॉक्स को वैध रखें
- दोहराए गए संदर्भ को कैश करें और प्रकाशित दरों पर रिक्वेस्ट लागत का अनुमान लगाएँ
- refusals हैंडल करें और एजेंट को FastAPI के माध्यम से एक्सपोज़ करें
बीटा फीचर्स तिथि-युक्त हेडर्स का उपयोग करते हैं, इसलिए शिप करने से पहले उन्हें Anthropic के दस्तावेज़ों से मिला लें।
एजेंट लूप में Claude Fable 5.1 चलाने की लागत कितनी है?
एजेंट हर टर्न पर वही सिस्टम प्रॉम्प्ट, टूल डेफिनिशन, और रिपॉजिटरी संदर्भ फिर से भेजता है, इसलिए आपकी बिलिंग तय करने वाली दर इनपुट नहीं बल्कि cache read होती है।
Fable 5.1 की लागत प्रति मिलियन इनपुट टोकन $10 और प्रति मिलियन आउटपुट टोकन $50 है, जो Fable 5 से अपरिवर्तित है। Cache reads की लागत प्रति मिलियन $0.25 है, जो $1 से कम हुई है, और पाँच मिनट के cache writes प्रति मिलियन $12.50 ही रहते हैं। हमारी Claude Fable 5.1 गाइड में पूरी दर तालिका और Anthropic के अपने savings अनुमान हैं।
कैश किए गए प्रीफिक्स को पढ़ना सस्ता है। उसे लिखना नहीं—रीड रेट से 50 गुना—इसलिए लूप तभी फायदेमंद होता है जब प्रीफिक्स कई बार पढ़ा जाए। आगे की लागत ब्रेकडाउन दिखाती है कि वास्तविक रन में यह कैसे बैठा, और कौन-सी श्रेणी ने वास्तव में दबदबा बनाया।
टोकन सीमा मॉडल से आती है, आपके बजट से नहीं। Fable 5.1 आपको 1M-टोकन का कॉन्टेक्स्ट विंडो देता है, प्रत्येक प्रतिक्रिया में अधिकतम 128K आउटपुट टोकन तक, और max_tokens सोच और रिस्पॉन्स टेक्स्ट दोनों पर संयुक्त सख्त सीमा है। उच्च effort पर आपको दोनों के लिए जगह चाहिए, इसलिए नीचे दिया गया एजेंट लूप 16,000 सेट करता है, न कि कोई गोल संख्या।
डेटा रिटेंशन, प्रायोरिटी टियर, और वॉटरमार्किंग
कोड लिखने से पहले कुछ एक्सेस विवरण मायने रखते हैं। उनमें से दो आपकी रिक्वेस्ट्स को सीधे रोक देंगे:
-
Fable 5.1 को 30-दिन का डेटा रिटेंशन चाहिए और यह शून्य रिटेंशन पर उपलब्ध नहीं है जब तक Anthropic एक्सेस अधिकृत न करे। असंगत वर्कस्पेस से आने वाली रिक्वेस्ट 400
invalid_request_errorलौटाती है बिना किसी और संकेत के। -
यह मॉडल Priority Tier पर सपोर्टेड नहीं है। Fable 5 है, इसलिए माइग्रेट करते समय यह लोगों को पकड़ लेता है।
-
Fable 5.1 टेक्स्ट आउटपुट Anthropic का टेक्स्ट वॉटरमार्क वहन करता है। यह कोई टोकन नहीं जोड़ता और रिक्वेस्ट में बदलाव की ज़रूरत नहीं होती।
API के माध्यम से Claude Fable 5.1 का उपयोग कर रिपॉजिटरी-सचेत डेवलपर एजेंट बनाएं
हमारा वर्कफ़्लो दो चरणों में है:
- एक सीमाबद्ध निरीक्षण लूप अनुमत प्रोजेक्ट फाइलें पढ़ता है।
- structured outputs का उपयोग करते हुए अंतिम रिक्वेस्ट उस संदर्भ को एक योजना में बदलती है।
सैंपल प्रोजेक्ट एक छोटा Flask JSON API है जो बुकमार्क सेव और सर्च करने के लिए है, जिसमें एक ऐप फैक्टोरी, तीन ब्लूप्रिंट, एक कॉन्फ़िग मॉड्यूल, मॉडल्स, और एक pytest सूट है। मैं रनिंग टास्क के रूप में rate limiting का उपयोग करता हूँ क्योंकि एजेंट को आवश्यक फाइलें और टेस्ट्स पहचानने से पहले ऐप सेटअप, रूट्स, कॉन्फ़िग, और टेस्ट्स का निरीक्षण करना पड़ता है। पूरा कोड और सैंपल प्रोजेक्ट GitHub रिपॉजिटरी में उपलब्ध है।

रिक्वेस्ट्स एक ही सीमा के जरिए फाइलों तक पहुँचती हैं। चित्र: लेखक।
एजेंट केवल तीन टूल्स का उपयोग कर सकता है: list_project_files, read_project_file, और get_project_metadata। Claude कभी फाइल सिस्टम को सीधे एक्सेस नहीं करता। वह एक पाथ मांगता है, और आपका कोड तय करता है कि वह पाथ अनुमत है या नहीं।
Python में Claude Fable 5.1 API सेटअप करना
एक अलग Python एनवायरमेंट से शुरू करें और API कुंजी सर्वर पर रखें।
पूर्वापेक्षाएँ
आपको Python 3.10 या नया और claude-fable-5-1 तक पहुंच वाली Anthropic API कुंजी चाहिए।
API कुंजी बनाने के लिए, Claude Console में साइन इन करें, API keys पेज खोलें, Create key पर क्लिक करें, फिर कुंजी कॉपी करें। इसे ऐसा नाम देना बेहतर है जो इसके उद्देश्य को याद रखने में मदद करे, एक समाप्ति तिथि चुनें, और कुंजी को सुरक्षित रखें।
SDK इंस्टॉल करें और API कुंजी जोड़ें
वर्चुअल एनवायरमेंट बनाएं और पैकेज इंस्टॉल करें:
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
SDK को पिन रखें क्योंकि बीटा फीचर्स अक्सर बदलते हैं। प्रोग्रेस अपडेट्स के लिए कम से कम 1.1.0 चाहिए, और उदाहरणों में 1.3.0 का उपयोग किया गया है।
कुंजी को .env फाइल में रखें और पहले कमिट से पहले .env को .gitignore में जोड़ें। यह आपकी नियंत्रण वाली सर्वर पर रहनी चाहिए, कभी भी ब्राउज़र या एक्सेसिबल रिपॉजिटरी में नहीं। इसे उजागर करने से अनधिकृत API उपयोग और इनपुट, आउटपुट, और कैश ऑपरेशंस पर शुल्क लग सकते हैं।
ANTHROPIC_API_KEY=sk-ant-your-key-here
यह सेट होने के साथ, क्लाइंट स्वयं कुंजी ढूँढ लेता है।
Python में अपना पहला Claude Fable 5.1 API कॉल करें
कुछ भी बनाने से पहले, संभवतः सबसे छोटी API रिक्वेस्ट भेजें।
पहली API रिक्वेस्ट भेजें
क्लाइंट इनिशियलाइज़ करें, एक यूज़र मैसेज भेजें, और प्रतिक्रिया मेटाडेटा प्रिंट करें:
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}")

पहली कॉल टेक्स्ट और मेटाडेटा लौटाती है। चित्र: लेखक।
next(...) कॉल पहला टेक्स्ट ब्लॉक चुनती है। Adaptive thinking हमेशा ऑन रहता है और डिसेबल नहीं किया जा सकता, इसलिए प्रतिक्रिया thinking ब्लॉक से शुरू हो सकती है; thinking: {"type": "disabled"} भेजने पर इसे बंद करने के बजाय 400 लौटता है। जब सोचने वाला ब्लॉक पहले आता है, तो response.content[0].text एक exception उठाता है।
समाधान यह है कि निश्चित पोज़िशन मान लेने के बजाय ब्लॉक प्रकार के आधार पर फ़िल्टर करें। response._request_id भी लॉग करें, क्योंकि Anthropic सपोर्ट इसे रिक्वेस्ट ट्रेस करने के लिए उपयोग करता है।
यहाँ वे प्लानिंग और effort उदाहरणों में उपयोग की गई रिक्वेस्ट है। यह एजेंट को कई फाइलों का निरीक्षण करने की आवश्यकता बताती है:
feature_request = (
"Add rate limiting to the public API endpoints so one client cannot exhaust "
"the search endpoint or brute force the token endpoint."
)
effort लेवल और टोकन काउंट की तुलना करते समय उस टेक्स्ट को अपरिवर्तित रखें। तब परिणाम अलग प्रॉम्प्ट के बजाय API सेटिंग्स का वर्णन करते हैं।
output_config से reasoning effort सेट करें
output_config के माध्यम से reasoning effort सेट करें। यह low, medium, high, xhigh, और max स्वीकार करता है। API डिफॉल्ट high है।
response = client.messages.create(
model=MODEL,
max_tokens=8192,
output_config={"effort": "high"},
messages=[{"role": "user", "content": feature_request}],
)
effort टोकन उपयोग, टूल व्यवहार, और लेटेंसी को प्रभावित कर सकता है। मैंने उसी फीचर रिक्वेस्ट को चार effort लेवल्स में से प्रत्येक पर तीन बार चलाया; तालिका औसत दिखाती है:
|
Effort |
सेकंड |
Thinking टोकन |
कुल आउटपुट टोकन |
लागत |
|---|---|---|---|---|
|
|
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 |
थिंकिंग टोकन कुल आउटपुट टोकन में शामिल हैं, इसलिए दोनों कॉलम को जोड़ें नहीं। इन रनों में,low, medium, और high लेटेंसी और लागत में पास-पास रहे।
xhigh दो-ढाई गुना अधिक समय लगा, लगभग नौ गुना अधिक आउटपुट टोकन बनाए, और आठ गुना अधिक लागत आई।
सारांश: high से शुरू करें, रूटीन स्टेप्स के लिए medium पर गिराएँ, और केवल तब उच्च स्तरों का उपयोग करें जब आपके अपने टेस्ट मापनीय सुधार दिखाएँ। low effort पर, मॉडल रिट्रीवल टूल कॉल करने के बजाय मेमोरी से उत्तर दे सकता है। यदि किसी टर्न को ताज़ा जानकारी चाहिए, तो स्पष्ट करें या स्तर बढ़ाएँ।
सिस्टम प्रॉम्प्ट से एजेंट के दायरे को सीमित करें
सिस्टम प्रॉम्प्ट एजेंट के व्यवहार को परिभाषित करता है:
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."""
Anthropic की प्रॉम्प्टिंग गाइडेंस बताती है कि मॉडल टास्क को बढ़ा सकता है या बहुत जल्दी रुक सकता है। प्रॉम्प्ट इसे दायरे में रहने और ठोस मार्गदर्शन के साथ समाप्त करने के लिए कहता है। आउटपुट फ़ॉर्मेट बाद में एक स्कीमा संभालेगा।
Pydantic के साथ एक संरचित योजना लौटाएँ
Pydantic के साथ योजना परिभाषित करें ताकि आपका एप्लिकेशन इसे वैलिडेट कर सके और अन्य कोड को पास कर सके:
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() Pydantic मॉडल को JSON स्कीमा में बदल देता है, उसे भेजता है, जवाब को वैलिडेट करता है, और parsed_output पर एक typed ऑब्जेक्ट लौटाता है। संरचित आउटपुट सामान्यतः उपलब्ध हैं, इसलिए कोई बीटा हेडर शामिल नहीं है। पहले stop_reason जांचें क्योंकि एक refusal, जिसे आगे कवर किया गया है, स्कीमा को स्किप करता है और आपके पास पार्स करने के लिए कुछ नहीं छोड़ता।
परिचय से वह सामान्य परिणाम एक चीज़ सही करता था: उसने ऐसी फाइलों के नाम नहीं लिए जिन्हें वह देख नहीं सका। एक स्कीमा संरचना वैलिडेट करता है, तथ्यात्मक ग्राउंडिंग नहीं।
Claude Fable 5.1 बनाम Fable 5: API माइग्रेशन बदलाव
टूल्स जोड़ने से पहले, forced-tool प्रतिबंध, thinking-block संगतता, और append-only इतिहास को ध्यान में रखें।
-
Fable 5.1 forced टूल चयन को अस्वीकार करता है। नीचे दिए गए टूल-लूप सेक्शन में त्रुटि और प्रयुक्त
autoकॉन्फिगरेशन दिखाया गया है। -
Thinking ब्लॉक्स केवल एक दिशा में संगत हैं। Fable 5.1 पहले के Claude मॉडलों के ब्लॉक्स पढ़ता है, लेकिन कोई भी पुराना मॉडल इसके ब्लॉक्स नहीं पढ़ सकता।
जब कोई राउटर या फॉलबैक बातचीत को पुराने मॉडल पर ले जाता है, तो API लक्ष्य मॉडल को दिखाने से पहले असंगत ब्लॉक्स हटा देता है। बचा हुआ इतिहास यथावत रहता है, लेकिन पुराने मॉडल को उन ब्लॉक्स के बिना योजना बनानी पड़ती है।
पहले के टर्न्स में संपादन बाद में आए thinking ब्लॉक्स को अमान्य कर देता है। इससे इतिहास ट्रिमिंग और क्लाइंट-साइड समरीकरण टूट सकता है।
माइग्रेशन गाइड बदलावों के पूरे सेट को कवर करता है।
Read-Only रिपॉजिटरी टूल्स जोड़ें
अब मॉडल को read-only टूल्स के जरिए रिपॉजिटरी संदर्भ दें।
Read-only टूल्स परिभाषित करें
टूल लेयर के दो भाग हैं: Python फ़ंक्शंस जो एक्सेस नियम लागू करते हैं और वे स्कीमा जिन्हें Claude कॉल कर सकता है।
पाथ्स को प्रोजेक्ट रूट तक सीमित करें
Read-only का मतलब सुरक्षित नहीं है। कोई मॉडल ../../.env उतनी ही आसानी से मांग सकता है जितना config.py, इसलिए गार्ड आपके कोड में होना चाहिए, प्रॉम्प्ट में नहीं:
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
एब्सोल्यूट पाथ और symlink घटकों को अस्वीकार करें, फिर पाथ रेज़ॉल्व करें और पुष्टि करें कि वह प्रोजेक्ट रूट के अंदर ही रहता है। ../.env मांगने पर "path is outside the project root" लौटता है। लौटा हुआ टूल एरर एजेंट को अनुमत फाइलों के साथ जारी रखने देता है।
सख्त टूल स्कीमा परिभाषित करें
रीडर क्लास नियंत्रित करता है कि Python क्या खोल सकता है। Claude को उन तीन कार्रवाइयों का वर्णन करने वाले JSON स्कीमा भी चाहिए जिन्हें वह अनुरोध कर सकता है:
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 मॉडल द्वारा टूल चुनते समय आर्ग्युमेंट्स की जांच करता है। यह टूल कॉल को बाध्य नहीं करता, जो Fable 5.1 के लिए मायने रखता है।
मल्टी-टर्न टूल लूप चलाएँ
बेस लूप से शुरू करें: टूल्स भेजें, stop_reason देखें, अनुरोधित चीज़ चलाएँ, परिणाम जोड़ें, और दोहराएँ।
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 मॉडल रिक्वेस्ट्स को सीमाबद्ध करता है, खर्च को नहीं, इसलिए ज़रूरत हो तो अलग लागत सीमा लागू करें। लूप सीधे refusal, max_tokens, और tool_use को हैंडल करता है; अन्य stop reasons निरीक्षण चरण समाप्त करते हैं। is_error फ़ील्ड मॉडल को बताता है कि कोई पाथ अस्वीकृत था, ताकि वह कोई और कार्रवाई चुन सके।
forced टूल चयन पर 400 क्यों लौटता है
Fable 5 पर, आप पहली कॉल को tool_choice: {"type": "any"} से फोर्स कर सकते थे। Fable 5.1 यह त्रुटि रिक्वेस्ट चलने से पहले लौटाता है:
tool_choice: type "tool" and "any" are not supported for this model.
फोर्स्ड कॉल्स हमेशा-ऑन thinking को स्किप कर देते। tool_choice को auto पर रखें, ऊपर परिभाषित सख्त स्कीमा उपयोग करें, और जब किसी स्टेप को किसी टूल की ज़रूरत हो तो प्रॉम्प्ट में टूल्स के नाम लें।
Fable 5.1 कभी-कभी प्रति टर्न एक टूल कॉल जारी करता है, जबकि Fable 5 कई को बैच करता था। इससे राउंड-ट्रिप्स बढ़ते हैं। प्रॉम्प्ट में यह पंक्ति जोड़ें: “स्वतंत्र फाइलें एक ही टर्न में अनुरोध करें, एक-एक टर्न में नहीं”। एक सैंपल रन ने नौ स्वतंत्र फाइल अनुरोध बैच किए, हालांकि काउंट बदलता रहता है।
Claude Fable 5.1 प्रतिक्रियाएँ और प्रोग्रेस अपडेट्स स्ट्रीम करें
टेक्स्ट स्ट्रीमिंग उत्पन्न होते ही रिस्पॉन्स कंटेंट भेजती है; प्रोग्रेस अपडेट्स टूल कॉल्स के बीच के विरामों को कवर करते हैं।
टेक्स्ट प्रतिक्रियाएँ स्ट्रीम करें
पूरा प्रोजेक्ट स्ट्रीम शुरू करने से पहले context_system() का उपयोग SYSTEM_PROMPT को प्रोजेक्ट सारांश के साथ मिलाने के लिए करता है:
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() आपको assembled संदेश देता है, जिसमें उपयोग और stop reason शामिल होते हैं, जैसे ही स्ट्रीम ड्रेन होती है। स्ट्रीमिंग चंक्स में पूर्ण JSON होने की गारंटी नहीं है, इसलिए पार्स करने से पहले अंतिम संदेश का इंतज़ार करें।
टूल कॉल्स के बीच प्रोग्रेस दिखाएँ
टेक्स्ट स्ट्रीमिंग टूल कॉल्स के दौरान होने वाली देरी को कवर नहीं करती। Fable 5.1 टूल कॉल्स से पहले छोटे प्रोग्रेस अपडेट्स लिख सकता है। डिफॉल्ट thinking.display के तहत "omitted", प्रोग्रेस-विशिष्ट thinking ब्लॉक्स खाली रहते हैं, हालाँकि मॉडल फिर भी एक सामान्य टेक्स्ट लीड-इन उत्पन्न कर सकता है।
display: "updates" और thinking-display-updates-2026-08-18 बीटा हेडर के साथ, API दस्तावेज़ एक पठनीय प्रोग्रेस अपडेट को नॉन-एम्प्टी thinking ब्लॉक के रूप में परिभाषित करती है जबकि reasoning छुपी रहती है। इस प्रोजेक्ट के लाइव रन में, thinking फ़ील्ड खाली रही और पठनीय स्टेटस एक सामान्य text ब्लॉक के रूप में tool_use से ठीक पहले आया। इसलिए हेल्पर दोनों ब्लॉक प्रकारों की जांच करता है, और लूप इसे केवल उन्हीं टर्न्स पर कॉल करता है जो 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
प्रोग्रेस संदेश वे फाइलें बताते हैं जिन्हें मॉडल पढ़ने की योजना बनाता है: "मैं ऐप वायरिंग, कॉन्फ़िग, एक्सटेंशंस, पब्लिक और auth रूट्स, और मौजूदा टेस्ट्स पढ़ूंगा, क्योंकि rate limiting वहीं हुक करेगी।" वे संदेश दिखाएँ और खाली ब्लॉक्स को नज़रअंदाज़ करें।

एजेंट प्रोग्रेस रिपोर्ट करते हुए फाइलें पढ़ता है। चित्र: लेखक।
Fable 5.1 इनमें से Fable 5 की तुलना में कम लिखता है, खासकर उच्च effort पर। यदि आपके इंटरफ़ेस को नियमित अपडेट चाहिए, तो एक ओपनिंग लाइन, प्रोग्रेस संदेश, और एक क्लोज़िंग रिकैप मांगें।
बातचीत के बीच Claude Fable 5.1 effort बदलें
अगला फीचर काफी उपयोगी है। हम सभी जानते हैं, रिपॉजिटरी एजेंट को हर टर्न में समान reasoning गहराई की ज़रूरत नहीं होती।
टर्न्स के बीच effort बदलें
एजेंट लूप में, रूटीन रिट्रीवल टर्न्स के लिए effort घटाएँ और अंतिम प्लानिंग टर्न के लिए फिर बढ़ाएँ।
mid-conversation-output-config-2026-07-01 बीटा हेडर के साथ, आप केवल 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,
)
नया स्तर अगले यूज़र टर्न से लागू होता है, मौजूदा टर्न के बीच में नहीं, और यह प्रॉम्प्ट कैश को अमान्य नहीं करता। रिक्वेस्ट्स के बीच टॉप-लेवल output_config.effort बदलना इसे अमान्य करता है।
एजेंट टॉप-लेवल सेटिंग को high पर रखता है, रूटीन रिट्रीवल से पहले प्रति-संदेश medium निर्देश जोड़ता है, और अंतिम योजना से पहले high निर्देश जोड़ता है। एक जुड़े परीक्षण में कम effort पर 18 आउटपुट टोकन उपयोग हुए बनाम पहले सेटिंग पर 76। इसे अपेक्षित कमी नहीं, उदाहरण समझें।
एक टर्न के लिए सिस्टम निर्देश लागू करें
अंतिम प्लानिंग के दौरान अतिरिक्त फाइल रीड्स को रोकने के लिए टर्न-स्कोप्ड निर्देश का उपयोग करें।
clear_at: "next_user_message" को mid-conversation-system-clear-at-2026-08-21 बीटा हेडर वाले सिस्टम मैसेज पर सेट करें। API इसके टेक्स्ट को मौजूदा टर्न के लिए सिस्टम निर्देश की तरह ट्रीट करता है, फिर अगले यूज़र मैसेज के बाद इसे रेंडर करना बंद कर देता है। यह messages में बना रहता है, इसलिए पुराना इतिहास नहीं बदलता, कैश मेल खाता रहता है, और क्लियर किया गया मैसेज कोई इनपुट टोकन खर्च नहीं करता।
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"} अंतिम रिक्वेस्ट को कोई और टूल कॉल करने से रोकता है। स्कोप्ड निर्देश योजना को उन फाइलों तक सीमित करता है जिन्हें एजेंट पहले ही निरीक्षण कर चुका है। कोई रिमाइंडर जोड़कर अगली रिक्वेस्ट में उसे हटाएँ नहीं। वह संपादन बाद के thinking ब्लॉक्स को अमान्य कर देता है।
Claude Fable 5.1 thinking-block 400 एरर्स ठीक करें
The block is bound to a different conversation त्रुटि का अर्थ है कि किसी thinking ब्लॉक से पहले का इतिहास बदल गया। हर Fable 5.1 thinking ब्लॉक ठीक उसी सिस्टम प्रॉम्प्ट, टूल डेफिनिशन, और संदेशों से बंधा होता है जो उससे पहले आए।
परिणाम आपके खाते के बनाए जाने के समय पर निर्भर करता है।
-
31 अगस्त, 2026 या उसके बाद बनाए गए खातों को 400 मिलता है कि ब्लॉक किसी अलग बातचीत से बंधा है।
-
पहले बनाए गए खातों के लिए, API मिसमैच रिकॉर्ड करती है पर उस पर तभी कार्रवाई करती है जब रिक्वेस्ट
thinking.block_binding.prefix_mismatch_behaviorसेट करती है।
आप इसे thinking-binding-controls-2026-08-01 बीटा हेडर, thinking.block_binding.prefix_mismatch_behavior को "drop_block" पर सेट कर, और input_transformations एरे से डिटेक्ट कर सकते हैं। संपादित इतिहास reason: "prefix_binding_mismatch" के रूप में दिखता है। इसे अपने इंटीग्रेशन के खिलाफ एक बार चलाएँ।
निम्न ऑपरेशंस मिसमैच ट्रिगर करते हैं:
-
बाद के टर्न्स को रखते हुए किसी पहले के टर्न में संपादन, पुनःक्रमण, या हटाना
-
किसी पहले के टर्न में प्रति-रिक्वेस्ट टेक्स्ट इंजेक्ट करना और अगली रिक्वेस्ट में उसे हटाना
-
बातचीत के बीच टॉप-लेवल
systemप्रॉम्प्ट याtoolsएरे की सामग्री या क्रम बदलना -
किसी बाद की रिक्वेस्ट पर किसी इमेज या डॉक्यूमेंट URL से अलग बाइट्स परोसना
इनमें से प्रत्येक का एक विकल्प है जो बाइंडिंग्स को अक्षुण्ण रखता है:
-
systemको एडिट करने के बजाय mid-conversation सिस्टम मैसेजेस से निर्देश जोड़ें। -
टॉप-लेवल एरे बदलने के बजाय mid-conversation टूल बदलावों से टूल्स बदलें।
-
सर्वर-साइड context editing या compaction से इतिहास ट्रिम करें, जो edits नहीं माने जाते।
-
thinking ब्लॉक्स को बिना बदले वापस पास करें।
cache_control मार्कर्स को स्थानांतरित करना और रिक्वेस्ट-स्तरीय effort बदलना दोनों सुरक्षित हैं और thinking-block बाइंडिंग्स को अमान्य नहीं करते। हालाँकि, टॉप-लेवल effort बदलने से प्रॉम्प्ट कैशिंग फिर से शुरू होती है, इसलिए जब cached प्रीफिक्स बना रहना चाहिए, तब प्रति-संदेश effort का उपयोग करें।
प्रॉम्प्ट कैशिंग और Claude Fable 5.1 API लागत
निम्न रन ताज़ा इनपुट, कैश राइट्स, कैश रीड्स, और आउटपुट लागत को अलग-अलग दिखाता है।
स्वचालित प्रॉम्प्ट कैशिंग जोड़ें
प्रॉम्प्ट कैशिंग टर्न्स के बीच दोहराए गए संदर्भ की लागत घटाती है। बढ़ता इतिहास ब्रेकपॉइंट की जगह बदलता रहता है, इसलिए यहाँ स्वचालित कैशिंग सरल फिट है।
टॉप-लेवल cache_control फ़ील्ड प्रत्येक रिक्वेस्ट पर ब्रेकपॉइंट को नवीनतम कैचेबल ब्लॉक तक ले जाती है:
response = client.beta.messages.create(
model=MODEL,
cache_control={"type": "ephemeral"},
system=system,
tools=TOOLS,
messages=messages,
# Other request fields...
)
Fable 5.1 पर 512 टोकन से छोटा कैचेबल प्रीफिक्स, cache_control से मार्क होने पर भी, कैश नहीं होता। API इसे सामान्य रूप से प्रोसेस करती है और दोनों कैश काउंटर्स के लिए शून्य लौटाती है। 583-टोकन प्रीफिक्स लिखने की लागत $0.0073 थी; अगले टर्न पर पढ़ने की $0.00015। दूसरे टर्न को फिर भी अपने नए हिस्से को कैश में लिखना पड़ा, इसलिए कैश हिट ने हर इनपुट लागत नहीं हटाई।
कैश-सचेत API लागत का अनुमान लगाएँ
response.usage ताज़ा इनपुट, कैश क्रिएशन, कैश रीड्स, और आउटपुट को अलग-अलग रिपोर्ट करता है। चारों काउंटर्स का अपनी-अपनी दर पर मूल्यांकन करें; केवल इनपुट और आउटपुट जोड़ना कैश-राइट लागत छिपाता है और कैश हिट्स की कीमत को बढ़ा-चढ़ाकर दिखाता है।
यहाँ एक पूर्ण रन की लागत ब्रेकडाउन है, जिसने तीन टर्न्स में 12 फाइलें पढ़ीं और एक अंतिम योजना बनाई:
|
लाइन आइटम |
टोकन |
अनुमानित लागत |
हिस्सा |
|---|---|---|---|
|
आउटपुट |
5,713 |
$0.2857 |
59.4% |
|
कैश राइट्स |
15,426 |
$0.1928 |
40.1% |
|
ताज़ा इनपुट |
50 |
$0.0005 |
0.1% |
|
कैश रीड्स |
6,549 |
$0.0016 |
0.3% |
|
कुल |
27,738 |
$0.4806 |
100% |
कैश रीड इस अनुमान का आधे प्रतिशत से कम का अंश थीं। Fable 5 की पुरानी रेट पर, रन की लागत लगभग $0.4855 के बजाय $0.4806 होती। जब हर टर्न बहुत अधिक संदर्भ को फिर से उपयोग करता है, तब बचत बढ़ती है।
इस रन में, आउटपुट ने लगभग 60% अनुमान उत्पन्न किया, और कैश राइट्स ने लगभग 40%। यहाँ प्रयुक्त पाँच-मिनट रेट पर, एक कैश-राइट टोकन की लागत कैश-रीड टोकन से 50 गुना अधिक है। एक घंटे का कैश राइट 80 गुना अधिक है।
Claude Fable 5.1 refusals और fallbacks हैंडल करें
एक refusal और विफल रिक्वेस्ट को अलग एप्लिकेशन व्यवहार चाहिए।
आउटपुट पार्स करने से पहले refusals डिटेक्ट करें
आउटपुट आने से पहले का refusal HTTP 200 के साथ stop_reason: "refusal", खाली कंटेंट, और stop_details के रूप में आता है। इसकी श्रेणी null हो सकती है। स्ट्रीम में बाद का refusal आंशिक आउटपुट के बाद आ सकता है, जिसे एप्लिकेशन को डिस्कार्ड करना चाहिए। try/except के आस-पास की रैपिंग इन दोनों मामलों को नहीं पकड़ती।
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})."
इसे एप्लिकेशन स्टेट के रूप में हैंडल करें। यदि अनुमत रिक्वेस्ट अस्पष्ट है, तो उसे अधिक सटीक रूप में दोबारा लिखें। ऐसा रिट्राई लॉजिक न बनाएँ जिसका उद्देश्य क्लासिफ़ायर को दरकिनार करना हो।

एक refusal HTTP 200 के रूप में आता है। चित्र: लेखक।
सर्वर-साइड फॉलबैक कॉन्फ़िगर करें
सर्वर-साइड फॉलबैक किसी अन्य मॉडल पर अस्वीकृत रिक्वेस्ट को fallbacks: "default" और server-side-fallback-2026-07-01 बीटा हेडर के साथ फिर से आज़मा सकता है। Fable 5.1 के लिए अनुमत लक्ष्यों में Opus 4.8 और Opus 5 शामिल हैं।
डिफॉल्ट फॉलबैक तभी चलता है जब refusal श्रेणी का कोई अनुशंसित लक्ष्य हो। एक परखा गया reasoning_extraction refusal ने फॉलबैक ट्रिगर नहीं किया; यह मानने के बजाय कि हर refusal रिट्राई होगा, usage.iterations जाँचें। जैसा पहले उल्लेख किया गया, पुराने मॉडल पर जाने से Fable 5.1 thinking ब्लॉक्स भी हट जाते हैं।
FastAPI के साथ Claude Fable 5.1 एजेंट सर्व करें
लोकल एजेंट अब वही वर्कफ़्लो एक HTTP API के माध्यम से सर्व कर सकता है।
प्लान एंडपॉइंट बनाएँ
यदि आपको केवल लोकल स्क्रिप्ट चाहिए, तो इस सेक्शन को छोड़ दें। वेब सर्विस के लिए, FastAPI का उपयोग AsyncAnthropic के साथ करें। एक lifespan हैंडलर में प्रोसेस के लिए एक ही क्लाइंट बनाएँ। स्कीमा और प्रॉम्प्ट्स मौजूदा एजेंट मॉड्यूल से इम्पोर्ट करें।
@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))
ध्यान दें कि कॉलर एक प्रोजेक्ट नाम भेजता है, पाथ नहीं। resolve_project() इसे अनुमत रूट्स के एक छोटे सेट में मैप करता है, ताकि रिक्वेस्ट सर्वर से कहीं भी पढ़ने के लिए न कह सके। यह सर्विस एप्लिकेशन विकल्प के रूप में refusals को 422 पर मैप करती है। Claude API स्वयं उन्हें HTTP 200 के रूप में लौटाती है।
इसे uvicorn app:app --reload के साथ चलाएँ। इंटरैक्टिव दस्तावेज़ीकरण http://localhost:8000/docs पर उपलब्ध है।
एंडपॉइंट अनुमानित लागत के साथ एक प्लान लौटाता है। वीडियो: लेखक।
/plan/stream एंडपॉइंट बैकग्राउंड टास्क में निरीक्षण चलाता है, प्रोग्रेस और टूल इवेंट्स को asyncio.Queue पर रखता है, और उन्हें StreamingResponse के माध्यम से इमिट करता है। जब स्ट्रीम बंद होती है, जनरेटर बैकग्राउंड टास्क रद्द करता है। रिपॉजिटरी में Streamlit इंटरफेस वही इवेंट स्ट्रीम रेंडर करता है।
Streamlit एजेंट की लाइव प्रोग्रेस दिखाता है। वीडियो: लेखक।
Claude Fable 5.1 एजेंट डिप्लॉयमेंट चेकलिस्ट
पहले बनाए गए लिमिट्स और चेक्स सर्विस का हिस्सा बने रहते हैं। डिप्लॉयमेंट से पहले, वे ऑपरेशनल हिस्से जोड़ें जो लोकल रन में दिखते नहीं हैं।
-
SDK के 429 और 5xx प्रतिक्रियाओं के लिए डिफॉल्ट दो रिट्राई की समीक्षा करें, फिर सर्विस की लेटेंसी बजट के अनुरूप
max_retriesऔर टाइमआउट सेट करें -
रिक्वेस्ट टाइमआउट सेट करें और पुष्टि करें कि मौजूदा SSE टास्क कैंसलेशन क्लाइंट डिसकनेक्ट होने पर पेंडिंग कार्य रोक देता है
-
प्रत्येक रन के लिए मॉडल ID, SDK संस्करण, रिक्वेस्ट ID, stop reason, और चार टोकन श्रेणियाँ लॉग करें
-
बढ़ते कैश राइट्स, आउटपुट टोकन, refusals, और टर्न कैप तक पहुँचने वाले रनों पर अलर्ट करें
-
पुष्टि करें कि खाते की रिटेंशन सेटिंग मॉडल आवश्यकता से मेल खाती है
-
SDK पिन करें और प्रत्येक रिलीज़ से पहले बीटा हेडर्स को फिर से जाँचें
Opus 5 या Sonnet 5 के बजाय कब Claude Fable 5.1 का उपयोग करें
- Anthropic Opus 5 को एक उचित डिफॉल्ट के रूप में सलाह देता है।
- जब Opus 5 लंबी रिपॉजिटरी विश्लेषण, कठिन डीबगिंग, या बड़े संदर्भ वाले एजेंटिक टास्क पर कमतर पड़े, तब Fable 5.1 का परीक्षण करें।
- रिपॉजिटरी कार्य और रोज़मर्रा के टास्क के लिए, गुणवत्ता, लेटेंसी, और लागत पर Sonnet 5 और Opus 5 की तुलना करें।
- वर्गीकरण, एक्सट्रैक्शन, छोटे उत्तर, और सरल रिक्वेस्ट्स के लिए, Sonnet 5 अच्छा डिफॉल्ट है; सबसे आसान टास्क के लिए Haiku 4.5 भी पर्याप्त मजबूत हो सकता है।
सिर्फ इसलिए Fable 5.1 न चुनें क्योंकि यह नया है। एकल रिक्वेस्ट फिर भी effort और structured outputs का उपयोग कर सकती है; स्ट्रीमिंग भी काम करती है। इसे यहाँ प्रयुक्त लूप या repeated-prefix कैशिंग से लाभ नहीं मिलता।
अंतिम विचार
मेरी पहली कॉल से आया सामान्य प्लान तभी उपयोगी बना जब एजेंट ने रिपॉजिटरी पढ़ी। पूर्ण रन में, इसने तीन टर्न्स में 12 फाइलों का निरीक्षण किया, जबकि आउटपुट और कैश राइट्स अनुमानित लागत के 99.5% थे। मैं पाथ सीमा और append-only इतिहास बनाए रखूँगा, फिर परीक्षण करूँगा कि क्या कम effort से लागत घटती है बिना मॉडल को रिपॉजिटरी टूल्स स्किप कराए।
यदि एक प्रतिक्रिया टास्क का उत्तर दे सकती है, तो structured outputs पर रुकें। टूल लूप का उपयोग तब करें जब उत्तर को रिपॉजिटरी फाइलों पर निर्भर होना पड़े या कॉल्स के बीच प्रोग्रेस रिपोर्ट करनी हो।
मॉडल-चयन विवरणों के लिए, मैं हमारा Introduction to Claude Models कोर्स लेने की सलाह देता हूँ। प्रॉम्प्टिंग और एजेंट वर्कफ़्लो के लिए, हमारा Software Development with Cursor कोर्स देखें।
FAQs
क्या Claude Fable 5.1 इमेज के साथ-साथ कोड भी पढ़ सकता है?
हाँ। यह इमेज इनपुट स्वीकार करता है और चार्ट्स व PDFs पढ़ सकता है। मैंने मुख्य उदाहरण में vision को इसलिए छोड़ दिया क्योंकि रिपॉजिटरी प्लान को इसकी जरूरत नहीं है। यदि मैं इस एजेंट को UI बदलाव की योजना तक बढ़ा रहा होता, तो मैं फीचर रिक्वेस्ट के साथ मौजूदा स्क्रीनशॉट भेजता। यदि छोटे विज़ुअल विवरण कार्य को प्रभावित नहीं करते, तो पहले उसे डाउनस्केल करें।
Fable 5 से स्विच करने के बाद मेरा एजेंट धीमा क्यों हो गया?
मॉडल को दोष देने से पहले टूल परिणाम जांचें। यदि पहले से बैचिंग निर्देश मौजूद है, तो उनकी संख्या और आकार दोनों की तुलना करें। मौजूदा रीडर प्रत्येक फाइल को 40,000 बाइट्स पर कैप करता है। यदि यह अभी भी बहुत बड़ा है, तो लाइन-रेंज या सर्च आर्ग्युमेंट्स जोड़ें ताकि टूल केवल संबंधित सेक्शन लौटा सके।
Claude Fable 5.1 400 invalid_request_error क्यों लौटाता है?
पहले रिट्राई न करें। एक invalid_request_error आमतौर पर रिक्वेस्ट के आकार या अकाउंट सेटिंग की ओर इशारा करता है जिसे बदलना चाहिए। इस प्रोजेक्ट में, संभावित कारण हैं फोर्स्ड tool_choice, असंगत रिटेंशन सेटिंग, संरक्षित thinking के साथ एडिट किया गया प्रीफिक्स, या मिलते-जुलते हेडर के बिना भेजा गया बीटा फ़ील्ड। बताई गई वजह ठीक करें, फिर रिक्वेस्ट दोबारा भेजें।
क्या मुझे सोर्स फाइलें कैश करनी चाहिए या सारांश?
मैं यह नियम उपयोग करता हूँ: जब कई टर्न्स में सटीक कोड मायने रखता हो, तो सोर्स फाइलें कैश करें। यदि आगे के स्टेप्स को केवल आर्किटेक्चर या फाइल मैप चाहिए, तो एक सारांश कैश करें। सारांश कम टोकन खर्च करता है, लेकिन वह वही एक पंक्ति छोड़ सकता है जिसकी अंतिम योजना को जरूरत है।
क्या Batch API यह एजेंट चला सकती है?
अपने आप नहीं। Batch API व्यक्तिगत Messages रिक्वेस्ट्स सबमिट करती है; यह क्लाइंट-साइड टूल लूप नहीं चलाती। मैं इसे स्व-निहित रिपॉजिटरी रिव्यू के लिए उपयोग करता जब लाइव प्रोग्रेस आवश्यक न हो। बैचों में पूरा लूप चलाने के लिए, आपको अपने कोड की जरूरत होगी जो एक बैच के टूल रिक्वेस्ट्स प्रोसेस करने के बाद अगला सबमिट करे।