SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

KV cache לעומת prompt cache: מה ההבדל ואיך זה משפיע?

הבינו את ההבדל בין KV cache שצורך משאבי RAM בשרת לבין prompt caching שמוזיל עלויות. גלו מדוע ה-KV cache עלול לגרום לשגיאת Out of Memory בעוד שהשני רק משפיע על התעריף.

KV cache לעומת prompt cache: התשובה הקצרה

המונחים KV cache ו־prompt cache של ספק שירות חולקים מילה משותפת, אך מעבר לכך אין ביניהם כמעט דבר. ה־KV cache הוא זיכרון עבודה לכל בקשה (per-request). הוא שוכן ב־RAM או ב־VRAM של השרת שלכם לאורך כל משך החיים של בקשה בודדת, והוא גדל בהתאם לאורך ההקשר (context length) ולמספר הבקשות שאתם מריצים במקביל. לעומת זאת, prompt caching של ספק שירות הוא תכונה הקשורה לחיוב ולזמן תגובה (latency). תחילית קבועה של ה־prompt שלכם נשמרת בשרתי הספק, ולאחר מכן מחויבת בתעריף מוזל כאשר אתם שולחים אותה שוב.

האחד הוא זיכרון שאתם רוכשים כחומרה. השני הוא זיכרון שמישהו אחר מחזיק ואתם משלמים עליו דמי שכירות.

להבדל המעשי יש חשיבות רבה יותר מההגדרה. אתם יכולים למצות את ה־KV cache, וכאשר זה קורה, המודל מסרב להיטען או שהבקשה נדחית. לא ניתן למצות prompt cache. במקרה הגרוע פשוט לא תצליחו להשתמש במטמון (cache miss), ואז תשלמו בשקט את המחיר המלא.

מה מכיל ה-KV cache ומדוע הוא קיים

מודל Transformer שמייצר את הטוקן ה-500 חייב לבצע attention לכל 499 הטוקנים שלפניו. עבור כל אחד מהטוקנים הללו, כל שכבה זקוקה ל-key vector ו-value vector. חישוב מחדש של כולם עבור כל טוקן חדש יגרום לזמן היצירה לגדול בריבוע של אורך הרצף, לכן סביבת הריצה שומרת אותם בזיכרון. מאגר זה הוא ה-KV cache (מטמון מפתחות/ערכים).

זהו מצב (state) ברמת הבקשה, כיוון שהוא נבנה מרצף הטוקנים המדויק של אותה בקשה. שני משתמשים השולחים prompts שונים אינם יכולים לשתף אותו, אלא אם סביבת הריצה מבצעת prefix caching, תכונה נפרדת שמתוארת בהמשך.

הגשת השירות (serving) מתבצעת בשני שלבים. שלב ה-prefill קורא את כל ה-prompt שלכם וממלא את ה-cache, והוא מוגבל על ידי כוח עיבוד (compute). שלב ה-decode מייצר טוקן אחד בכל פעם ומוסיף אותו ל-cache, והוא מוגבל על ידי רוחב פס של זיכרון (memory bandwidth). הפיצול הזה הוא הסיבה לכך שעיבוד ה-prompt ויצירת הטוקנים מציגים מהירויות שונות כאשר אתם מודדים טוקנים לשנייה על השרת שלכם.

כמה זיכרון צורך ה-KV cache?

אל תחפשו טבלאות ספקים. גודל הזיכרון הוא חישוב אריתמטי שניתן לבצע עבור כל מודל:

bytes per token = 2 * layers * kv_heads * head_dim * bytes per element

הספרה 2 מייצגת את ה-key ואת ה-value. כל שאר המספרים נגזרים מה-config.json של המודל, כפי שפורסם בדף ה-Hugging Face שלו.

קחו לדוגמה את Llama 3.1 8B. ה-config שלו מציין num_hidden_layers 32 ו-num_key_value_heads 8. ה-hidden_size של 4096, מחולק בין 32 ראשי attention, נותן גודל ראש (head dimension) של 128. בפורמט f16, כל אלמנט תופס 2 בתים:

