कोर्स
अधिकांश बेंचमार्क अलग-अलग मॉडलों की आपस में तुलना करते हैं। लेकिन जब आप एक प्रोडक्शन AI पाइपलाइन बना रहे होते हैं, तो अधिक उपयोगी प्रश्न अक्सर सरल होता है—यानी, किसी दिए गए कार्य पर वही मॉडल कितनी मेहनत करे, और उसकी लागत क्या होगी?
Claude Opus 4.8 ने एक effort पैरामीटर पेश किया है जिसमें कई स्तर हैं जो सीधे नियंत्रित करते हैं कि मॉडल कितनी गहराई से तर्क करेगा। अधिक effort का मतलब है अधिक thinking टोकन, edge cases का बेहतर कवरेज, और लंबा उत्तर। इसका अर्थ अधिक latency और लागत भी है।
इस ट्यूटोरियल में, हम एक Streamlit ऐप बनाएंगे जो इस tradeoff को ठोस और मापने योग्य बनाता है। ऐप एक ही प्रॉम्प्ट पर तीन API कॉल (हर effort स्तर के लिए एक) चलाता है, Claude Haiku 4.5 का उपयोग करके प्रत्येक उत्तर को rubric-आधारित जज से स्वतः स्कोर करता है, और एक इंटरैक्टिव cost-projection कर्व प्रस्तुत करता है ताकि आप देख सकें कि आपके task वॉल्यूम के लिए कौन-सा effort स्तर उपयुक्त है।
इस ट्यूटोरियल के अंत तक, आप जान जाएंगे कि कैसे:
-
Claude Opus 4.8 API पर
effortपैरामीटर पास करें -
आवश्यक सहायक फ्लैग के रूप में
thinking: {type: "adaptive"}का उपयोग करें -
किसी सस्ते जज मॉडल से प्रोग्रामेटिक तरीके से मॉडल आउटपुट को स्कोर करें
-
Streamlit के साथ एक cost projection UI बनाएं
Claude Opus 4.8 क्या है?
Claude Opus 4.8 Anthropic का फ्लैगशिप large language model (LLM) है। यह जटिल तर्क, long-horizon agentic कोडिंग, और उच्च-स्वायत्तता वाले कार्यों के लिए डिज़ाइन किया गया है, जहाँ मॉडल को कई चरणों में सुसंगत रहना, बड़े संदर्भ संभालना, और compaction त्रुटियों को कम करना होता है।
Opus 4.8 को पहले के Claude मॉडलों से अलग करने वाली कुछ बातें:
-
1M टोकन कॉन्टेक्स्ट विंडो: यह डिफॉल्ट रूप से Claude API, Amazon Bedrock, और Vertex AI पर उपलब्ध है
-
128k अधिकतम आउटपुट टोकन: लंबे प्रारूप के artifacts बिना truncation के तैयार करने में मदद
-
Adaptive thinking: मॉडल हर turn पर तय करता है कि गहन तर्क की ज़रूरत है या नहीं, बजाय हमेशा एक तय thinking बजट खर्च करने के
-
effortपैरामीटर: प्रति अनुरोध तर्क की गहराई और लागत को नियंत्रित करने के लिए एक डायल -
न्यूनतम prompt cache कम: cacheable प्रॉम्प्ट सीमा ~2,048 से घटकर 1,024 टोकन हो गई है, यानी अब अधिक system प्रॉम्प्ट बगैर किसी कोड बदलाव के cache hit पाएंगे
अगर आप Opus 4.8 को दूसरे frontier विकल्प से तौल रहे हैं, तो हमारा Claude Opus 4.8 vs. GPT-5.5 तुलना लेख बताता है कि कोडिंग और तर्क में कौन-सा मॉडल कहाँ आगे निकलता है।
Opus 4.8 ने Opus 4.7 से मिली कुछ API पाबंदियों को और सख्त किया है, जिनमें temperature, top_p, और top_k शामिल हैं जिन्हें non-default मानों पर सेट नहीं किया जा सकता, और budget_tokens के जरिए विस्तारित thinking बजट अब समर्थित नहीं हैं। इनमें से कोई भी पास करने पर 400 त्रुटि मिलती है।
अब effort पैरामीटर और adaptive thinking ही तर्क-व्यवहार नियंत्रित करने के प्राथमिक साधन हैं।
Effort पैरामीटर क्या है?
Claude Opus 4.8 में effort पैरामीटर जोड़ा गया है जो आपको प्रति अनुरोध तर्क की गहराई नियंत्रित करने देता है। इसे तीन-स्थिति वाले डायल की तरह समझें:
-
low: मॉडल अधिक सीधे उत्तर देता है, कम thinking टोकन उपयोग करता है—अच्छी तरह परिभाषित, तथ्यात्मक, या संरचित कार्यों के लिए उपयुक्त। -
medium: बीच का रास्ता—मॉडल अधिक सावधानी से तर्क करता है, पर हर edge case को विस्तार से नहीं खंगालता। -
high: यह मॉडल का डिफॉल्ट है—बढ़ी हुई thinking गहराई के साथ, जटिल तर्क, बहु-चरणीय डिज़ाइन समस्याओं, और जहाँ edge case छूटना महंगा पड़े, ऐसे कार्यों के लिए सर्वोत्तम। -
xhigh: लंबे क्षितिज वाले agentic और कोडिंग कार्यों के लिए, जिनमें कई चरणों में सतत सुसंगति चाहिए। -
max: पूर्ण compute बजट आरक्षित करते हुए अधिकतम क्षमता स्तर—सबसे मांग वाले कार्यों के लिए।
effort पैरामीटर केवल thinking: {type: "adaptive"} के साथ काम करता है। Adaptive thinking मॉडल को हर turn पर तय करने देता है कि गहरे तर्क की ज़रूरत है या नहीं। साथ मिलकर, ये नियंत्रित करते हैं कि मॉडल अपना compute बजट कैसे खर्च करे।
यह ट्यूटोरियल low, medium, और high पर केंद्रित है—वे तीन स्तर जो सामान्य-उद्देश्य प्रोडक्शन वर्कलोड्स के लिए सबसे प्रासंगिक हैं—पर वही ऐप संरचना xhigh या max तक बढ़ाने पर भी लागू होती है।
ये शीर्ष effort स्तर सतत agentic कार्यों के लिए बने हैं—जिन्हें हमने अपने Spec-Driven Development with Claude Code ट्यूटोरियल में walkthrough किया है।
Claude Opus 4.8 की गुणवत्ता बनाम लागत के संतुलन को मापने के लिए एक Effort डायल बनाना
ऐप एक सिंगल Python फ़ाइल है। इसे चलाने पर, आपको साइडबार में प्रॉम्प्ट इनपुट और tasks-per-day स्लाइडर दिखता है, और मुख्य पैनल में चार टैब:
- गुणवत्ता बनाम लागत स्कैटर प्लॉट
- वॉल्यूम प्रोजेक्शन चार्ट्स
- कच्चे उत्तर
- डाउनलोड करने योग्य परिणाम तालिका
हर रन पर वर्कफ़्लो यह है:
claude-opus-4-8पर क्रमिक रूप से तीन API कॉल फायर करें, जिनमें effort क्रमशःlow,medium, औरhighहो- हर उत्तर को
claude-haiku-4-5को rubric-आधारित स्कोरर के रूप में पास करें - Streamlit UI में सभी परिणाम रेंडर करें और मैनुअल ओवरराइड के लिए समायोज्य स्लाइडर्स दें
डिफॉल्ट प्रॉम्प्ट एक distributed systems डिज़ाइन प्रश्न है जो effort स्तर के साथ स्वाभाविक रूप से स्केल करता है।
स्टेप 0: पूर्व-आवश्यकताएँ
इस ट्यूटोरियल का पालन करने के लिए आपको चाहिए:
-
Python 3.10 या नवीनतर
-
claude-opus-4-8तक पहुँच वाला Anthropic API key -
Streamlit की बुनियादी जानकारी
स्टेप 1: निर्भरताएँ इंस्टॉल करें
एक वर्चुअल एनवायरनमेंट बनाएं और आवश्यक पैकेज इंस्टॉल करें:
bashpython -m venv .venv
source .venv/bin/activate
pip install anthropic streamlit plotly pandas python-dotenv
Windows पर source .venv/bin/activate की जगह .venv\Scripts\activate का उपयोग करें।
प्रोजेक्ट रूट में .env फ़ाइल में अपना Anthropic API key जोड़ें:
.env
ANTHROPIC_API_KEY=sk-ant-...
एनवायरनमेंट सेट होने के बाद, हम UI के लिए effort_dial स्कीमा परिभाषित करेंगे।
स्टेप 2: प्रोजेक्ट कॉन्स्टेंट्स सेट करें
एक effort_dial.py नाम की फ़ाइल बनाएँ और शीर्ष पर यह कॉन्फ़िगरेशन ब्लॉक जोड़ें:
import os
import time
import json
import re
import anthropic
import pandas as pd
import plotly.graph_objects as go
import streamlit as st
from dotenv import load_dotenv
load_dotenv()
st.set_page_config(
page_title="Opus 4.8 Effort Dial — Claude Opus 4.8",
layout="wide",
)
MODEL = "claude-opus-4-8"
SCORER_MODEL = "claude-haiku-4-5"
MAX_OUTPUT_TOKENS = 16000
SCORER_MAX_TOKENS = 500
PRICE_OUT_PER_TOK = 25 / 1_000_000
PRICE_IN_PER_TOK = 5 / 1_000_000
SCORER_PRICE_OUT_PER_TOK = 5 / 1_000_000
SCORER_PRICE_IN_PER_TOK = 1 / 1_000_000
EFFORT_ORDER = ["low", "medium", "high"]
EFFORT_COLORS = {"low": "#185FA5", "medium": "#639922", "high": "#EF9F27"}
DEFAULT_QUALITY = {"low": 68, "medium": 82, "high": 91}
यहाँ MAX_OUTPUT_TOKENS को डिफॉल्ट 4,096 की जगह 16,000 पर सेट किया गया है। यह इसलिए ज़रूरी है क्योंकि 4,096 टोकन कैप पर, medium और high दोनों एक ही बिंदु पर truncate हो जाते हैं, जिससे उनके बीच का दृश्यमान अंतर मिट जाता है। आपको इतना headroom चाहिए कि उत्तर स्वाभाविक रूप से अलग हो सकें।
अंतिम आउटपुट में max_tokens के बजाय end_turn stop reason यह भी पुष्टि करता है कि मॉडल अपना उत्तर स्वयं पूरा करके रुका है।
स्टेप 3: डिफॉल्ट प्रॉम्प्ट सेट करें
"explain recursion" जैसा सरल प्रॉम्प्ट तीनों effort स्तरों पर मिलते-जुलते उत्तर देता है, क्योंकि यहाँ गहरी तर्क-गति प्रेरित करने लायक कठिनाई नहीं है। इसलिए, हमने इसके बजाय एक बहु-भागीय सिस्टम डिज़ाइन प्रश्न उपयोग किया:
DEFAULT_PROMPT = """\
Design a production-ready rate-limiting system for a distributed API gateway
handling 100k requests/second. Cover:
1. Algorithm choice (token bucket vs sliding window vs leaky bucket) with tradeoffs
2. Redis data structure design and TTL strategy
3. Race condition handling across 50 pods
4. Failure mode behavior when Redis is unavailable
5. How you'd test this under load
Be specific about implementation details, not just concepts.
"""
इस प्रॉम्प्ट में पाँच अलग-अलग उपसमस्याएँ हैं। Low-effort दृष्टिकोण आमतौर पर इन्हें सतही स्तर पर छूते हैं—मुख्य अवधारणाएँ कवर होती हैं, पर इम्प्लीमेंटेशन विवरण छूट जाते हैं। High effort सीमा-स्थितियों को कवर करता है, Lua scripting के उदाहरण जोड़ता है, EVALSHA atomicity पर चर्चा करता है, और ठोस सीमाओं के साथ लोड टेस्टिंग योजना जोड़ता है।
स्टेप 4: Effort पैरामीटर के साथ Claude Opus 4.8 कॉल करें
अब मॉडल को कॉल करने वाला कोर फ़ंक्शन परिभाषित करें। यहाँ दो अहम विवरण हैं: thinking={"type": "adaptive"} और output_config={"effort": effort}:
def call_opus(client: anthropic.Anthropic, effort: str, prompt: str) -> dict:
t0 = time.perf_counter()
response = client.messages.create(
model=MODEL,
max_tokens=MAX_OUTPUT_TOKENS,
thinking={"type": "adaptive"},
output_config={"effort": effort},
# Do NOT set temperature, top_p, or top_k — those 400-error on Opus 4.8
messages=[{"role": "user", "content": prompt}],
)
latency_ms = (time.perf_counter() - t0) * 1000
in_tok = response.usage.input_tokens
out_tok = response.usage.output_tokens
text = next(
(b.text for b in response.content if b.type == "text"), "(no text block)"
)
return {
"effort": effort,
"in_tokens": in_tok,
"out_tokens": out_tok,
"latency_ms": latency_ms,
"cost_usd": in_tok * PRICE_IN_PER_TOK + out_tok * PRICE_OUT_PER_TOK,
"response": text,
"stop_reason": response.stop_reason,
"hit_token_cap": out_tok >= MAX_OUTPUT_TOKENS,
}
आइए इस फ़ंक्शन के प्रमुख फ़ैसलों को समझें।
-
thinking={"type": "adaptive"}:effortपैरामीटर के प्रभावी होने के लिए यह आवश्यक है। इसके बिना, आप जो भीeffortपास करें, तीनों कॉल एक जैसे बर्ताव करेंगे। Adaptive thinking मॉडल को हर turn पर तय करने देता है कि गहरे तर्क की ज़रूरत है या नहीं, और जब ज़रूरत हो तो बजट आवंटन नियंत्रित करता है। -
output_config={"effort": effort}: Anthropic Python SDK में उन पैरामीटर्स को पास करने का तरीका जो अभी नामित आर्ग्यूमेंट के रूप में exposed नहीं हैं। आंतरिक रूप से यह dict को रॉ API अनुरोध बॉडी में मर्ज कर देता है। -
time.perf_counter(): wall-clock latency के लिएtime.time()की जगह यह मेथड इसलिए उपयोग किया जाता है क्योंकिperf_counterउच्च रिज़ोल्यूशन देता है और सिस्टम क्लॉक समायोजन से प्रभावित नहीं होता। -
response.content: Adaptive thinking के साथ Opus 4.8 कई कंटेंट ब्लॉक लौटा सकता है—एक thinking ब्लॉक जिसमें मॉडल की आंतरिक तर्क-श्रृंखला होती है, और एक text ब्लॉक जिसमें अंतिम उत्तर होता है। हमें केवल प्रदर्शन के लिए text ब्लॉक चाहिए।next()कॉल thinking ब्लॉक को छोड़कर केवल user-facing उत्तर निकालता है। -
hit_token_cap: एक डायग्नोस्टिक फ़्लैग जोTrueहोता है जबout_tokens,MAX_OUTPUT_TOKENSके बराबर हो। अगर यहmediumयाhighके लिए True है, तो मतलब उत्तर बीच में ही कट गया।
स्टेप 5: Claude Haiku 4.5 से उत्तरों को स्वतः स्कोर करें
हर रन पर तीन लंबे उत्तरों को मैन्युअल रूप से स्कोर करना धीमा और व्यक्तिपरक है। इसकी जगह हर उत्तर को Claude Haiku 4.5 को एक rubric के साथ पास करें और उससे structured JSON स्कोर लौटाने दें।
एक मॉडल से दूसरे को ग्रेड करवाना LLM-as-a-judge मूल्यांकन का रूप है; हमारी LLM Evaluation गाइड बताती है कि भरोसेमंद rubrics कैसे डिज़ाइन करें।
Rubric गुणवत्ता को चार उप-स्कोर में बाँटता है:
- completeness,
- correctness,
- edge-case कवरेज, और
- implementation
ये ठीक उसी बात से मेल खाते हैं जो सिस्टम डिज़ाइन प्रॉम्प्ट पर effort स्तरों को अलग करती है:
def score_response_with_haiku(client: anthropic.Anthropic, original_prompt: str,
response_text: str, effort: str) -> dict:
rubric = (
"You are grading an answer to a difficult systems design prompt. "
"Score the response from 0 to 100 using this rubric: "
"completeness 30 points, technical correctness 30 points, "
"edge-case coverage 20 points, implementation specificity 20 points. "
"Return strict JSON only with keys: score, rationale, completeness, "
"correctness, edge_cases, specificity. "
"The rationale must be concise, concrete, and no more than 80 words."
)
grader_prompt = (
f"{rubric}\n\n"
f"Original prompt:\n{original_prompt}\n\n"
f"Effort level being graded: {effort}\n\n"
f"Candidate response:\n{response_text}"
)
result = client.messages.create(
model=SCORER_MODEL,
max_tokens=SCORER_MAX_TOKENS,
messages=[{"role": "user", "content": grader_prompt}],
)
raw = next((b.text for b in result.content if b.type == "text"), "")
parsed = extract_json_object(raw)
in_tok = result.usage.input_tokens
out_tok = result.usage.output_tokens
score = max(0, min(100, int(round(float(parsed["score"])))))
return {
"score": score,
"rationale": str(parsed.get("rationale", "")).strip(),
"subscores": {
"completeness": parsed.get("completeness"),
"correctness": parsed.get("correctness"),
"edge_cases": parsed.get("edge_cases"),
"specificity": parsed.get("specificity"),
},
"scorer_model": SCORER_MODEL,
"scorer_cost_usd": in_tok * SCORER_PRICE_IN_PER_TOK + out_tok * SCORER_PRICE_OUT_PER_TOK,
"scorer_in_tokens": in_tok,
"scorer_out_tokens": out_tok,
}
extract_json हेल्पर उन मामलों को संभालता है जब Haiku कभी-कभी अपने JSON आउटपुट को Markdown fences में लपेट देता है। छोटे मॉडलों को प्रॉम्प्ट करते समय यह एक आम विफलता है।
तीनों उत्तरों पर कुल स्कोरिंग लागत आम तौर पर $0.002 से कम होती है। यह एक नगण्य ओवरहेड है जो व्यक्तिपरक मैन्युअल स्टेप को दोहराने योग्य rubric से बदल देता है।
स्टेप 6: Plotly चार्ट बनाएं
ऐप में तीन चार्ट हैं:
- गुणवत्ता स्कोर बनाम प्रति कॉल लागत का स्कैटर प्लॉट, जो cost-quality frontier का आकार दिखाता है।
- एक grouped बार चार्ट जो आउटपुट टोकन और दैनिक लागत की तुलना करता है, एक कॉन्फ़िगर करने योग्य task वॉल्यूम पर।
- एक लाइन चार्ट जो 100–5,000 tasks प्रति दिन तक संचयी दैनिक लागत दिखाता है।
आइए ये तीनों चार्ट बनाते हैं:
def quality_tradeoff_chart(results: list[dict], scores: dict) -> go.Figure:
fig = go.Figure()
for r in results:
effort = r["effort"]
fig.add_trace(go.Scatter(
x=[r["cost_usd"]],
y=[scores[effort]],
mode="markers+text",
name=effort.capitalize(),
text=[effort.capitalize()],
textposition="top center",
marker=dict(size=18, color=EFFORT_COLORS[effort],
line=dict(color="white", width=2)),
hovertemplate=(
"<b>%{text}</b><br>"
"Cost / call: $%{x:.5f}<br>"
"Quality: %{y}<extra></extra>"
),
))
fig.update_layout(
plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
margin=dict(t=20, b=20, l=0, r=0),
xaxis=dict(title="Cost / call (USD)", gridcolor="rgba(128,128,128,0.15)"),
yaxis=dict(title="Quality score", range=[0, 100],
gridcolor="rgba(128,128,128,0.15)"),
legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
)
return fig
def projection_chart(results: list[dict], tasks: int) -> go.Figure:
fig = go.Figure()
fig.add_traces([
go.Bar(
name="Output tokens", x=[r["effort"] for r in results],
y=[r["out_tokens"] for r in results],
marker_color=[EFFORT_COLORS[r["effort"]] for r in results],
yaxis="y1", text=[f"{r['out_tokens']:,}" for r in results],
textposition="outside", width=0.35, offset=-0.2,
),
go.Bar(
name=f"Daily cost ({tasks:,} tasks)",
x=[r["effort"] for r in results],
y=[r["cost_usd"] * tasks for r in results],
marker_color=[EFFORT_COLORS[r["effort"]] for r in results],
marker_opacity=0.45, yaxis="y2",
text=[f"${r['cost_usd']*tasks:.4f}" for r in results],
textposition="outside", width=0.35, offset=0.2,
),
])
fig.update_layout(
barmode="group", plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
margin=dict(t=20, b=20, l=0, r=0),
yaxis=dict(title="Output tokens", gridcolor="rgba(128,128,128,0.15)"),
yaxis2=dict(title="Daily cost (USD)", overlaying="y", side="right"),
legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
)
return fig
def breakeven_chart(results: list[dict]) -> go.Figure:
volumes = list(range(100, 5001, 100))
fig = go.Figure()
for r in results:
fig.add_trace(go.Scatter(
x=volumes, y=[r["cost_usd"] * v for v in volumes],
mode="lines", name=r["effort"].capitalize(),
line=dict(color=EFFORT_COLORS[r["effort"]], width=2.5),
))
fig.update_layout(
plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
margin=dict(t=20, b=20, l=0, r=0),
xaxis=dict(title="Tasks / day", gridcolor="rgba(128,128,128,0.15)"),
yaxis=dict(title="Daily cost (USD)", gridcolor="rgba(128,128,128,0.15)"),
legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
)
return fig
हर चार्ट उन्हीं तीन डेटा बिंदुओं पर अलग-अलग प्रश्नों का उत्तर देता है।
-
quality_tradeoff_chartx-अक्ष पर लागत और y-अक्ष पर गुणवत्ता स्कोर प्लॉट करता है, जिससे frontier का आकार तुरंत दिखता है। -
projection_chartAPI परिणामों से प्रति-कॉल लागत एंकर लेता है और उसे tasks-per-day स्लाइडर मान से गुणा करता है, ताकि हर बार अनुमान के बजाय वास्तविक टोकन काउंट झलके। -
breakeven_chart100 से 5,000 tasks प्रति दिन तक sweep करता है, उन्हीं वास्तविक लागत एंकरों का उपयोग करके—इसलिए रेखाएँ API प्रतिक्रियाओं पर आधारित दर से अलग होती हैं। 500 tasks/दिन चलाने वाली टीम की लागत तस्वीर 5,000 चलाने वाली टीम से बहुत अलग होती है, और यह चार्ट उसे ठोस बनाता है।
अगले चरण में, हम इन तीनों चार्ट फ़ंक्शनों को Streamlit UI में वायर करेंगे और उन्हें लाइव API परिणामों से जोड़ेंगे।
स्टेप 7: Streamlit UI बनाएँ
अंतिम हिस्सा Streamlit इंटरफ़ेस है। साइडबार key resolution, प्रॉम्प्ट इनपुट, और tasks-per-day स्लाइडर संभालता है। मुख्य पैनल क्रमिक रूप से कॉल चलाता है और जैसे-जैसे प्रत्येक पूरा होता है प्रोग्रेस कार्ड अपडेट करता है।
def main():
api_key = os.getenv("ANTHROPIC_API_KEY", "").strip()
with st.sidebar:
st.title("Opus 4.8 Effort Dial")
st.divider()
if api_key:
st.success("Key loaded.")
else:
st.error("Missing ANTHROPIC_API_KEY. Set it in your .env file.")
prompt = st.text_area(
"Prompt (runs at all 3 effort levels)",
value=DEFAULT_PROMPT, height=220,
)
run = st.button("▶ Run 3 calls", use_container_width=True, type="primary")
st.divider()
tasks = st.slider("Tasks / day", min_value=10, max_value=5000, value=500, step=10)
if "results" not in st.session_state:
st.session_state.results = []
for effort, default in DEFAULT_QUALITY.items():
if f"quality_{effort}" not in st.session_state:
st.session_state[f"quality_{effort}"] = default
if run:
if not api_key:
st.error("Set ANTHROPIC_API_KEY first.")
st.stop()
client = anthropic.Anthropic(api_key=api_key)
collected = []
progress = st.progress(0, text="Starting calls…")
cols = st.columns(3)
holders = {e: cols[i].empty() for i, e in enumerate(EFFORT_ORDER)}
for i, effort in enumerate(EFFORT_ORDER):
holders[effort].info(f"**{effort.upper()}** — calling…")
progress.progress(i / 3, text=f"Running {effort} effort…")
try:
result = call_opus(client, effort, prompt)
try:
scored = score_response_with_haiku(
client, prompt, result["response"], effort
)
result.update(scored)
st.session_state[f"quality_{effort}"] = scored["score"]
score_line = f"auto-score: {scored['score']}/100"
except Exception as e:
result["score_error"] = str(e)
score_line = "auto-score unavailable"
collected.append(result)
holders[effort].success(
f"**{effort.upper()}**\n\n"
f"{result['out_tokens']:,} output tokens\n\n"
f"{result['latency_ms']/1000:.2f}s\n\n"
f"${result['cost_usd']:.5f} / call\n\n"
f"{score_line}"
)
except Exception as exc:
holders[effort].error(f"**{effort.upper()}** failed: {exc}")
progress.progress((i + 1) / 3)
st.session_state.results = sorted(
collected, key=lambda r: EFFORT_ORDER.index(r["effort"])
)
progress.empty()
st.header("Opus 4.8 Effort Dial: Quality vs. Cost Tradeoff")
results = st.session_state.results
if not results:
st.info("Set your API key and click **▶ Run 3 calls** to start.")
st.stop()
if any(r.get("hit_token_cap") for r in results):
st.warning(
f"One or more calls hit the {MAX_OUTPUT_TOKENS:,}-token cap. "
"Raise MAX_OUTPUT_TOKENS if medium and high still look similar."
)
scorer_spend = sum(r.get("scorer_cost_usd", 0) for r in results)
if scorer_spend > 0:
st.caption(
f"Auto-scoring used {SCORER_MODEL} and added "
f"${scorer_spend:.6f} across all three responses."
)
# Per-call metric cards
st.subheader("Per-call results")
scores = {e: int(st.session_state.get(f"quality_{e}", DEFAULT_QUALITY[e]))
for e in EFFORT_ORDER}
mcols = st.columns(3)
for row, col in zip(results, mcols):
effort = row["effort"]
with col:
st.metric(f"{effort.upper()} effort", f"{row['out_tokens']:,} output tokens")
st.caption(
f"Input: {row['in_tokens']:,} · "
f"Latency: {row['latency_ms']/1000:.2f}s · "
f"Cost: ${row['cost_usd']:.5f} · "
f"Stop: {row.get('stop_reason', 'n/a')}"
)
st.slider(
f"Quality score — {effort.UPPER()}",
min_value=0, max_value=100,
value=DEFAULT_QUALITY[effort],
key=f"quality_{effort}",
)
if row.get("rationale"):
st.caption(f"Auto-scored by {SCORER_MODEL}: {row['rationale']}")
st.divider()
# Tabs
t1, t2, t3, t4 = st.tabs(
["Quality vs cost", "Volume projection", "Raw responses", "Raw data"]
)
with t1:
left, right = st.columns([1.1, 1], gap="large")
with left:
st.plotly_chart(quality_tradeoff_chart(results, scores),
use_container_width=True)
with right:
low = next((r for r in results if r["effort"] == "low"), None)
med = next((r for r in results if r["effort"] == "medium"), None)
high = next((r for r in results if r["effort"] == "high"), None)
if low and med and high:
st.markdown("#### Read on the current anchor set")
st.write(
f"Low → medium adds **${med['cost_usd'] - low['cost_usd']:.5f}** per call "
f"for **{scores['medium'] - scores['low']}** quality points."
)
st.write(
f"Medium → high adds **${high['cost_usd'] - med['cost_usd']:.5f}** per call "
f"for **{scores['high'] - scores['medium']}** more quality points."
)
st.write(
f"High vs low: **${high['cost_usd'] - low['cost_usd']:.5f}** "
f"total per-call delta."
)
st.caption(
"Quality scores are auto-generated by Haiku 4.5 using a rubric, "
"but you can override them with the sliders above."
)
with t2:
st.plotly_chart(projection_chart(results, tasks), use_container_width=True)
st.plotly_chart(breakeven_chart(results), use_container_width=True)
if low and high:
daily_delta = (high["cost_usd"] - low["cost_usd"]) * tasks
monthly_delta = daily_delta * 30
st.caption(
f"High vs low at {tasks:,} tasks/day: "
f"**+${daily_delta:.4f}/day** · **+${monthly_delta:.2f}/month**"
)
with t3:
for row in results:
with st.expander(
f"{row['effort'].upper()} — {row['out_tokens']:,} tokens",
expanded=True,
):
if row.get("rationale"):
st.info(
f"Auto-score: **{scores[row['effort']]}/100**. "
f"{row['rationale']}"
)
st.markdown(row["response"])
with t4:
df = pd.DataFrame([{
"Effort": r["effort"],
"Quality score": scores[r["effort"]],
"Input tokens": r["in_tokens"],
"Output tokens": r["out_tokens"],
"Latency (s)": round(r["latency_ms"] / 1000, 2),
"Cost / call ($)": round(r["cost_usd"], 6),
"Auto-score cost ($)": round(r.get("scorer_cost_usd", 0), 6),
f"Daily @ {tasks} tasks ($)": round(r["cost_usd"] * tasks, 4),
f"Monthly @ {tasks} tasks/day ($)": round(r["cost_usd"] * tasks * 30, 2),
} for r in results])
st.dataframe(df, use_container_width=True, hide_index=True)
st.download_button(
"Download CSV",
df.to_csv(index=False),
file_name="effort_dial_results.csv",
mime="text/csv",
)
if __name__ == "__main__":
main()
साइडबार सभी कॉन्फ़िगरेशन संभालता है—API key लोड करना, इनपुट के लिए प्रॉम्प्ट, और tasks-per-day स्लाइडर—जिससे मुख्य पैनल परिणामों के लिए साफ़ रहता है। मुख्य पैनल को चार टैब में बाँटा गया है ताकि वर्कफ़्लो संरचित रहे।

