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

שינוי num_ctx ב-Ollama: הגדלת חלון ההקשר למודלים

נתקלים בקיטוע של prompts ארוכים ב-Ollama? למדו כיצד להגדיר num_ctx ברמת הבקשה או השרת. מדריך זה מסביר איך לחשב את צריכת ה-VRAM הנדרשת ולמנוע שגיאות זיכרון נפוצות.

מה עושה num_ctx, ומדוע ה-prompt הארוך שלכם נקטע

אורך ההקשר (context length) ב-Ollama הוא מספר ה-tokens שמודל טעון יכול להחזיק בזיכרון בו-זמנית, והאפשרות num_ctx היא זו שקובעת אותו. Ollama בוחרת ערך ברירת מחדל הנמוך משמעותית מהמקסימום שהמודל מצהיר עליו, ולכן prompt ארוך נקטע עוד לפני שהמודל מספיק לקרוא אותו. שום דבר בתגובה לא יתריע בפניכם שזה קרה.

המודל Llama 3.1 8B רשום בספריית המודלים של Ollama עם חלון הקשר של 128k. שרת בתצורה סטנדרטית לא יספק לכם ערך זה. התיעוד של Ollama עצמה מציג ברירות מחדל שונות בדפים שונים: ה-FAQ מציין 4096 tokens, ההפניה ל-Modelfile מציינת ש-num_ctx כברירת מחדל הוא 2048, ודף אורך ההקשר מציין שברירת המחדל נבחרת לפי ה-VRAM (זיכרון וידאו) הזמין: 4k מתחת ל-24 GiB, 32k בין 24 ל-48 GiB, ו-256k מעל ערך זה. כל אחד מהנתונים הללו היה נכון לגרסה מסוימת. חוסר ההסכמה הזה הוא הלקח החשוב כאן: קראו את הערך מהשרת הפעיל שלכם במקום להסתמך על דף כלשהו, כולל דף זה.

קיטוע מתרחש בשקט מכיוון שהמודל עדיין עונה, והתשובה עדיין נראית תקינה. היא נכתבה על בסיס סוף הקלט שלכם. סיכום שמחמיץ את החצי הראשון של מסמך נראה כמו מודל חלש. בדרך כלל, מדובר פשוט בחלון הקשר קטן מדי.

בדיקת אורך ההקשר (context length) שהשרת החיל בפועל ב-Ollama

הבדיקה שעובדת בכל גרסה היא prompt_eval_count, המונה את מספר ה-tokens של ה-prompt שהשרת מדווח כי עיבד. שלחו כמות גדולה ממה שההקשר יכול להכיל, והמספר הזה ייעצר במגבלה.

sudo apt update && sudo apt install -y jq
LONG=$(python3 -c "print('the quick brown fox jumps over the lazy dog. ' * 2000)")
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:4096}}' |
  curl -s http://localhost:11434/api/generate -d @- |
  jq '{prompt_eval_count, prompt_eval_duration}'

ה-prompt הזה מכיל כ-18,000 מילים, הרבה מעבר ל-4096 tokens. הערך prompt_eval_count יחזור קרוב ל-4096 במקום קרוב למספר ה-tokens האמיתי, כיוון שהשרת השמיט את השאר. הריצו זאת שוב עם "num_ctx":16384 והמונה יעלה. אם הגרסה שלכם מחזירה שגיאה במקום לקטום את הטקסט, זו אותה תוצאה עם התרעה ברורה יותר.

ollama ps

העמודה CONTEXT, בגרסאות שמציגות אותה, מכילה את אורך ההקשר שבו המודל הטעון רץ כרגע. העמודה PROCESSOR לצדה מציגה היכן המודל ממוקם. הערך 100% CPU הוא תקין ב-VPS ללא GPU. פיצול כמו 30%/70% CPU/GPU בשרת עם GPU מעיד על כך שהמשקולות (weights) יחד עם ה-cache אינם נכנסים יותר ב-VRAM, וערך num_ctx גבוה הוא הסיבה הנפוצה לכך.

journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5

מריץ ההסקה (inference runner) מדפיס את גודל ההקשר שלו בשורה המכילה את n_ctx. הניסוח המדויק משתנה בין גרסאות, לכן אם השורה חסרה, התייחסו לכך כשינוי שם ולא כהוכחה למשהו אחר.

ארבעה מקומות להגדרת num_ctx

בבקשה. שלחו את "options": {"num_ctx": 16384} ל-/api/generate או ל-/api/chat. הגדרה זו גוברת על כל הגדרה אחרת וחלה על הקריאה הספציפית הזו. אם הערך שונה מזה שבו המודל הטעון רץ, השרת יטען מחדש את המודל תחילה; ניתן להבחין בכך ב-load_duration בתגובה: הערך יקפוץ מקרוב לאפס למספר שניות שלמות.

בסשן אינטראקטיבי. בתוך ollama run, הקלידו /set parameter num_ctx 16384. הגדרה זו תקפה למשך אותו סשן בלבד.

בתוך Modelfile. פעולה זו מטמיעה את הערך במודל בעל שם, כך שכל לקוח מקבל אותו ללא צורך בשינוי בצד הלקוח.

FROM llama3.1:8b
PARAMETER num_ctx 16384
ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16k

בשרת. OLLAMA_CONTEXT_LENGTH קובע את ברירת המחדל עבור כל בקשה שאינה נושאת num_ctx משלה. תחת systemd, הוסיפו קובץ drop-in במקום לערוך את קובץ ה-unit.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"
sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama ps

סדר הקדימויות חשוב במיוחד כאשר אתם מנפים שגיאות בלקוח של מישהו אחר. בקשה הנושאת num_ctx גוברת על ברירת המחדל של השרת, לכן ממשק צ'אט או סוכן (agent) ששולח ערך קטן משלו יבטל בשקט את השינוי שביצעתם ב-systemd. כאשר אתם מפנים סוכן תכנות לשרת ה-Ollama שלכם, בדקו מה הלקוח שולח לפני שאתם מאשימים את השרת.

מדוע לא ניתן פשוט להגדיר את num_ctx למקסימום של המודל

מנגנון ה-Attention גורם לכל טוקן "להסתכל" על כל הטוקנים שקדמו לו. המפתחות (keys) והערכים (values) שמחושבים עבור טוקנים מוקדמים נשמרים כדי שלא יהיה צורך לחשב אותם מחדש עבור כל טוקן חדש; מאגר זה נקרא KV cache (מטמון מפתחות/ערכים). הוא מוקצה עבור מלוא ה-num_ctx בעת טעינת המודל, ולא גדל בהדרגה ככל שהשיחה מתארכת. לכן, הקשר (context) גדול צורך את הזיכרון שלו גם עבור הנחיה (prompt) של שורה אחת בלבד.

המדריך של DigitalOcean לעלויות הסקה מציג את החישוב בשורה אחת:

kv_bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_value

הספרה 2 סופרת את המפתחות והערכים בנפרד. את שאר המספרים יש לקחת מנתוני המודל הספציפי שלכם.

curl -s http://localhost:11434/api/show -d '{"model":"llama3.1:8b"}' |
  jq '.model_info | {ctx: ."llama.context_length", layers: ."llama.block_count", heads: ."llama.attention.head_count", kv_heads: ."llama.attention.head_count_kv", embed: ."llama.embedding_length"}'

המודל Llama 3.1 8B מדווח על 32 שכבות ו-8 ראשי מפתח/ערך. ממד הראש הוא embed חלקי heads, כלומר 4096 / 32 = 128 במקרה זה, וחלק מהמודלים מפרסמים זאת ישירות כ-llama.attention.key_length. המטמון המוגדר כברירת מחדל מחזיק ערכי f16, לכן bytes_per_value הוא 2, והחישוב 2 32 8 128 2 מניב 131,072 בתים. מדובר ב-128 KiB של מטמון עבור כל טוקן בודד של הקשר. הכפילו זאת באורך ההקשר, והעלות מפסיקה להיות מופשטת.