2 * 32 * 8 * 128 * 2 = 131072 bytes = 128 KiB per token

הכפילו זאת באורך ה-context המבוקש, ולאחר מכן במספר הבקשות המורצות במקביל.

ChartLlama 3.1 8B KV cache at f16, in GiB
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
  }
]

ב-context של 8k, ה-cache תופס 1 GiB. ב-32k הוא תופס 4 GiB, טווח דומה למשקולות המודל ב-4-bit. ב-context המלא של המודל, 128k, הוא מגיע ל-16 GiB עבור בקשה אחת, ול-64 GiB אם ארבע בקשות ממלאות אותו במלואו. המשקולות לא השתנו, רק ה-cache גדל.

טכניקת ה-Grouped query attention (GQA) משפיעה משמעותית על מספר זה. ב-Llama 3.1 8B ישנם 8 ראשי key/value המשרתים 32 ראשי query, כך שארבעה ראשי query חולקים זוג key/value מאוחסן אחד. מודל שבו ה-num_key_value_heads שווה ל-num_attention_heads שלו יצרוך פי ארבעה זיכרון cache עבור אותו מספר פרמטרים. בדקו שדה זה לפני שאתם מניחים שעלות ההגשה של שני מודלי 8B היא זהה.

מדוע מודל שרץ ב-2k מסרב להיטען ב-32k

סביבת הריצה משריינת את ה-KV cache בעת טעינת המודל, לפי גודל ה-context length שהגדרת, ולא לפי ה-prompt שאתה שולח בפועל. חלון ה-context המוגדר כברירת מחדל ב-Ollama הוא 4096 טוקנים. אם תעלה אותו ל-32k, תדרוש הקצאה נוספת של 4 GiB עוד לפני שהגיע טוקן אחד.

OLLAMA_CONTEXT_LENGTH=32768 ollama serve

הגדרה זהה לכל סשן, מתוך ה-prompt האינטראקטיבי:

ollama run llama3.1:8b
/set parameter num_ctx 32768

הכשל נראה אחרת בכל stack. המערכת vLLM מבצעת בדיקה חשבונאית בעת העלייה ומסרבת לרוץ:

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.

בשרת VPS מבוסס CPU בלבד אין בדיקה כזו, כיוון שההקצאה מתבצעת ב-RAM הרגיל של המערכת. מנגנון ה-out-of-memory killer של ה-kernel מסיים את התהליך במקום זאת, והוא מותיר עקבות ב-kernel ring buffer:

dmesg -T | grep -i "killed process"

שורה המציינת את תהליך ה-serving שלך מעידה על כך שהשרת התחייב ליותר זיכרון ממה שיש לו. הפתרון הוא context קטן יותר, לא קובץ swap גדול יותר: KV cache שמועבר לדיסק נקרא בכל טוקן שנוצר, ולכן מהירות היצירה תואט עד לרמה שאינה שימושית. בחירת מספר הגיוני מוסברת ב-מדריך שלנו בנושא num_ctx ו-context length ב-Ollama.

השפעת ה-concurrency על המספר

כל בקשה שנמצאת בעיבוד (in-flight) נושאת איתה את ה-KV cache הייחודי לה. זו השורה שרוב תוכניות הקיבולת מחמיצות. ארבעה משתמשים, שכל אחד מהם מחזיק context של 32k, זקוקים ל-16 GiB במצטבר, מעבר למשקולות המודל.

סביבות הרצה (runtimes) נבדלות במידת הקשיחות של ניהול זה. Ollama ו-llama.cpp משריינים את ה-context המבוקש בעת טעינת המודל, כך שהזיכרון מוקצה בין אם נעשה בו שימוש ובין אם לא. לעומת זאת, vLLM מחלק את המאגר לבלוקים בגודל קבוע ומקצה אותם ככל שהבקשה גדלה, כך שבקשה של 500 טוקנים תופסת נפח של 500 טוקנים בלבד. כך או כך, המאגר סופי, וברגע שהוא מתמלא, בקשות חדשות ימתינו בתור במקום לעובד. ההשפעה של המתנה זו על זמני התגובה מפורטת ב-כמה משתמשים בו-זמנית יכול שרת LLM עצמאי לשרת.