- quality vs cost टैब प्राथमिक दृश्य है। यह x-अक्ष पर लागत और y-अक्ष पर गुणवत्ता के साथ स्कैटर प्लॉट दिखाता है, साथ ही प्रति-स्टेप लागत और गुणवत्ता डेल्टा का पाठ-सारांश।

- वॉल्यूम प्रोजेक्शन टैब decision-support परत है। यह grouped बार चार्ट और breakeven लाइन चार्ट दिखाता है, ताकि पाठक साइडबार स्लाइडर से अपने वास्तविक task वॉल्यूम पर effort trade-off लागत का प्रोजेक्शन कर सकें।
- raw responses टैब हर effort स्तर पर पूर्ण मॉडल आउटपुट को expandable सेक्शनों में दिखाता है, जिनके ऊपर Haiku auto-score का rationale पिन किया रहता है। यहीं पाठक वास्तविक उत्तर पढ़कर आँक सकते हैं कि गुणवत्ता स्कोर सही लगते हैं या नहीं।

- raw data टैब पूर्ण परिणामों को DataFrame के रूप में दिखाता है, CSV डाउनलोड बटन के साथ—उनके लिए उपयोगी जो अलग-अलग प्रॉम्प्ट के साथ डेमो कई बार चलाकर ऐप के बाहर रन की तुलना करना चाहते हैं।
बैकएंड, चार्ट्स, और UI तैयार होने के साथ, ऐप चलाने के लिए तैयार है।
स्टेप 8: ऐप चलाएँ
Streamlit सर्वर शुरू करें:
streamlit run effort_dial.py
http://localhost:8501 खोलें और डिफॉल्ट प्रॉम्प्ट रखें या अपनी पाइपलाइन से कुछ और रखें, फिर Run 3 calls पर क्लिक करें।
ऐप हर effort स्तर को क्रम से चलाता है और हर एक के पूरा होते ही एक स्टेटस कार्ड दिखाता है। तीनों पूरे होने पर, यह तीन Haiku स्कोरिंग कॉल चलाता है और चार्ट भरता है। डिफॉल्ट प्रॉम्प्ट पर कुल wall-clock समय आमतौर पर 2–3 मिनट होता है, जिसका अधिकांश हिस्सा high-effort कॉल लेती है।
परिणाम पढ़ना
यहाँ rate-limiting प्रॉम्प्ट पर एक प्रतिनिधि रन के आँकड़े हैं:
|
Effort |
Output tokens |
Latency |
Cost/call |
Auto-score |
|
Low |
3,276 |
46s |
$0.0827 |
72/100 |
|
Medium |
5,109 |
70s |
$0.1285 |
82/100 |
|
High |
5,382 |
71s |
$0.1354 |
92/100 |
यहाँ कुछ बातें खास रहीं:
-
टोकन काउंट क्रम में हैं (3,276 -> 5,109 -> 5,382) और तीनों में stop reason
end_turnहै। यह पुष्टि करता है कि effort पैरामीटर सही से लागू हो रहा है और उत्तर स्वाभाविक रूप से पूरे हो रहे हैं। -
low से medium पर गुणवत्ता में +10 अंकों की छलांग की प्रति कॉल लागत $0.046 है। medium से high पर +10 अंकों की छलांग की लागत केवल $0.007 है। medium लगभग वही गुणवत्ता लाभ बहुत कम अतिरिक्त लागत पर दिलाता है, जो high तक अंतिम कदम लेने में लगता।
-
स्कैटर प्लॉट यह असमानता तुरंत दिखा देता है। Low नीचे-बाएँ है—सस्ता पर कम पूर्ण। Medium बीच में है। High ऊपर-दाएँ है, पर medium से केवल थोड़ा महंगा है क्योंकि इस प्रॉम्प्ट पर उन दोनों स्तरों के टोकन काउंट में अंतर छोटा है।
-
Haiku स्कोरर का rationale भी शिक्षाप्रद है। low उत्तर पर उसने नोट किया: "algorithm selection और Lua scripting पर मजबूत तकनीकी गहराई, पर pod-to-shard रूटिंग लॉजिक में ठोस विवरणों की कमी और पॉड्स के बीच sharding समन्वय कैसे होता है, यह गायब है।" high पर: "सभी पाँच आवश्यकताओं को production-grade गहराई के साथ कवर करने वाला उत्कृष्ट उत्तर, EVALSHA स्क्रिप्ट्स और ठोस boundary-case उदाहरणों के साथ।"
निष्कर्ष
इस ट्यूटोरियल में, हमने एक Streamlit ऐप बनाया जो Claude Opus 4.8 के तीन वास्तविक API कॉल (हर effort स्तर पर एक) चलाता है, हर उत्तर को Haiku 4.5 से स्वतः स्कोर करता है, और आपके task वॉल्यूम पर लागत प्रोजेक्ट करता है।
मुख्य विचार यह थे कि effort और thinking: {type: "adaptive"} साथ मिलकर तर्क की गहराई नियंत्रित करते हैं, और एक सस्ता जज मॉडल नगण्य लागत पर दोहराने योग्य rubric के साथ मैन्युअल स्कोरिंग की जगह ले सकता है। हमने यह भी देखा कि cost-quality frontier रैखिक नहीं है—यानी medium effort, high effort के अतिरिक्त लागत के एक अंश में अधिकांश गुणवत्ता लाभ पकड़ लेता है।
1,000 tasks प्रति दिन पर, high से medium पर स्विच करने से लगभग $207/माह की बचत होती है, जबकि 100-बिंदु rubric पर गुणवत्ता स्कोर में करीब 10 बिंदु की गिरावट आती है। वर्गीकरण, निष्कर्षण, या सारांश जैसे अच्छी तरह परिभाषित कार्यों के लिए medium अक्सर पर्याप्त होता है। परंतु गहरे तकनीकी तर्क या व्यापक edge-case कवरेज माँगने वाले कार्यों—जैसे code review, आर्किटेक्चर डिज़ाइन, और नीति विश्लेषण—के लिए high effort अपनी लागत वसूल कर देता है।
यहाँ से कुछ विस्तार यह हो सकते हैं कि एक दूसरा प्रॉम्प्ट प्रकार जोड़ें, जिससे दिखे कि जब समस्या को गहरे तर्क की ज़रूरत नहीं होती तो effort डेल्टा कैसे सिमट जाता है; या एक side-by-side उत्तर दृश्य जोड़ें जो ठीक-ठीक हाइलाइट करे कि जहाँ high effort ठोस विवरण जोड़ता है जो medium चूक जाता है।
Claude Opus 4.8 API ट्यूटोरियल FAQs
मैं Claude Opus 4.8 पर temperature क्यों सेट नहीं कर सकता?
Claude Opus 4.8 sampling पैरामीटर्स के overrides को सपोर्ट नहीं करता। non-default temperature, top_p, या top_k पास करने पर 400 त्रुटि मिलती है। इसके बजाय response शैली निर्देशित करने के लिए prompting तकनीकें उपयोग करें।
अगर मैं thinking: {type: "adaptive"} छोड़ दूँ तो क्या होगा?
Adaptive thinking सक्षम किए बिना effort पैरामीटर का कोई असर नहीं होता। इसके बिना, आप जो भी effort मान पास करें, तीनों कॉल एक जैसे बर्ताव करेंगे।
तीनों कॉल्स को समानांतर में क्यों न चलाएँ?
आप ऐसा कर सकते हैं, और इससे wall time लगभग दो-तिहाई घट जाएगा। इस ट्यूटोरियल में क्रमिक तरीका जानबूझकर है, ताकि प्रोग्रेस कार्ड एक-एक करके अपडेट हों और डेमो संदर्भ में वर्कफ़्लो अधिक स्पष्ट दिखे। प्रोडक्शन में समानांतर निष्पादन चाहिए तो तीनों call_opus कॉल्स को concurrent.futures.ThreadPoolExecutor() में लपेटें।
Haiku auto-scorer कितना भरोसेमंद है?
ठोस आयामों और स्पष्ट ग्रेडिंग प्रॉम्प्ट वाले rubric के साथ, Haiku 4.5 एक ही उत्तर पर रन-दर-रन सुसंगत रहता है। यह उच्च-जोखिम कार्यों के लिए मानव मूल्यांकन का विकल्प नहीं है, पर cost-quality स्कैटर प्लॉट को एंकर करने और हर रन के बाद तीन लंबे उत्तर मैन्युअल रूप से पढ़ने की आवश्यकता हटाने के लिए पर्याप्त विश्वसनीय है।
एक सिंगल डेमो रन की कुल लागत क्या है?
MAX_OUTPUT_TOKENS=16000 के साथ rate-limiting प्रॉम्प्ट पर, एक पूर्ण रन में मॉडल आउटपुट की लागत लगभग $0.35 होती है और तीन Haiku स्कोरिंग कॉल्स की लागत $0.002 से कम—यानी कुल मिलाकर लगभग $0.35।
मैं एमएल (Gen AI) में Google Developers Expert, Kaggle 3x Expert, और Women Techmakers एंबेसडर हूँ, तथा तकनीक क्षेत्र में 3+ वर्षों का अनुभव रखती हूँ। मैंने 2020 में एक हेल्थ-टेक स्टार्टअप की सह-स्थापना की और वर्तमान में Georgia Tech से कंप्यूटर विज्ञान में मास्टर कर रही हूँ, जिसमें मेरा विशेषज्ञता क्षेत्र मशीन लर्निंग है।