ChartLlama 3.1 8B at f16: KV cache and total RAM by context length, in GiB
The data behind this chart
[
  {
    "label": "4k",
    "kv_cache_gib": 0.5,
    "total_ram_gib": 5.1
  },
  {
    "label": "8k",
    "kv_cache_gib": 1,
    "total_ram_gib": 5.6
  },
  {
    "label": "16k",
    "kv_cache_gib": 2,
    "total_ram_gib": 6.6
  },
  {
    "label": "32k",
    "kv_cache_gib": 4,
    "total_ram_gib": 8.6
  },
  {
    "label": "64k",
    "kv_cache_gib": 8,
    "total_ram_gib": 12.6
  },
  {
    "label": "128k",
    "kv_cache_gib": 16,
    "total_ram_gib": 20.6
  }
]

השורות 6 הן תוצאה של הנוסחה לעיל, ולא מדידות בפועל. עמודת הסך הכל מוסיפה את ה-4.9 GB של הורדת המודל שספריית Ollama הציגה עבור llama3.1:8b באוגוסט 2026, שהם 4.6 GiB, והיא אינה כוללת את מאגרי החישוב (compute buffers) ואת תהליך השרת עצמו. התייחסו לנתון זה כאל רף מינימלי.

הצורה היא העיקר. ב-8k, המטמון עולה 1 GiB, שזה זניח לעומת משקלי המודל. במקסימום של המודל, 128k, העלות היא 16 GiB – יותר מפי שלושה ממשקלי המודל – עבור סך הכל הקרוב ל-20.6 GiB. לכן, שרת VPS עם 4 GB לא יכול לטעון את המודל הזה עם הקשר שימושי כלשהו. שרת VPS עם 8 GB יריץ בנוחות 8k. שרת VPS עם 16 GB יגיע ל-32k עם מקום פנוי לשאר צורכי השרת. כל אחד מהספים הללו עולה ככל שמשקלי המודל גדלים; לכן, אם אתם שוקלים מודל גדול יותר מ-8B זה, אותם חישובים שבוצעו עבור התגית של Qwen 27B על שרת VPS מבוסס CPU בלבד מראים כמה מעט מקום נשאר למשקלים עבור הקשר בטווח שבין 8 ל-64 GB.

מה קורה כאשר ה-KV cache אינו נכנס בזיכרון

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

free -m
ps -eo rss,comm --sort=-rss | head -n 5

הערך RSS (resident set size) מוצג בקילובייטים. אם השימוש ב-swap ב-free -m מתחיל לעלות, צמצמו את ה-context. כאשר ה-KV cache נמצא ב-swap, יצירת הטוקנים תיתקע למשך שניות לכל טוקן, כיוון שכל טוקן חדש מחייב קריאה של כל ה-cache.

אם השרת אוזל מזיכרון לחלוטין, ה-kernel בוחר את התהליך הגדול ביותר ומסיים אותו (kill).

sudo dmesg | grep -i "killed process"

שורה המציינת Out of memory: Killed process 1234 (ollama) משמעותה שה-context שביקשתם לא נכנס בזיכרון. Ollama לרוב מסרב לבקשה עוד לפני כן, והבקשה נכשלת עם הודעה המציינת את כמות הזיכרון הנדרשת לעומת הזיכרון הפנוי.

בשרת עם GPU הכשל שקט יותר. שכבות המודל גולשות ל-RAM של המערכת, ollama ps מציג את החלוקה בין ה-CPU ל-GPU, וקצב העבודה (throughput) צונח בחדות. עוצמת הירידה תלויה בחומרה שלכם, לכן מדדו טוקנים לשנייה על השרת שלכם עבור כל הגדרת context, במקום להסתמך על נתונים ממכונה של מישהו אחר.

זמן ה-Prefill גדל מהר יותר מאורך ה-prompt