ארבע דרכים להקטנת ה-KV cache

  1. הפחתת אורך ההקשר (context length). זהו המנוף המשמעותי ביותר ובדרך כלל הזול ביותר. רוב עומסי העבודה של צ'אט אינם מתקרבים ל-32k.
  2. קוונטיזציה (Quantization) של ה-cache עצמו. ערכי ברירת המחדל של OLLAMA_KV_CACHE_TYPE ב-Ollama הם f16, והוא תומך ב-q8_0, שמשתמש בכמחצית מהזיכרון, וב-q4_0, שמשתמש ברבע ממנו. המקבילות ב-llama.cpp הן -ctk q8_0 ו--ctv q8_0.
  3. בחירת מודל עם פחות ראשי key/value או פחות שכבות. קראו את config.json לפני שתורידו 40 GB של משקולות (weights).
  4. הגשת פחות בקשות בו-זמנית והעברת השאר לתור.

ב-q4_0, הנתון עבור Llama 3.1 8B יורד מ-128 KiB לטוקן לכ-32 KiB, כך ש-32k של הקשר עולים כ-1 GiB במקום 4 GiB. חיסכון זה אינו מגיע בחינם. המפתחות והערכים נשמרים ברמת דיוק נמוכה יותר, לכן השוו את הפלט עם ה-prompts שלכם לפני שתחליטו להשתמש בהגדרה זו.

מה באמת משיגים באמצעות Prompt Caching של ספק השירות

Prompt Caching של ספק השירות הוא מוצר שונה עם יחידת חיוב שונה. אתם מסמנים תחילית (prefix) יציבה, הספק מאחסן אותה, וקריאות עתידיות שחוזרות בדיוק על אותה תחילית מחויבות בתעריף מופחת במקום במחיר הקלט המלא.

מכפילי המחיר שפרסמה Anthropic, נכון לאוגוסט 2026: כתיבה למטמון (cache write) ל-5 דקות עולה פי 1.25 ממחיר טוקן קלט בסיסי. כתיבה ל-שעה עולה פי 2, וקריאה מהמטמון (cache read) עולה פי 0.1. הציבו system prompt של 20,000 טוקנים בתוך המספרים האלו, והמשמעות הכלכלית הופכת לברורה.

ChartCost of a 20,000 token prefix, in base input token equivalents
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"
  }
]

קראו זאת כתרגיל חשבוני. הפרמיה על כתיבה ל-5 דקות היא שוות ערך ל-5,000 טוקנים בקריאה הראשונה: 25,000 לעומת 20,000 עבור שליחה ללא מטמון. כל קריאה מאוחרת בתוך חלון הזמן מחויבת ב-2,000 במקום ב-20,000, חיסכון של 18,000. לכן, המטמון ל-5 דקות הופך למשתלם החל מהקריאה השנייה ואילך.

המטמון ל-שעה הוא הימור מסוג אחר. הוא מחייב 40,000 בעת הכתיבה, פרמיה של 20,000 טוקנים, ולכן הוא דורש שתי פגיעות (hits) בתוך השעה כדי להפוך למשתלם. זו שאלה שנוגעת לדפוס התעבורה שלכם, לא למודל. החישוב המלא, כולל האופן שבו בוחרים את חלון הזמן, נמצא ב-חישוב נקודת האיזון עבור Claude prompt caching.

שני פרטים קובעים האם תפגעו במטמון בכלל. ראשית, תחילית הקצרה מהאורך המינימלי של המודל לא תישמר במטמון ללא התראה: נכון לאוגוסט 2026, המינימום המתועד הוא 512 טוקנים עבור Claude Opus 5 ו-1,024 טוקנים עבור Claude Sonnet 5, ובקשה קצרה יותר מעובדת כרגיל ללא החזרת שגיאה. שנית, זמן החיים נמדד מתחילת הבקשה שכותבת או קוראת את הרשומה, וכל קריאה מרעננת אותו ללא עלות נוספת. לכן, נקודת קצה עמוסה שומרת על מטמון של 5 דקות פעיל ללא הגבלת זמן. נקודת קצה שנקראת פעם בעשר דקות משלמת את פרמיית הכתיבה בכל פעם מחדש ולעולם לא מפיקה תועלת.

