Alejandro Rioja.
AI Agents Operations

Claude API के साथ Prompt Caching: मॉडल बदले बिना अपनी इनपुट लागत घटाएं

Alejandro Rioja
Alejandro Rioja
9 मिनट पढ़ें
TL;DR

Prompt caching बड़े और स्थिर इनपुट — आपका system prompt, tool definitions, few-shot examples — की लागत को दोहराए जाने वाले requests पर सामान्य इनपुट कीमत के लगभग 10% तक घटा देता है। इसका तंत्र एक prefix match है: अपनी स्थिर सामग्री के अंत में एक cache_control मार्कर लगाएं और उसके बाद सब कुछ बदलता हुआ (volatile) रखें। कैश हिट रेट को बर्बाद करने वाली गलती है किसी timestamp या UUID को prefix में घुसने देना।

मुफ़्त न्यूज़लेटर

हर बुधवार। 28,400+ पाठक। बिना फालतू बात।

Table of contents

Open Table of contents

Prompt caching असल में क्या करता है

Claude API के हर कॉल में टोकन भेजे जाते हैं। caching के बिना, आपके request का हर टोकन — system prompt, tool definitions, few-shot examples, और user message — सामान्य इनपुट दर पर चार्ज होता है। caching के साथ, पहले request के बाद उन टोकन का एक prefix Anthropic के सर्वर पर संग्रहीत हो जाता है। आगे आने वाले उन requests पर जो उसी सटीक prefix को साझा करते हैं, आप उन्हें शुरू से दोबारा प्रोसेस करने के बजाय एक कैश read कीमत चुकाते हैं।

लागत का अंतर असली है:

एक बार जब आप break-even पार कर लेते हैं — जो किसी भी ऐसे एजेंट पर तेज़ी से होता है जो दिन में कुछ बार से ज़्यादा चलता है — तो हर अतिरिक्त कैश हिट उन टोकन पर ~90% की छूट है।

Prefix-match का नियम (invariant)

यही वह एक नियम है जिसका बाकी सब कुछ पालन करता है: कैश की कुंजी आपके rendered prompt का एक prefix match होती है।

Anthropic के सर्वर आपके prompt की शुरुआत से लेकर cache_control मार्कर तक की rendered सामग्री संग्रहीत करते हैं। अगले request पर कैश हिट होने के लिए, prompt की शुरुआत से उस मार्कर तक का हर टोकन समान होना चाहिए — बाइट दर बाइट।

prefix matching के लिए render का क्रम है: tools → system → messages। यानी आपका tools array सबसे पहले हैश होता है, फिर system block, फिर messages क्रम में।

व्यवहार में इसका मतलब यह है: स्थिर सामग्री सबसे पहले आनी चाहिए। अगर आपका system prompt किसी गतिशील चीज़ का संदर्भ देता है — मौजूदा तारीख, एक user ID, एक request trace ID — और वह cache_control मार्कर से पहले दिखती है, तो हर request पर कैश मिस होगा क्योंकि prefix बदलता रहता है।

कैश मार्कर किस पर लगाएं

सबसे ज़्यादा फ़ायदा देने वाले लक्ष्य हैं:

1. आपका system prompt

System prompts आमतौर पर सबसे बड़े स्थिर block होते हैं। एक विस्तृत एजेंट persona, व्यवहार के नियमों की एक सूची, आउटपुट फ़ॉर्मैट निर्देशों का एक सेट — यह सब उसी एजेंट के हर invocation में समान रहता है। इसे मार्क करें:

typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  system: [
    {
      type: "text",
      text: `You are a content operations agent for alejandrorioja.com.
Your job is to draft blog posts in Alejandro's voice: direct, practitioner, 
first-person, numbered lists, honest caveats. No hedging. No filler. 
Every section must earn its place.

[... 2000 more tokens of stable instructions ...]`,
      cache_control: { type: "ephemeral" },
    },
  ],
  messages: [
    {
      role: "user",
      content: "Draft a post about prompt caching.",
    },
  ],
});

system block पर cache_control: { type: "ephemeral" } Claude को बताता है कि उस block तक की हर चीज़ को कैश करे (उस block समेत)। messages array volatile है — हर request पर अलग — और कैश की सीमा से बाहर रहता है।

2. Tool definitions

अगर आपका एजेंट tools इस्तेमाल करता है, तो वे definitions काफ़ी बड़े हो सकते हैं। description, parameter names, और enum values वाला एक अच्छी तरह दस्तावेज़ किया गया tool schema प्रति tool 500–1,000 टोकन तक हो सकता है। 5 tools के साथ, यह 5,000 टोकन तक होते हैं जिन्हें आप हर कॉल पर दोबारा प्रोसेस करने के लिए चुका रहे हैं:

