প্রম্পট ক্যাশিং (prompt caching) চালু করে আমার কোনো লাভ হয়নি—বরং, আমার OpenAI-API ইনভয়েস প্রায় এক চতুর্থাংশ বেড়ে গেল। এর কারণ ছিল একটি মাত্র লাইন যা প্রতিবার রিকোয়েস্টের সাথে পরিবর্তিত হচ্ছিল: সিস্টেম প্রম্পটে অন্তর্ভুক্ত একটি টাইমস্ট্যাম্প (timestamp)।

LLM প্রোভাইডাররা টোকেন প্রসেসিং খরচ কমানোর জন্য ডেভেলপারদের প্রম্পট ফ্র্যাগমেন্ট (prompt fragments) ক্যাশ করার সুযোগ দেয়। একটি ক্যাশ রিড (একটি “hit”) সাধারণ রেটের মাত্র এক-দশমাংশ খরচ করে, যেখানে একটি ক্যাশ রাইট (একটি “miss”) সাধারণ মূল্যের প্রায় ১.২৫ গুণ খরচ করে। যদি একটি রাইট ঘটে কিন্তু ক্যাশ করা ফ্র্যাগমেন্টটি কখনও পড়া না হয়, তবে অতিরিক্ত ২৫% চার্জ বৃথা যায়। ঠিক এটাই ঘটেছিল যখন টাইমস্ট্যাম্পের কারণে প্রম্পটটি বিদ্যমান কোনো ক্যাশ এন্ট্রির সাথে মিলতে পারছিল না।

কেন ক্যাশিং উল্টো ফল দিতে পারে

প্রম্পট ক্যাশিং কাজ করে ক্যাশ করা অংশের নির্ভুল (exact) বাইট সিকোয়েন্সের সাথে মিলিয়ে। প্রোভাইডার ইনপুটটিকে হ্যাশ (hash) করে; যদি হ্যাশটি সংরক্ষিত কোনো এন্ট্রির সাথে মিলে যায়, তবে সিস্টেমটি পূর্বের কম্পিউটেশন পুনরায় ব্যবহার করে এবং সস্তা রিড রেট প্রয়োগ করে। যেকোনো ধরনের পরিবর্তন—এমনকি একটি মাত্র অক্ষরও—মিল নষ্ট করে দেয় এবং একটি নতুন কম্পিউটেশন করতে বাধ্য করে, যার জন্য উচ্চতর রাইট রেটে বিল করা হয়।

আমার ক্ষেত্রে সিস্টেম প্রম্পটটি শুরু হয়েছিল এভাবে:

Current session started: 2026-07-14T09:41:07Z

যেহেতু প্রতিটি API কলের জন্য টাইমস্ট্যাম্প আপডেট হচ্ছিল, তাই রিকোয়েস্টের প্রথম কয়েকটি বাইট কখনোই একই ছিল না। প্রোভাইডার প্রতিটি কলকে একটি নতুন ক্যাশ এন্ট্রি হিসেবে গণ্য করেছিল, রাইট প্রিমিয়াম চার্জ করেছিল এবং কখনও কোনো রিড রেকর্ড করেনি। এর ফলে cache_creation_input_tokens-এর ক্রমাগত বৃদ্ধি ঘটছিল, যেখানে cache_read_input_tokens শূন্য ছিল—যা একটি স্পষ্ট লক্ষণ ছিল যে ক্যাশটি কখনও ব্যবহৃত (hit) হচ্ছিল না।

কীভাবে একটি ত্রুটিপূর্ণ ক্যাশ শনাক্ত করবেন

API দ্বারা সরবরাহ করা ইউসেজ লগ দুটি মূল কাউন্টার প্রদান করে:

  • cache_creation_input_tokens – সেই টোকেন যা একটি রাইট ট্রিগার করেছে।
  • cache_read_input_tokens – সেই টোকেন যা রিড থেকে সুবিধা পেয়েছে।

যখন প্রথমটি বাড়ে এবং দ্বিতীয়টি স্থির থাকে, তখন বোঝা যায় যে ক্যাশটি পুনরায় ব্যবহার করা হচ্ছে না। একটি দ্রুত যাচাই করার উপায় হলো ঠিক একই রিকোয়েস্ট দুবার পাঠানো; ক্যাশ যদি সঠিকভাবে কাজ করে, তবে দ্বিতীয় কলে রিড টোকেনের সংখ্যা বৃদ্ধি পাওয়া উচিত।

সমস্যাটি সমাধান করা

সমাধানটি সহজ: নিশ্চিত করুন যে ক্যাশ করা অংশটি কলগুলোর মধ্যে স্থির (static) থাকে। এই দুটি নিয়ম অনুসরণ করুন:

১. অপরিবর্তনযোগ্য (immutable) কন্টেন্ট আগে রাখুন। সিস্টেম প্রম্পট, টুল ডেফিনিশন, বা এমন কোনো নির্দেশনা যা কখনোই পরিবর্তন হয় না, তা রিকোয়েস্টের শুরুর বাইটগুলোতে থাকা উচিত। ২. পরিবর্তনশীল (mutable) কন্টেন্ট শেষে যুক্ত করুন। টাইমস্ট্যাম্প, ইউজার-জেনারেটেড টেক্সট, রিকোয়েস্ট আইডি, বা এমন কোনো ডেটা যা প্রতি কলের সাথে পরিবর্তিত হয়, তা অবশ্যই ক্যাশ করা সেগমেন্টের পরে আসতে হবে।