ה-Prefill הוא העבודה שמתבצעת על הקלט שלכם לפני שמופיע ה-token הראשון בפלט. כל token ב-prompt מבצע פעולת attention מול כל ה-tokens שקדמו לו, לכן סך העבודה גדל לפי ריבוע אורך הקלט. הכפלת ה-prompt תגרום לזמן ההמתנה ל-token הראשון לגדול ביותר מפי שניים.

התגובה כוללת את נתוני המדידה, כך שאין צורך להסתמך על הערכות.

jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:16384}}' |
  curl -s http://localhost:11434/api/generate -d @- |
  jq '{tokens: .prompt_eval_count, prefill_seconds: (.prompt_eval_duration/1000000000)}'

הריצו זאת עם prompt קצר ושוב עם prompt ארוך, ולאחר מכן חלקו את מספר ה-tokens בשניות בכל מקרה. בשרת VPS מבוסס CPU בלבד, ה-Prefill הוא בדרך כלל החלק האיטי ביותר בבקשה עם context ארוך, ונתון של tokens לשנייה שנלקח מ-prompt קצר לא ינבא זאת.

הבעיה מורגשת ביותר במצבי Concurrency. כל בקשה שמטופלת זקוקה ל-cache משלה, לכן הזיכרון בתרשים לעיל הוא לכל בקשה ולא לכל שרת; בקשה אחת ארוכה עלולה לתפוס את המשאבים בזמן שבקשות קצרות ממתינות בתור מאחוריה. הגדירו את OLLAMA_NUM_PARALLEL באופן מחושב, וקראו על כמה משתמשים בו-זמנית יכול מודל LLM באירוח עצמי לשרת לפני שתעלו את שני הערכים יחד.

החזרת הקשר (context) באמצעות מטמון קטן יותר

bytes_per_value בנוסחה הוא הגדרה שניתן לשלוט בה. ה-FAQ של Ollama מתעד את OLLAMA_KV_CACHE_TYPE, כאשר f16 הוא ברירת המחדל ב-2 בתים, בתוספת q8_0 ב-1 בתים ו-q4_0 מתחת לכך. מעבר ל-q8_0 מקטין את המטמון בחצי, כך ששורה של 32k עולה 2 GiB במקום 4 GiB. אותו FAQ מתעד את OLLAMA_FLASH_ATTENTION=1, שחלק מהגרסאות דורשות לפני שמטמון מקוונטט (quantised) נכנס לתוקף.