typescript
const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  tools: [
    {
      name: "search_airtable",
      description: "Search the Airtable content queue...",
      input_schema: { type: "object", properties: { query: { type: "string" } } },
    },
    // ... more tools ...
    {
      name: "post_to_kit",
      description: "Schedule a broadcast via the Kit API...",
      input_schema: { /* ... */ },
      // Mark the last tool to cache the entire tools array
    } as Anthropic.Tool & { cache_control: { type: "ephemeral" } },
  ],
  system: "...",
  messages: [...],
});

array में आख़िरी tool को मार्क करें। prefix match उस बिंदु से पूरे tools array को कवर करेगा।

3. messages में few-shot examples

अगर आप messages array में शुरुआती messages के रूप में स्थिर few-shot examples पास करते हैं, तो उन्हें भी कैश किया जा सकता है। उन्हें पहले N messages के रूप में संरचित करें और आख़िरी example turn को मार्क करें:

typescript
const messages: Anthropic.MessageParam[] = [
  {
    role: "user",
    content: [
      {
        type: "text",
        text: "Here are examples of posts in my voice:\n\n[Example 1...]\n\n[Example 2...]",
        cache_control: { type: "ephemeral" },
      } as Anthropic.TextBlockParam & { cache_control: { type: "ephemeral" } },
    ],
  },
  {
    role: "assistant",
    content: "Understood. I'll follow that voice.",
  },
  // The actual user turn follows — this is volatile, no cache marker
  {
    role: "user",
    content: actualUserRequest,
  },
];

क्या कैश न करें (चुपके से कैश तोड़ने वाली चीज़ें)

ये वे चीज़ें हैं जो स्थिर लगती हैं पर हैं नहीं — और ये चुपचाप आपका हिट रेट बर्बाद कर देंगी। API आपको चेतावनी नहीं देगा। आप बस हर request पर cache_creation_input_tokens देखेंगे और सोचते रहेंगे कि ऐसा क्यों है।

system prompt में timestamps। सबसे आम गलती:

typescript
// This invalidates the cache on every request
const system = `You are an agent. Current time: ${new Date().toISOString()}`;

timestamps को user message में ले जाएं, जहां उनकी जगह है:

typescript
// Stable system prompt — cacheable
const system = `You are an agent. Use the current time provided by the user.`;

// Volatile user message — not cached
const userMessage = `Current time: ${new Date().toISOString()}. Run the daily brief.`;

रैंडम UUIDs और trace IDs। वही समस्या। अगर आप logging के लिए system block में एक trace ID डालते हैं, तो हर request को एक नया prefix मिलता है।

ग़ैर-निर्धारक (non-deterministic) JSON serialization। अगर आप किसी object को system prompt में serialize करते हैं और key क्रम की गारंटी नहीं है, तो rendered string अलग हो सकती है, भले ही अंतर्निहित data वही हो। एक स्थिर key क्रम के साथ serialize करें या एक template string इस्तेमाल करें।

गतिशील few-shot चयन। अगर आप मौजूदा query के आधार पर few-shot examples चुन रहे हैं और उन्हें कैश किए गए prefix में डाल रहे हैं, तो आपने “स्थिर” prefix को query पर निर्भर बना दिया है। या तो कैश लेयर के लिए तय examples पर टिके रहें, या गतिशील examples को बिना कैश वाले message turn में ले जाएं।

अपना कैश हिट रेट सत्यापित करना

हर response में usage metadata शामिल होता है। उसे जांचें:

typescript
const response = await client.messages.create({ /* ... */ });

console.log({
  inputTokens: response.usage.input_tokens,
  cacheRead: response.usage.cache_read_input_tokens,
  cacheWrite: response.usage.cache_creation_input_tokens,
  outputTokens: response.usage.output_tokens,
});

पहले request पर: cache_creation_input_tokens शून्य से अधिक होगा, cache_read_input_tokens 0 होगा। यह write है।

कैश हिट पर: cache_read_input_tokens शून्य से अधिक होगा, cache_creation_input_tokens 0 होगा। यह read है।

अगर आप हर request पर cache_creation_input_tokens देख रहे हैं, तो आपका prefix बदल रहा है। एक log statement जोड़ें जो हर कॉल से पहले आपके rendered system prompt के पहले 200 अक्षर प्रिंट करे — एक बदलता हुआ timestamp तुरंत साफ़ नज़र आ जाएगा।

1-घंटा TTL: कब अतिरिक्त write लागत वसूल है

डिफ़ॉल्ट TTL 5 मिनट है। अगर आपका एजेंट कम बार चलता है — हर 5 मिनट में एक बार से भी कम — तो आप ज़्यादातर requests पर बिना reads पाए cache write लागत चुकाते रहेंगे।

typescript
// Opt into a 1-hour TTL
cache_control: { type: "ephemeral", ttl: "1h" }

