KV cache বনাম prompt cache: পার্থক্য কী?
KV cache প্রতিটি request-এ server-এর RAM বা VRAM খরচ করে এবং শেষ হলে model load বা request ব্যর্থ হতে পারে। Prompt cache শুধু billing কমায়, cache miss হলে full price লাগে।
KV cache বনাম prompt cache: সংক্ষিপ্ত উত্তর
KV cache এবং কোনো provider-এর prompt cache-এর মধ্যে একটি শব্দ ছাড়া প্রায় কোনো মিল নেই। KV cache হলো প্রতিটি request-এর জন্য ব্যবহৃত working memory। একটি request যতক্ষণ সক্রিয় থাকে, ততক্ষণ এটি আপনার server-এর RAM বা VRAM-এ থাকে। context length এবং একই সময়ে চালানো request-এর সংখ্যা বাড়লে এর আকারও বাড়ে। Provider-এর prompt caching হলো billing ও latency কমানোর একটি feature। আপনার prompt-এর অপরিবর্তিত prefix provider-এর server-এ সংরক্ষিত থাকে। একই prefix আবার পাঠালে এর জন্য কম হারে charge করা হয়।
একটি হলো hardware হিসেবে কেনা memory। অন্যটি হলো অন্য কেউ ধরে রাখে এবং ব্যবহারের জন্য আপনাকে ভাড়া নেয় এমন memory।
সংজ্ঞার চেয়ে ব্যবহারিক পার্থক্য বেশি গুরুত্বপূর্ণ। KV cache শেষ হয়ে যেতে পারে। তা হলে model load হতে অস্বীকার করে অথবা request প্রত্যাখ্যাত হয়। Prompt cache শেষ হয়ে যায় না। শুধু cache hit নাও হতে পারে। তখন আপনি নীরবে full price পরিশোধ করেন।
KV cache কী ধরে রাখে এবং কেন এটি থাকে
কোনো transformer token number 500 তৈরি করার সময় তার আগের 499টি token-এর সবগুলোর দিকে attention দিতে হয়। প্রতিটি token-এর জন্য প্রতিটি layer-এ একটি key vector এবং একটি value vector প্রয়োজন। প্রতিটি নতুন token-এর সময় এগুলো আবার গণনা করলে generation-এর কাজের পরিমাণ sequence length-এর বর্গের সঙ্গে বাড়ত। তাই runtime এগুলো সংরক্ষণ করে। এই সংরক্ষিত অংশটিই KV cache (key/value cache)।
এটি প্রতি request-এর আলাদা state, কারণ এটি ওই request-এর নির্দিষ্ট token sequence থেকে তৈরি হয়। ভিন্ন prompt পাঠানো দুই ব্যবহারকারী এটি ভাগ করে নিতে পারেন না, যদি না runtime prefix caching ব্যবহার করে। এটি পরে বর্ণিত একটি পৃথক feature।
Serving দুইটি phase-এ হয়। Prefill আপনার সম্পূর্ণ prompt পড়ে cache পূরণ করে, এবং এটি compute দ্বারা সীমাবদ্ধ। Decode একবারে একটি token তৈরি করে cache-এ যোগ করে, এবং এটি memory bandwidth দ্বারা সীমাবদ্ধ। এই বিভাজনের কারণে prompt processing এবং token generation-এর গতি আলাদা দেখা যায়, যখন আপনি নিজের box-এ প্রতি সেকেন্ডে token-এর হার মাপেন।
KV cache কত মেমরি ব্যবহার করে?
কোনো vendor table খুঁজতে যাবেন না। যেকোনো model-এর জন্য এই আকারটি আবার arithmetic করে বের করা যায়:
bytes per token = 2 * layers * kv_heads * head_dim * bytes per elementএখানে 2 দিয়ে key এবং value—এই দুটি গণনা করা হয়েছে। বাকি প্রতিটি সংখ্যা model-এর config.json থেকে নেওয়া, যা model-এর Hugging Face page-এ প্রকাশিত থাকে।
Llama 3.1 8B ধরা যাক। এর config-এ num_hidden_layers 32 এবং num_key_value_heads 8 দেওয়া আছে। 4096-এর hidden_size 32টি attention head-এর মধ্যে ভাগ করলে প্রতিটি head-এর dimension হয় 128। f16-এ প্রতিটি element 2 bytes:
2 * 32 * 8 * 128 * 2 = 131072 bytes = 128 KiB per tokenআপনি যে context নির্ধারণ করেছেন, তার সঙ্গে এই মান গুণ করুন। এরপর একই সময়ে চালানো request-এর সংখ্যা দিয়ে গুণ করুন।
The data behind this chart
[
{
"label": "2k context",
"one_request_gib": 0.25,
"four_requests_gib": 1
},
{
"label": "8k context",
"one_request_gib": 1,
"four_requests_gib": 4
},
{
"label": "32k context",
"one_request_gib": 4,
"four_requests_gib": 16
},
{
"label": "128k context",
"one_request_gib": 16,
"four_requests_gib": 64
}
]8k context-এ cache-এর আকার 1 GiB। 32k context-এ এটি 4 GiB, যা 4-bit weight-এর আকারের কাছাকাছি। model-এর পূর্ণ 128k context-এ একটি request-এর জন্য এটি 16 GiB, আর চারটি request প্রত্যেকে cache পূর্ণ করলে 64 GiB। weight-এর কোনো পরিবর্তন হয়নি। শুধু cache-এর আকার পরিবর্তিত হয়েছে।
Grouped query attention (GQA) এই হিসাবের একটি বড় অংশ। Llama 3.1 8B-তে 8টি key/value head 32টি query head-কে সেবা দেয়, তাই প্রতি চারটি query head একটি সংরক্ষিত key/value pair ভাগ করে ব্যবহার করে। যে model-এর num_key_value_heads এবং num_attention_heads সমান, সেটি একই parameter count-এ চার গুণ cache ব্যবহার করে। দুটি 8B model serve করার খরচ সমান ধরে নেওয়ার আগে ওই field-টি পরীক্ষা করুন।
2k-এ চলা একটি model 32k-এ load হতে অস্বীকার করার কারণ
Runtime model load করার সময় KV cache reserve করে। এই cache-এর আকার নির্ধারিত হয় আপনার configured context length অনুযায়ী, আপনি বাস্তবে যে prompt পাঠাচ্ছেন তার দৈর্ঘ্য অনুযায়ী নয়। Ollama-এর default context window হলো 4096 tokens। এটি 32k করলে, একটি token আসার আগেই আপনি 4 GiB অতিরিক্ত allocation চেয়ে নিচ্ছেন।
OLLAMA_CONTEXT_LENGTH=32768 ollama serveInteractive prompt থেকে, প্রতি session-এর জন্য একই setting ব্যবহার করুন:
ollama run llama3.1:8b
/set parameter num_ctx 32768প্রতিটি stack-এ failure ভিন্নভাবে দেখা যায়। vLLM startup-এর সময় হিসাব যাচাই করে এবং চলতে অস্বীকার করে:
ValueError: The model's max seq len (131072) is larger than the maximum number of tokens that can be stored in KV cache (78336). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when initializing the engine.শুধু CPU ব্যবহার করা VPS-এ এমন কোনো check থাকে না, কারণ allocation সাধারণ system RAM-এ হয়। এর পরিবর্তে kernel-এর out-of-memory killer process-টি বন্ধ করে দেয় এবং kernel ring buffer-এ প্রমাণ রেখে যায়:
dmesg -T | grep -i "killed process"যে line-এ আপনার serving process-এর নাম আছে, সেটি বোঝায় যে box-এর available memory-এর চেয়ে বেশি memory প্রয়োজন ছিল। সমাধান হলো ছোট context ব্যবহার করা, বড় swap file নয়। Disk-এ paged করা KV cache প্রতিটি generated token-এর সময় পড়তে হয়। ফলে generation এত ধীর হয়ে যায় যে তা ব্যবহার অযোগ্য হয়ে পড়ে। উপযুক্ত সংখ্যা নির্ধারণের পদ্ধতি Ollama-এ num_ctx এবং context length নিয়ে আমাদের guide-এ ব্যাখ্যা করা হয়েছে।
concurrency সংখ্যাকে কীভাবে প্রভাবিত করে
প্রতিটি চলমান request নিজের KV cache বহন করে। Capacity plan-এ সাধারণত এই বিষয়টি বাদ পড়ে। 32k context ধরে রাখা চারজন user-এর জন্য weights-এর অতিরিক্ত হিসেবে মোট 16 GiB প্রয়োজন।
এই ব্যবহারের কঠোরতা runtime ভেদে আলাদা। Ollama এবং llama.cpp model load করার সময় আপনার নির্ধারিত context-এর জন্য memory reserve করে। তাই কেউ সেটি ব্যবহার না করলেও memory committed থাকে। vLLM pool-কে নির্দিষ্ট আকারের block-এ ভাগ করে এবং প্রতিটি request বড় হওয়ার সঙ্গে সঙ্গে block বরাদ্দ করে। ফলে 500-token-এর request কেবল 500 token-এর সমপরিমাণ memory ধরে রাখে। উভয় ক্ষেত্রেই pool-এর আকার সীমিত। pool পূর্ণ হলে নতুন request চলার বদলে queue-তে অপেক্ষা করে। এই queueing response time-এ কী প্রভাব ফেলে, তা self-hosted LLM কতজন concurrent user-কে সেবা দিতে পারে অংশে ব্যাখ্যা করা হয়েছে।
KV cache ছোট করার 4টি উপায়
- Context length কমান। এটি সবচেয়ে বড় প্রভাব ফেলে এবং সাধারণত সবচেয়ে কম খরচের পদ্ধতি। অধিকাংশ chat workload কখনোই 32k-এর কাছাকাছি যায় না।
- KV cache-এ নিজেই quantisation প্রয়োগ করুন। Ollama-র
OLLAMA_KV_CACHE_TYPEডিফল্টভাবেf16ব্যবহার করে এবংq8_0গ্রহণ করে, যা প্রায় অর্ধেক memory ব্যবহার করে, এবংq4_0গ্রহণ করে, যা প্রায় এক-চতুর্থাংশ memory ব্যবহার করে। llama.cpp-তে এর সমতুল্য হলো-ctk q8_0এবং-ctv q8_0। - কম key/value head বা কম layer-যুক্ত model বেছে নিন। 40 GB weight download করার আগে
config.jsonপড়ুন। - একসঙ্গে কম request পরিবেশন করুন এবং বাকি request queue করুন।
q4_0-এ Llama 3.1 8B-এর পরিমাণ প্রতি token-এ 128 KiB থেকে কমে প্রায় 32 KiB হয়। ফলে 32k context-এর জন্য 4 GiB-এর পরিবর্তে প্রায় 1 GiB লাগে। এই সাশ্রয় বিনামূল্যে নয়। Key এবং value কম precision-এ সংরক্ষিত হয়। তাই এই সেটিং স্থায়ীভাবে ব্যবহারের আগে নিজের prompt দিয়ে output তুলনা করুন।
Provider prompt caching আসলে যে সুবিধা দেয়
Provider prompt caching একটি ভিন্ন ধরনের product, যার হিসাবের এককও ভিন্ন। আপনি একটি স্থিতিশীল prefix চিহ্নিত করেন। Provider সেটি সংরক্ষণ করে। পরে একই prefix হুবহু পুনরায় পাঠানো হলে সম্পূর্ণ input price-এর পরিবর্তে কম হারে billing হয়।
August 2026 অনুযায়ী Anthropic-এর প্রকাশিত multiplier হলো: 5-minute cache write-এর খরচ base input token price-এর 1.25 গুণ। 1-hour write-এর খরচ 2 গুণ। Cache read-এর খরচ 0.1 গুণ। 20,000-token system prompt-এর ক্ষেত্রে হিসাবটি কীভাবে কাজ করে, তা এতে স্পষ্ট হয়।
The data behind this chart
[
{
"label": "No caching, every call",
"billed_token_equivalents": "20,000"
},
{
"label": "First call, 5 minute cache write",
"billed_token_equivalents": "25,000"
},
{
"label": "First call, 1 hour cache write",
"billed_token_equivalents": "40,000"
},
{
"label": "Every later call, cache hit",
"billed_token_equivalents": "2,000"
}
]এটিকে arithmetic হিসেবে দেখুন। প্রথম call-এ 5-minute write premium হলো 5,000 token equivalent: uncached অবস্থায় এটি পাঠানোর জন্য 20,000-এর বিপরীতে billing হবে 25,000। Window-এর মধ্যে পরবর্তী প্রতিটি call-এ 20,000-এর পরিবর্তে billing হবে 2,000; সাশ্রয় হবে 18,000। তাই দ্বিতীয় call থেকে 5-minute cache লাভজনক হয়ে যায়।
1-hour cache একটি ভিন্ন হিসাব। Write-এর সময় billing হবে 40,000। অর্থাৎ premium হলো 20,000 token equivalent। তাই লাভজনক হতে hour-এর মধ্যে এটি দুইবার hit পেতে হবে। এটি আপনার traffic pattern-এর প্রশ্ন, model-এর নয়। Window কীভাবে নির্বাচন করবেন এবং সম্পূর্ণ হিসাব Claude prompt caching-এর break-even math-এ দেওয়া আছে।
Cache hit হবে কি না, তা দুটি বিষয় নির্ধারণ করে। প্রথমত, prefix model-এর minimum length-এর চেয়ে ছোট হলে তা নীরবে cache করা হয় না। August 2026 অনুযায়ী নথিভুক্ত minimum হলো Claude Opus 5-এর জন্য 512 tokens এবং Claude Sonnet 5-এর জন্য 1,024 tokens। ছোট request স্বাভাবিকভাবে process হয় এবং কোনো error ফেরত আসে না। দ্বিতীয়ত, entry যে request write বা read করে, তার শুরু থেকে lifetime গণনা করা হয়। প্রতিটি read অতিরিক্ত খরচ ছাড়াই lifetime আবার refresh করে। তাই ব্যস্ত endpoint একটি 5-minute cache অনির্দিষ্টকাল সক্রিয় রাখতে পারে। প্রতি দশ মিনিটে একবার call করা endpoint প্রতিবার write premium দেয়, কিন্তু কোনো cache read পায় না।
অনুমান না করে response পরীক্ষা করুন। usage object-এ cache_creation_input_tokens এবং cache_read_input_tokens report করা হয়। প্রতিটি call-এ read count শূন্য হলে বুঝবেন, আপনি write-এর জন্য খরচ করছেন কিন্তু কোনো সুবিধা পাচ্ছেন না।
যেখানে দুই ধরনের cache একে অপরের সঙ্গে যুক্ত
একটি দীর্ঘ system prompt হলো সেই সংযোগস্থল, এবং এটি একই সময়ে উভয় দিকের খরচ তৈরি করে।
স্থানীয়ভাবে, f16-এ Llama 3.1 8B server-এ 20,000-token system prompt প্রায় 2.4 GiB KV cache দখল করে। এই prompt-সহ প্রতিটি concurrent request-এর জন্য এটি আলাদাভাবে প্রয়োজন হয়। দূরবর্তী provider-এর ক্ষেত্রে একই prefix-এর জন্য প্রথমে একটি cache write হয়, এরপর প্রতিটি call-এ input-এর 0.1 গুণ খরচ হয়। স্থানীয় খরচ আপনার user-এর সংখ্যার সঙ্গে বাড়ে। দূরবর্তী খরচ আপনার traffic-এর সঙ্গে বাড়ে এবং idle সময়ে cache reset হয়।
এখানে একটি স্থানীয় feature আছে, যা provider prompt caching-এর মতো দেখায় এবং প্রায়ই সেটির সঙ্গে গুলিয়ে ফেলা হয়: prefix caching। vLLM documentation-এ automatic prefix caching-কে এভাবে বর্ণনা করা হয়েছে: “existing queries-এর KV cache cache করা, যাতে নতুন query কোনো existing query-এর সঙ্গে একই prefix ভাগ করলে সরাসরি সেই KV cache পুনরায় ব্যবহার করতে পারে”। llama.cpp server ডিফল্টভাবে প্রতিটি slot-এর জন্য একটি prompt cache রাখে, এবং --cache-reuse N নির্ধারণ করে পুনরায় ব্যবহারের চেষ্টা করার জন্য সর্বনিম্ন chunk কত বড় হবে।
prefix caching যে সাশ্রয় করে, তা হলো prefill compute। আপনার 20,000-token system prompt প্রতিটি request-এ পুনরায় process না করে একবার process করা হয়। এতে time to first token উল্লেখযোগ্যভাবে কমে। vLLM-এ shared block পুনরায় ব্যবহার করা হয়, duplicate করা হয় না। ফলে memory usage-ও কমে। তবে বর্তমানে সক্রিয় token-এর জন্য যে cache ধরে রাখতে হয়, prefix caching কখনো সেটির আকার কমায় না। request-এর মাঝেও weights resident রাখা একটি সম্পর্কিত কিন্তু আলাদা উপায়। এটি request-এর মধ্যে একটি Ollama model loaded রাখা-এ ব্যাখ্যা করা হয়েছে।
আপনার নিজের মেশিনে যা মাপবেন
আপনার নির্ধারিত context-এ model load করুন। এরপর estimate-এর ওপর নির্ভর না করে প্রকৃত সংখ্যা দেখুন।
ollama ps
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
free -gollama ps loaded model-এর size এবং সেটি GPU নাকি CPU-তে চলছে তা দেখায়। কোনো model পুরোপুরি GPU-তে থাকার কথা থাকলেও যদি CPU split দেখায়, তাহলে KV cache model-এর একটি অংশ GPU-এর বাইরে ঠেলে দিয়েছে। ফলে generation speed কমে যাবে। nvidia-smi প্রকৃত VRAM-এর পরিমাণ দেখায়। CPU-only VPS-এ একই কাজ করে free -g। context ধাপে ধাপে বাড়ান, model reload করুন এবং সংখ্যাটি কীভাবে পরিবর্তিত হয় তা monitor করুন। আপনার হিসাব এবং প্রদর্শিত সংখ্যা কাছাকাছি হওয়া উচিত। তা না হলে পার্থক্যটি সাধারণত formula-র ভুল নয়; runtime-এর নিজস্ব compute buffer-এর কারণে হয়।
এই সংখ্যাগুলো যদি এমন hardware নেওয়ার দিকে ঠেলে দেয় যা আপনি ভাড়া করতে চান না, তাহলে token-প্রতি অর্থপ্রদানের সঙ্গে তুলনাটি GPU VPS বনাম API token-এ ব্যাখ্যা করা হয়েছে।
FAQ
KV cache কি prompt caching-এর একই বিষয়?
না। KV cache হলো serving process-এর ভিতরের request-প্রতি memory। এতে বর্তমান context-এর প্রতিটি token-এর key ও value vector থাকে। এটি আপনার RAM বা VRAM-এ থাকে এবং request শেষ হলে ছেড়ে দেওয়া হয়। Provider prompt caching হলো billing feature। এটি provider-এর infrastructure-এ একটি স্থিতিশীল prompt prefix সংরক্ষণ করে এবং আপনি সেটি আবার পাঠালে কম rate প্রয়োগ করে। KV cache শেষ হয়ে গেলে model load হয় না। Prompt cache না থাকলে শুধু আপনার invoice এবং first token পাওয়ার সময় বাড়ে।
আমার model 2k context-এ load হয়, কিন্তু 32k-এ ব্যর্থ হয় কেন?
কারণ runtime load করার সময় পুরো KV cache allocate করে। এই cache আপনার পাঠানো prompt-এর পরিবর্তে configured context length অনুযায়ী নির্ধারিত হয়। Llama 3.1 8B-এর জন্য f16-এ প্রতি token-এ cache লাগে 128 KiB। তাই 2k context-এর জন্য লাগে 0.25 GiB এবং 32k-এর জন্য লাগে 4 GiB। উভয় ক্ষেত্রেই weights memory-তে fit করে। ব্যর্থ হয় cache reservation। vLLM এটি একটি ValueError হিসেবে report করে। এতে সর্বোচ্চ কত token সংরক্ষণ করা সম্ভব, তা উল্লেখ থাকে। vLLM gpu_memory_utilization বাড়ানো বা max_model_len কমানোর পরামর্শ দেয়। শুধু CPU-নির্ভর সিস্টেমে kernel-এর out-of-memory killer পরিবর্তে process বন্ধ করে দেয়। dmesg -T | grep -i "killed process" দিয়ে এটি নিশ্চিত করতে পারেন।
আমার model-এর KV cache-এর আকার কীভাবে হিসাব করব?
Layer count, key/value head-এর সংখ্যা, head dimension এবং প্রতি element-এর bytes—এই মানগুলোকে 2 দিয়ে গুণ করুন। এতে প্রতি token-এর জন্য প্রয়োজনীয় bytes পাওয়া যায়। এরপর এই মানকে context length এবং একসঙ্গে চলা request-এর সংখ্যা দিয়ে গুণ করুন। Model-এর config.json থেকে layer ও head-এর সংখ্যা দেখুন। f16 বা bf16-এর জন্য প্রতি element-এ 2 bytes ব্যবহার করুন। q8_0 cache-এর আকার এর প্রায় অর্ধেক এবং q4_0-এর আকার প্রায় এক-চতুর্থাংশ।
Prompt caching কি আমার নিজের server-এর প্রয়োজনীয় memory কমায়?
Provider prompt caching আপনার hardware-এর জন্য কিছু করে না, কারণ storage provider-এর দিকেই থাকে। স্থানীয় বিকল্প হলো prefix caching, যা vLLM এবং llama.cpp server উভয়ই সমর্থন করে। এটি shared prefix-এর আগে গণনা করা key ও value vector পুনরায় ব্যবহার করে। ফলে prefill compute কমে এবং first token পাওয়ার সময় কমে। vLLM-এ shared block-গুলো duplicate না করে পুনরায় ব্যবহার করা হয়, তাই memory ব্যবহারেরও উন্নতি হয়। তবে কোনো feature-ই বর্তমানে in-flight token-এর জন্য প্রয়োজনীয় cache ছোট করে না। তাই context এবং concurrency-এর হিসাবই ন্যূনতম প্রয়োজন নির্ধারণ করে।
যে prompt আমি শুধু একবার পাঠাব, সেটি cache করা কি উপযোগী?
না। সাধারণ input-এর তুলনায় cache write-এর খরচ বেশি। August 2026 অনুযায়ী 5-minute option-এর জন্য base rate-এর 1.25 গুণ খরচ হয়। তাই window-এর মধ্যে যে prefix আর কখনও পাঠানো হবে না, সেটি cache করা সরাসরি ক্ষতির কারণ। একই prefix বারবার পাঠালে caching উপযোগী হয়। যেমন, দীর্ঘ system prompt বা এমন একটি document, যার বিষয়ে আপনি একাধিক প্রশ্ন করবেন। Write-এর জন্য অর্থ না দিয়ে cache hit পাচ্ছেন কি না নিশ্চিত করতে API response-এ cache_read_input_tokens দেখুন।