בדקו את התגובה במקום להניח הנחות. האובייקט usage מדווח על cache_creation_input_tokens ו-cache_read_input_tokens. ספירת קריאות של אפס בכל פנייה משמעותה שאתם קונים כתיבות ולא מקבלים דבר בתמורה.

הנקודה שבה שני סוגי ה־cache נפגשים

הנחיית מערכת (system prompt) ארוכה היא המקום שבו הם נפגשים, והיא מחייבת אותך בשני הצדדים בו-זמנית.

באופן מקומי, הנחיית מערכת של 20,000 טוקנים תופסת כ-2.4 GiB של KV cache בשרת Llama 3.1 8B בפורמט f16, והיא עושה זאת בנפרד עבור כל בקשה מקבילה שכוללת אותה. מרחוק, אותו קידומת (prefix) עולה בכתיבת cache אחת ולאחר מכן ב-0.1 מהקלט בכל קריאה מאוחרת. העלות המקומית גדלה בהתאם למספר המשתמשים שלך. העלות המרוחקת גדלה בהתאם לתעבורה שלך ומתאפסת בזמני חוסר פעילות.

קיימת תכונה מקומית שנראית כמו prompt caching של ספקי שירות ומתבלבלים ביניהם ללא הרף: prefix caching. התיעוד של vLLM מתאר prefix caching אוטומטי כ-"שמירה ב-cache של ה-KV cache של שאילתות קיימות, כך ששאילתה חדשה יכולה לעשות שימוש חוזר ישיר ב-KV cache אם היא חולקת את אותה קידומת עם אחת השאילתות הקיימות". שרת llama.cpp שומר cache של הנחיות לכל slot כברירת מחדל, והדגל --cache-reuse N מגדיר את גודל הנתח הקטן ביותר שהוא ינסה לעשות בו שימוש חוזר.

מה ש-prefix caching חוסך הוא חישוב ה-prefill. הנחיית המערכת שלך בת ה-20,000 טוקנים מעובדת פעם אחת במקום בכל בקשה, מה שמקצר משמעותית את הזמן עד לטוקן הראשון. ב-vLLM, הבלוקים המשותפים עוברים שימוש חוזר במקום שכפול, כך שגם ניצול הזיכרון משתפר. מה שזה לעולם לא עושה הוא לצמצם את ה-cache שעליך להחזיק עבור הטוקנים הפעילים כרגע. שמירת המשקולות (weights) בזיכרון בין בקשות היא מנגנון קשור אך נפרד, המכוסה ב-שמירת מודל Ollama טעון בין בקשות.

מה למדוד בשרת הפרטי שלך

טען את המודל בהקשר (context) היעד שלך, ולאחר מכן קרא את המספרים בפועל במקום להסתמך על הערכות.

ollama ps
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
free -g

ollama ps מציג את המודל הטעון יחד עם גודלו והאם הוא רץ על ה-GPU או על ה-CPU. אם מודל שאמור היה להיכנס במלואו ל-GPU מדווח על פיצול ל-CPU, המשמעות היא שה-KV cache דחק חלק ממנו החוצה, ומהירות היצירה (generation speed) תרד בהתאם. nvidia-smi מספק את נתון ה-VRAM האמיתי, ו-free -g מבצע את אותה פעולה בשרת VPS מבוסס CPU בלבד. העלה את ה-context בשלבים, טען מחדש, ועקוב אחר השינוי במספרים. החישובים שלך והנתון המדווח צריכים להיות קרובים זה לזה. כאשר הם אינם תואמים, הפער נובע בדרך כלל ממאגרי החישוב (compute buffers) של סביבת הריצה עצמה ולא משגיאה בנוסחה.

אם המספרים הללו מכוונים אותך לחומרה שאינך מעוניין לשכור, ההשוואה מול תשלום לפי token מפורטת ב-GPU VPS מול API tokens.