1-घंटा write की लागत 1.25× के बजाय बेस इनपुट कीमत का ~2× होती है। गणित यह है: अगर आप प्रति घंटे 3 या उससे ज़्यादा बार कैश हिट कर रहे हैं, तो 1-घंटा TTL पैसे बचाता है। अगर आपका एजेंट दिन में एक बार चलता है (मेरे daily brief की तरह), तो 1-घंटा TTL भी मदद नहीं करेगा — आप हर बार write लागत चुका रहे हैं। उस स्थिति में, caching का फ़ायदा मामूली होता है, बशर्ते system prompt बहुत बड़ा न हो।

मेरे daily brief एजेंट का system prompt 3,000 टोकन का है पर यह दिन में एक बार चलता है। caching मदद नहीं करती। मेरा newsletter एजेंट draft करते समय प्रति session दर्जनों बार चलता है — caching काफ़ी बचत करती है।

Pre-warming: पहले request को सस्ता बनाना

अगर आपको पता है कि कोई traffic spike आने वाला है — एक batch job, एक API लॉन्च — तो आप एक कम लागत वाले डमी request से कैश को पहले से गर्म (pre-warm) कर सकते हैं:

typescript
// Pre-warm: write the cache at near-zero output cost
await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1, // minimal output
  system: [{ type: "text", text: stableSystemPrompt, cache_control: { type: "ephemeral" } }],
  messages: [{ role: "user", content: "ping" }],
});

// Now the real requests read from cache

यह ज़्यादातर batch processing के लिए उपयोगी है, जहां आप कई समानांतर requests शुरू कर रहे हैं और चाहते हैं कि हर एक कैश लिखने की होड़ करने के बजाय एक गर्म कैश को हिट करे।

एजेंटिक लूप्स में prompt caching

एक multi-turn एजेंटिक लूप में, conversation history हर turn पर बढ़ती है। कैश इसे संभालने के लिए काफ़ी समझदार है: यह एक 20-block lookback window इस्तेमाल करता है, और पिछले 20 content blocks के भीतर सबसे लंबा मेल खाता prefix ढूंढता है।

व्यावहारिक निहितार्थ: अपनी स्थिर सामग्री (system prompt, tool definitions) को ऊपर ही टिकाए रखें। messages array के अंत में बढ़ती conversation history स्थिर blocks के prefix match को नहीं तोड़ेगी — वे volatile सामग्री से पहले हैं, और prefix match ऊपर से शुरू होता है।

व्यवहार में, मेरे एजेंट्स turns को इस तरह संरचित करते हैं:

code
System (cached) → Tools (cached) → Few-shot (cached) → Turn 1 → Turn 2 → ... → Current turn

कैश few-shot मार्कर तक की हर चीज़ को कवर करता है। उसके बाद बढ़ती turn history हर बार दोबारा प्रोसेस होती है, पर यह ठीक है — वे टोकन session-विशिष्ट हैं और स्थिर prefix के मुकाबले छोटे हैं।

बिल पर यह कैसा दिखता है

एक ज़्यादा बार चलने वाला एजेंट लीजिए: प्रति दिन 100 कॉल, 4,000-टोकन वाला system prompt, Sonnet कीमत।

caching के बिना:

caching के साथ (5-मिनट TTL, मान लें peak पर 50 कॉल/घंटा):

यह उन इनपुट टोकन पर लगभग 90% की कमी है। बड़े पैमाने पर — प्रति दिन 1,000 कॉल — यह अंतर और भी बढ़ता जाता है। और यह Haiku बनाम Sonnet के गणित से होने वाली किसी भी model-routing बचत के ऊपर है: caching हर टियर पर काम करती है।

ऑपरेटर का निष्कर्ष

Prompt caching, Claude API में सबसे आसान लागत-अनुकूलन है: उन्हीं content blocks पर एक अतिरिक्त field जो आप पहले से लिख रहे हैं। बाधा है prefix की स्थिरता के इर्द-गिर्द अनुशासन — कैश मार्कर से पहले कुछ भी गतिशील न हो। अगर आप अपने system prompt, tools, और किसी भी स्थिर examples को volatile सामग्री से मुक्त रख सकते हैं, तो आप हर कैश हिट पर सामान्य इनपुट लागत का ~10% चुकाएंगे। बड़े और स्थिर prompts वाले ज़्यादा बार चलने वाले एजेंट्स के लिए, यह मॉडल टियर बदलने से बड़ा लीवर है।


संबंधित: AI Agent Cost Math: When Haiku Beats Sonnet · Event-Triggered vs Scheduled Agents · The 5 AI Tools I Actually Use to Run My Business

पढ़ते रहें

AI प्लेबुक अपने इनबॉक्स में पाएं

हर बुधवार। 28,400+ पाठक। बिना फालतू बात।

↵ सभी परिणाम देखें esc esc बंद करें