[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"

אמתו את הנתונים במקום להניח הנחות: הפעילו מחדש את השירות, טענו את המודל באותו num_ctx כמו קודם, והשוו את ה-RSS. התמיכה תלויה במודל וב-backend, לכן הגדרה שאינה משנה דבר מעידה על כך שהשילוב שלכם אינו נתמך. התיעוד מפרט אפשרויות אלו ללא הבטחה לתוצאה איכותית, לכן בדקו את q4_0 מול ה-prompts שלכם לפני שתסתמכו עליו. אם כפתורי כוונון אלו הם הסיבה לכך שאתם כאן, Ollama ו-llama.cpp חושפים אותם בצורה שונה.

מתכון לבחירת num_ctx

  1. קראו את הקונטקסט המרבי של המודל, את מספר השכבות שלו ואת מספר ה-key/value heads מתוך /api/show.
  2. חשבו את מספר הבתים לכל טוקן לפי הנוסחה, והכפילו בקונטקסט הרצוי לכם.
  3. הוסיפו את גודל המשקולות, השוו מול ה-RAM הפנוי, והשאירו לפחות 1 GiB פנוי עבור שאר המערכת.
  4. הגדירו את הערך, טענו את המודל, ואז ודאו מה הוחל בפועל באמצעות ollama ps ו-prompt_eval_count.
  5. הריצו את עומס העבודה האמיתי שלכם תוך ניטור free -m, וצמצמו את הקונטקסט בחצי אם מתחילה פעילות של swap.

רוב המשימות דורשות פחות קונטקסט ממה שמקצים להן בדרך כלל. סיכום של דוח ארוך נכנס ב-16k. ממשק שליפה (retrieval) שמדביק חמישה מקטעי מסמכים לעיתים רחוקות עובר את ה-8k. סוכן תכנות שקורא קבצים שלמים הוא המקרה שבאמת זקוק ל-64k ומעלה, וזהו גם המקרה שבו עליכם להתאים את גודל השרת לקונטקסט ולא להפך. אם השרת עצמו עדיין חדש, התחילו מ-התקנה תקינה של Ollama על גבי VPS וכוונו את הקונטקסט לאחר שהמודלים נטענים בצורה חלקה.

FAQ

מהו אורך ההקשר (context length) המוגדר כברירת מחדל ב-Ollama?

הדבר תלוי בגרסת הבנייה ובחומרה, לכן יש לבדוק זאת במקום להניח הנחות. ה-FAQ של Ollama מציין 4096 אסימונים (tokens), תיעוד ה-Modelfile מציין ערך ברירת מחדל של num_ctx השווה ל-2048, ודף אורך ההקשר מציין ברירת מחדל הנבחרת לפי ה-VRAM הזמין: 4k מתחת ל-24 GiB, 32k בין 24 ל-48 GiB, ו-256k מעל לערכים אלו. שרת VPS מבוסס CPU בלבד יקבל את הערך הנמוך. הפקודה ollama ps מדפיסה את אורך ההקשר המיושם בגרסאות הכוללות עמודה זו, ו-prompt_eval_count בתגובת API מאמת זאת בכל גרסה.

מדוע Ollama מתעלם מתחילת ה-prompt הארוך שלי?

מכיוון שה-prompt היה ארוך מחלון ההקשר, השרת קיצץ אותו לפני שהמודל הספיק לעבד אותו, ולא הוחזרה שגיאה. שלחו שוב את אותו ה-prompt עם ערך num_ctx גדול יותר ועקבו אחר העלייה ב-prompt_eval_count בתגובה. אם מספר זה אינו משתנה, ייתכן שרכיב כלשהו ביניכם לבין השרת מגדיר את num_ctx בעצמו, דבר נפוץ בממשקי צ'אט ובספריות סוכנים (agent frameworks).

כמה זיכרון RAM נוסף נדרש עבור num_ctx גדול יותר?

יש להכפיל את אורך ההקשר בעלות המטמון (cache) לכל אסימון, שהיא 2 * layers * kv_heads * head_dim * bytes_per_value. עבור Llama 3.1 8B בפורמט f16, מדובר ב-128 KiB לכל אסימון; לכן 32k אסימונים עולים 4 GiB, ו-128k אסימונים מלאים עולים 16 GiB מעבר למשקולות המודל. המטמון מוקצה בעת טעינת המודל, כך שערך num_ctx גבוה צורך זיכרון זה גם כאשר ה-prompts שלכם נשארים קצרים.

האם חלון הקשר גדול יותר מאט את Ollama?

כן, בשתי דרכים. עבודת ה-prefill גדלה ביחס ריבועי לאורך ה-prompt, לכן קלט ארוך מעכב את האסימון הראשון מעבר למה שמרמז אורכו. המטמון הגדול גם מתחרה על הזיכרון: בשרת עם GPU הוא דוחף שכבות לתוך ה-RAM של המערכת, ובשרת CPU הוא דוחף את המכונה לכיוון ה-swap. ערך num_ctx גדול שלעולם אינכם ממלאים עדיין צורך את הזיכרון, אם כי הוא אינו מוסיף לזמן ה-prefill.

האם ניתן להגדיר num_ctx באופן קבוע עבור מודל מסוים?

כן. צרו Modelfile המכיל את FROM llama3.1:8b ואת PARAMETER num_ctx 16384, ולאחר מכן הריצו את ollama create llama3.1-16k -f ./Modelfile. כל לקוח שיבקש את llama3.1-16k יקבל את ההקשר הזה מבלי לשלוח אפשרויות נוספות. בקשה הכוללת num_ctx משלה עדיין תגבר על הגדרה זו, כך שמדובר בברירת מחדל ולא בתקרה קשיחה.