FAQ

האם KV cache הוא אותו הדבר כמו prompt caching?

לא. ה-KV cache הוא זיכרון לכל בקשה בתוך תהליך ההגשה (serving process), המאחסן את וקטורי ה-key וה-value עבור כל טוקן בהקשר הנוכחי. הוא נמצא ב-RAM או ב-VRAM ומשתחרר בסיום הבקשה. ה-prompt caching של ספק השירות הוא תכונה לחיוב כספי המאחסנת תחילית (prefix) קבועה של ה-prompt בתשתית של הספק, ומחייבת בתעריף מופחת בעת שליחה חוזרת. חוסר ב-KV cache מונע מהמודל להיטען. חוסר ב-prompt cache רק מעלה את החשבונית ואת הזמן עד לטוקן הראשון.

מדוע המודל שלי נטען בהקשר של 2k אך נכשל ב-32k?

מכיוון שזמן הריצה מקצה את כל ה-KV cache בעת הטעינה, בגודל התואם לאורך ההקשר שהגדרת ולא לפי ה-prompt שאתה שולח. עבור Llama 3.1 8B בפורמט f16, ה-cache תופס 128 KiB לכל טוקן, כך ש-2k של הקשר עולים 0.25 GiB ו-32k עולים 4 GiB. המשקולות נכנסות בשני המקרים. ההקצאה היא זו שנכשלת. vLLM מדווח על כך כ-ValueError המציין את מספר הטוקנים המקסימלי שניתן לאחסן, ומציע להעלות את gpu_memory_utilization או להנמיך את max_model_len. בשרת מבוסס CPU בלבד, ה-kernel out-of-memory killer יסיים את התהליך, דבר שניתן לאמת באמצעות dmesg -T | grep -i "killed process".

כיצד עלי לחשב את גודל ה-KV cache עבור המודל שלי?

הכפל 2 במספר השכבות, במספר ה-key/value heads, במימד ה-head, ובמספר הבייטים לכל אלמנט. זה נותן את מספר הבייטים לכל טוקן. לאחר מכן הכפל באורך ההקשר שלך ובמספר הבקשות המקבילות. קרא את מספר השכבות וה-heads מתוך ה-config.json של המודל. השתמש ב-2 בייטים לכל אלמנט עבור f16 או bf16. ב-q8_0 ה-cache הוא בערך חצי מכך, וב-q4_0 בערך רבע.

האם prompt caching מפחית את הזיכרון שהשרת שלי צריך?

ה-prompt caching של ספק השירות אינו משפיע על החומרה שלך, כיוון שהאחסון נמצא בצד של הספק. המקבילה המקומית היא prefix caching, המוצעת על ידי vLLM ועל ידי שרת llama.cpp. היא עושה שימוש חוזר בוקטורי key ו-value שכבר חושבו עבור תחילית משותפת, מה שחוסך חישובי prefill ומקצר את הזמן עד לטוקן הראשון. ב-vLLM הבלוקים המשותפים עוברים שימוש חוזר במקום לשוכפל, כך שגם הזיכרון משתפר. אף אחת מהתכונות הללו לא מקטינה את ה-cache הנדרש עבור הטוקנים שנמצאים כרגע בתהליך, לכן חישובי ההקשר והמקביליות שלך עדיין קובעים את רף המינימום.

האם כדאי לבצע caching ל-prompt שאני שולח רק פעם אחת?

לא. כתיבה ל-cache עולה יותר מאשר קלט רגיל, פי 1.25 מהתעריף הבסיסי עבור אפשרות ה-5 דקות נכון לאוגוסט 2026, כך שתחילית שלעולם לא תשלח שוב בתוך חלון הזמן היא הפסד נקי. ה-caching משתלם כאשר אותה תחילית חוזרת על עצמה, כגון system prompt ארוך או מסמך שתשאל עליו מספר שאלות. בדוק את cache_read_input_tokens בתגובת ה-API כדי לוודא שאתה מקבל hits במקום לשלם על כתיבות.