যদি একটি অক্ষরও সরে যায়, তবে হ্যাশ পরিবর্তিত হয়ে যায় এবং ক্যাশ মিস (cache miss) চলতে থাকে। প্রম্পটটি এমনভাবে সাজানো যাতে টাইমস্ট্যাম্পটি শেষে থাকে, তা ক্যাশ হিট রেট পুনরুদ্ধার করে এবং বিলকে প্রত্যাশিত স্বল্পমূল্যের স্তরে ফিরিয়ে আনে।

কখন ক্যাশিং প্রকৃতপক্ষে সাহায্য করে

প্রম্পট ক্যাশিং সেই সব ক্ষেত্রে দারুণ কাজ করে যেখানে একই নির্দেশাবলী বারবার ব্যবহার করা হয়:

  • Agent loops যেখানে একটি AI বারবার নির্দিষ্ট কিছু টুলের সাহায্য নেয়।
  • Chat sessions যেখানে একটি দীর্ঘ, স্থির ডকুমেন্ট রেফারেন্স হিসেবে থাকে এবং শুধুমাত্র ইউজারের সর্বশেষ প্রশ্নটি পরিবর্তিত হয়।
  • Bulk data extraction যেখানে অনেকগুলো রেকর্ডের জন্য একই পার্সিং প্রম্পট প্রয়োগ করা হয়।

সিঙ্গেল-শট কলের ক্ষেত্রে, যেখানে প্রতিবার নতুন কনটেক্সট থাকে—যেমন একটি অনন্য ভূমিকা সহ একটি একক প্রশ্ন—সেখানে ক্যাশিং কোনো সুবিধা দেয় না এবং রিকোয়েস্টটি যদি অনিচ্ছাকৃতভাবে একটি রাইট ট্রিগার করে, তবে তা খরচ বাড়িয়ে দিতে পারে।

লুকানো বিপদসমূহ

প্রম্পটটি স্থির থাকলেও, রিকোয়েস্টটি পরবর্তী ধাপে পরিবর্তিত হতে পারে:

  • Proxies বা aggregators যা ক্রম পরিবর্তন করে বা হোয়াইটস্পেস (whitespace) যোগ করে, তা বাইট-বাইটে মিল নষ্ট করতে পারে।
  • Gateway services যা অথেন্টিকেশন হেডার যুক্ত করে বা JSON ফরম্যাটিং পরিবর্তন করে, তা অনিচ্ছাকৃতভাবে ক্যাশ করা ফ্র্যাগমেন্ট পরিবর্তন করে দিতে পারে।

গেটওয়ের মাধ্যমে একই রিকোয়েস্ট দুবার পাঠিয়ে এবং রিড কাউন্টার পরীক্ষা করে যাচাই করা যায় যে ক্যাশিং পাথটি ঠিক আছে কি না।

খরচের সামগ্রিক চিত্র

রাইটের ওপর ২৫% অতিরিক্ত চার্জ ক্যাশিং ব্যবহারের জন্য কোনো জরিমানা নয়; এটি ভবিষ্যতে পুনরায় ব্যবহারের জন্য ফ্র্যাগমেন্টটি সংরক্ষণ করতে প্রয়োজনীয় অতিরিক্ত কম্পিউটেশনকে নির্দেশ করে। যখন একটি ক্যাশ হিট ঘটে, তখন খরচ নাটকীয়ভাবে কমে যায়—প্রায় অনেক ক্ষেত্রে সাধারণ রেটের একটি ক্ষুদ্র অংশে। মূল বিষয়টি হলো সিস্টেমকে প্রকৃতপক্ষে ক্যাশ হিট করতে দেওয়া। অন্যথায়, আপনি কোনো সাশ্রয় ছাড়াই প্রিমিয়াম মূল্য পরিশোধ করবেন।

পাল্টা যুক্তি: ক্যাশিং মরে যায়নি

Some developers argue that the complexity of managing static versus dynamic prompt parts outweighs the savings. That view overlooks the fact that many production pipelines already separate configuration (static) from user data (dynamic). By structuring prompts accordingly, the same caching mechanism that saved the original developers of the API can be leveraged without extra effort. The trade-off is a modest discipline in prompt design, not a fundamental flaw in the technology.

What to watch next

  • Monitor the two cache counters in your usage dashboard weekly.
  • Audit prompt construction to confirm that any variable element sits after the cached block.
  • Run A/B tests with and without caching on a representative workload to quantify actual savings.
  • Validate the gateway by comparing raw request payloads before and after any proxy.

Takeaway

Prompt caching can slash LLM API costs, but only if the cached segment is truly identical across calls. A stray timestamp or any other dynamic token at the start of a prompt forces a costly write every time, inflating the bill. By front-loading static instructions and relegating changing data to the tail end, you let the cache do its job and keep your expenses in check.