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

מדוע ה-LLM שלכם מואט כשמצטרפים משתמשים נוספים?

השרת שלכם לא תקול אלא פשוט מעבד בקשה אחת בכל פעם. גלו כיצד הגדרות כמו OLLAMA_NUM_PARALLEL, ניהול KV cache, תהליכי prefill ו-batching קובעים את גבול היכולת של השרת שלכם.

מדוע מודל שפה (LLM) באירוח עצמי מואט כאשר מגיעים משתמשים נוספים?

מודל שפה באירוח עצמי נתקע ב־5 משתמשים בו-זמניים כיוון שהשרת עדיין מייצר תשובה אחת בכל פעם, וארבעת המשתמשים האחרים ממתינים בתור. התיעוד של Ollama מבהיר זאת ללא כחל וסרק לגבי ברירת המחדל: OLLAMA_NUM_PARALLEL הוא "מספר הבקשות המקביליות המקסימלי שכל מודל יעבד בו-זמנית, ברירת המחדל היא 1". שום דבר אינו תקול. ארבעה מתוך חמשת האנשים שלכם פשוט ממתינים לתורם.

התיקון הוא לעיתים רחוקות שדרוג השרת למכונה חזקה יותר. הפתרון הוא מנוע הגשה (serving engine) שדוחף בקשות רבות דרך המודל באותו forward pass, בתוספת זיכרון פנוי מספיק כדי להחזיק את השיחה של כולם בזמן שהתהליך מתבצע. שני החלקים חשובים, והחלק השני הוא זה שקובע בפועל את תקרת הביצועים שלכם.

שני השלבים שכל בקשה עוברת

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

אסימטריה זו היא הסיבה לכך ש-batching עובד. פעולת decode עבור משתמש אחד קוראת, למשל, 5 GB של משקולות עבור כל token, ומותירה את רוב יחידות החישוב במצב המתנה. הוספת בקשה שנייה גורמת למנוע לקרוא את אותם 5 GB פעם אחת, ואז לחשב שני tokens מתוכם. המשתמש השני כמעט אינו מוסיף זמן המתנה. הגשת בקשות בזו אחר זו מבטלת את היתרון הזה.

שני מספרים מתארים את חוויית המשתמש. TTFT (זמן עד ל-token הראשון) הוא זמן ההמתנה בתור בתוספת ה-prefill. ITL (זמן השהיה בין tokens) הוא המרווח בין ה-tokens המוזרמים, והוא נקבע על ידי ה-decode. שרת איטי סובל בדרך כלל מאיטיות באחד מהשלבים הללו, והפתרונות עבורם אינם זהים.

עיבוד אצווה סטטי גורם לכולם להמתין לתגובה האיטית ביותר

עיבוד אצווה סטטי (Static batching) הוא הגישה הפשטנית, והוא מתקבל כאשר מקבצים בקשות באופן ידני בקוד היישום. המנוע אוסף N בקשות, מריץ אותן יחד, ומחזיק כל משבצת (slot) פתוחה עד לסיום היצירה הארוכה ביותר בקבוצה.

משתמש שמבקש סיכום של 1,200 אסימונים (tokens) גורם לארבע תשובות קצרות להישאר נעולות באצווה, כיוון שהאצווה אינה משחררת אף משבצת עד שהחבר האיטי ביותר בה מסיים את עבודתו.

לכך מתלווים שני מחירים. רצפים שהסתיימו ממשיכים לתפוס משבצות שאינן מחשבות דבר מועיל, ולכן התפוקה האפקטיבית יורדת ככל שאורכי הפלט משתנים – ואורכי פלט בצ'אט משתנים במידה רבה. בקשה שמגיעה צעד אחד לאחר שהאצווה נוצרה ממתינה עד להתרוקנות האצווה כולה לפני שהיא מתחילה בשלב ה-prefill, מה שאומר שזמן ה-TTFT שלה נקבע על ידי חיבור של משתמש אחר.

Continuous batching מקבל ומוציא בקשות בכל token

Continuous batching מתזמן ברמה של צעד פענוח בודד. לאחר כל צעד, המתזמן מסיר רצפים שזה עתה פלטו את ה-stop token שלהם, ולאחר מכן מכניס בקשות ממתינות למקומות הפנויים. תשובה שמסתיימת בצעד 40 משחררת את המקום שלה בצעד 40, ולא בסוף ה-batch.

זה אינו מנגנון אקזוטי. llama-server מתעד את -cb, --cont-batching כ-"האם להפעיל continuous batching (ידוע גם כ-dynamic batching) (ברירת מחדל: מופעל)", ו-vLLM בנוי סביב רעיון זה. גם Ollama מגישה בקשות במקביל. ברירת המחדל פשוט מגבילה את המספר לאחד, וזו הסיבה שמשתמשים רבים מסיקים שהחומרה שלהם אינה מסוגלת לביצועים מקביליים, בעוד שהתצורה שלהם היא זו שהגדירה זאת כלא אפשרי.

תוצאות של continuous batching שפורסמו נמדדות בדרך כלל על כרטיסי datacenter שיש להם גם כוח מחשוב פנוי וגם עשרות גיגה-בייטים עבור ה-cache. צורת התוצאות הללו תקפה גם עבור השרת שלכם. גודלן אינו תקף, וסעיף הזיכרון להלן מסביר מדוע.

שלב ה-prefill מתחרה עם ה-decode על אותם משאבי חישוב

כאשר בקשה חדשה מגיעה בזמן שארבע תשובות נמצאות בתהליך הזרמה (streaming), ה-prompt שלה חייב לעבור prefill תחילה, ופעולת ה-prefill צורכת משאבי חישוב רבים. אם ה-scheduler מקצה ל-prefill זה צעד (step) משלו, ארבעת המשתמשים שמקבלים תשובות לא יקבלו אף token במהלך אותו זמן. ב-prompt ארוך, מדובר בהשהיה מורגשת בכל חלון פתוח. זהו ה-"גמגום" שאליו מתכוונים משתמשים כשהם אומרים שהשרת "מקרטע" בכל פעם שמישהו אחר לוחץ על שליחה.

טכניקת Chunked prefill מפרקת prompt ארוך לחלקים ומשלבת כל חלק באותו צעד שבו מתבצעים ה-decodes הפעילים. מדריך הכוונון של vLLM מציג את הפשרה בצורה ישירה: תקציבי chunk קטנים יותר "משיגים ITL טוב יותר כיוון שיש פחות פעולות prefill שמאטות את ה-decodes", בעוד ערכים גבוהים יותר "משיגים זמן טוב יותר לקבלת ה-token הראשון (TTFT), כיוון שניתן לעבד יותר tokens של prefill באותו batch". עליך לבחור את מי מהמשתמשים להעדיף: את האדם שממתין לתחילת התשובה, או את האנשים שצופים בטקסט זורם.

אורך ה-prompt קובע עד כמה הדבר יפגע בביצועים. prompt של 6,000 tokens עם תשובה של 200 tokens משמעותו 6,000 tokens של עבודת prefill מול 200 צעדי decode. צ'אט מבוסס שליפת מידע (RAG) ו-system prompts ארוכים דוחפים את המערכת למצב זה, כך שה-prefill מפסיק להיות זניח והופך לגורם שמעכב את המשתמשים. מנגנון Prefix caching מסייע כאשר החלק הארוך חוזר על עצמו: vLLM חושף את --enable-prefix-caching, המאפשר שימוש חוזר ב-cache עבור קידומת prompt משותפת במקום לחשב אותה מחדש עבור כל בקשה.

הזיכרון שנגמר ראשון הוא ה-KV cache

כל אסימון (token) בכל שיחה פעילה משאיר וקטור מפתח (key vector) ווקטור ערך (value vector) בכל שכבה של המודל. זהו ה-KV cache (מטמון מפתח/ערך), והוא המאפשר לתהליך ה-decode להימנע מחישוב מחדש של כל ה-prompt עבור כל אסימון חדש. גודלו לכל אסימון נקבע לפי מבנה המודל: 2 (מפתח אחד, ערך אחד) כפול מספר השכבות, כפול מספר ראשי המפתח/ערך, כפול ממד הראש, כפול מספר הבתים לערך. קראו את המספרים הללו מתוך ה-config.json של המודל.

בצעו את החישוב פעם אחת והתקרה תפסיק להיות תעלומה. מודל 8B טיפוסי עם 36 שכבות, 8 ראשי מפתח/ערך וממד ראש של 128, השומר את המטמון ב-16-bit, צורך 2 36 8 128 2 בתים לכל אסימון. מדובר ב-147,456 בתים, בערך 144 KiB. שיחה אחת של 8,192 אסימונים דורשת לכן בערך 1.2 GB של מטמון. חמש שיחות כאלו דורשות בערך 6 GB, מעבר למשקולות המודל, וזו התשובה האמיתית לשאלה כמה משתמשים נכנסים.

מקביליות מכפילה את ההקשר (context), והכלים מצהירים על כך בגלוי. ה-FAQ של Ollama מציין: "עיבוד בקשות מקבילי עבור מודל נתון גורר הגדלה של גודל ההקשר לפי מספר הבקשות המקביליות. לדוגמה, הקשר של 2K עם 4 בקשות מקביליות יביא להקשר של 8K ולהקצאת זיכרון נוספת". ה-RAM הנדרש גדל לפי OLLAMA_NUM_PARALLEL כפול OLLAMA_CONTEXT_LENGTH. ב-llama-server, ההקשר שאתם מבקשים עם -c מתחלק בין ה--np slots, כך שהעלאת מספר ה-slots כשלעצמה מצמצמת את מה שכל בקשה יכולה להכיל. קראו את ההקשר לכל slot מתוך לוג ההפעלה במקום להניח הנחות.

vLLM מבצע הקצאה מראש (preallocation) במקום זאת. --gpu-memory-utilization (ברירת המחדל היא 0.92) הוא "חלק זיכרון ה-GPU שישמש את ה-model executor". כל מה שנשאר לאחר טעינת המשקולות הופך למאגר ה-paged KV, וכאשר המאגר הזה מתרוקן, ה-scheduler מבצע eviction לבקשה במקום לגרום לקריסתה:

WARNING 05-09 00:49:33 scheduler.py:1057] Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space.

במנוע V1 של vLLM, מצב ברירת המחדל ל-preemption הוא RECOMPUTE, כך שבקשה שבוצעה לה eviction מאבדת את המטמון שלה ומבצעת prefill מחדש כשהיא מוחזרת. העבודה הזו מתבצעת פעמיים. התיעוד מזהיר ש-"preemption ו-recomputation עלולים להשפיע לרעה על ה-latency מקצה לקצה", ושורת לוג זו היא ההסבר הטוב ביותר לכך שמשתמש אחד חסר מזל המתין זמן רב הרבה יותר מכולם, בעוד הממוצע שלכם נראה תקין. הגדירו את disable_log_stats=False כדי לתעד את המונה המצטבר, או קראו את מונה ה-preemption מתוך מדדי ה-Prometheus ש-vLLM חושף.

מה משתנה ב-2, 5 ו-20 משתמשים בו-זמנית

שני משתמשים. כמעט בלתי מורגש ב-GPU עם מטמון פנוי, כיוון שזרם הפענוח השני "רוכב" על הראשון עם תוספת זמן זניחה. ב-VPS מבוסס CPU בלבד עם 4 עד 8 GB של RAM, זה לא בחינם: שני הזרמים חולקים את אותם vCPUs ואת אותו רוחב פס של ה-RAM, לכן כל משתמש מקבל בערך מחצית מה-tokens לשנייה, ודרישת המטמון מוכפלת מול תקציב מצומצם בהרבה.

חמישה משתמשים. כאן הגדרות ברירת המחדל מפסיקות להספיק, והבעיה מתחילה כתור המתנה. כאשר OLLAMA_NUM_PARALLEL מוגדר ל-1, ארבעה אנשים ממתינים למי שביקש תשובה ארוכה, וכל אחד מהם רואה מהירות רגילה ברגע שתורו מגיע. העלאת מספר המקביליות משנה את אופי הבעיה: חמישה חריצים עם 8K context כל אחד דורשים מטמון של 40K tokens. אם זה לא נכנס ב-VRAM, המנוע מעביר שכבות ל-RAM של המערכת, ואם זה לא נכנס ב-RAM, המכונה מבצעת swap וקצב ה-tokens לשנייה קורס.

עשרים משתמשים. עשרים בני אדם בממשק צ'אט הם בדרך כלל לא עשרים בקשות בו-זמניות, וזה הדבר החשוב ביותר להבנה לפני רכישת חומרה. אדם קורא תשובה וחושב במשך 20 עד 60 שניות בין תור לתור, כך שרוב הסשן שלו אינו פעיל. עשרים סוכנים, או עשרים משימות סיכום מסמכים, הם עשרים זרמים אמיתיים ללא זמן המתנה כלל. זו מכונה מסוג אחר.

האם המשתמשים שלכם פעילים בו-זמנית, או רק מחוברים?

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

  1. מדדו תחילה את מהירות הזרם הבודד שלכם, כולל prefill ופענוח. אל תסתמכו על נתונים מכרטיס של מישהו אחר: מדדו טוקנים לשנייה על השרת שלכם והשתמשו בתוצאה שקיבלתם.
  2. העריכו את מחזור העבודה (duty cycle). עשרים משתמשי צ'אט, 12 שניות יצירה לכל תור, ותור אחד כל 90 שניות, נותנים 20 * 12 / 90, כלומר כ-2.7 בקשות פעילות בו-זמנית.
  3. הגדירו את מספר ה-slots מעט מעל ערך זה, ולאחר מכן בדקו אותו מול הזיכרון: מספר ה-slots כפול ההקשר (context) לכל בקשה חייב להיכנס בתוך טוקני ה-cache העומדים לרשותכם.
  4. שמרו על תור קצר כדי שכשל עקב חריגה (overflow) יתרחש במהירות ובאופן גלוי.

טוקני ה-cache הזמינים הם הזיכרון הפנוי לאחר טעינת המשקולות (weights), מחולק בעלות לכל טוקן כפי שצוין בסעיף הקודם. כרטיס של 24 GB המריץ מודל 8B ב-16-bit משתמש בכ-16 GB עבור המשקולות, ונותרו לו בערך 6 GB של cache זמין בניצול ברירת המחדל, מה שמאפשר כחמש שיחות של 8K. כדי להכניס יותר, קצרו את ההקשר לכל בקשה, או אחסנו את ה-cache ב-8-bit (llama-server דורש --cache-type-k q8_0). שתי האפשרויות מאפשרות הגדלת כמות המשתמשים במקביל על חשבון ויתור על איכות או דיוק, וכדאי לקרוא על המשמעות של פשרה זו לפני השקעה בחומרה: מתי שרת GPU וירטואלי משתלם יותר מאשר שימוש ב-API.

היכן הגדרות ברירת המחדל של Ollama אינן מספיקות

הגדילו את מספר הבקשות המקבילות דרך ה-service unit, כיוון שפקודת export ב-shell לא תשפיע על daemon שמנוהל על ידי systemd.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_MAX_QUEUE=64"
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment
ollama ps

systemctl show אמור להציג את שלושת המשתנים שהגדרתם זה עתה. אם הם לא מופיעים, ה-drop-in לא נשמר, ושום פעולה אחרת לא תועיל. ollama ps יציג לאחר מכן את המודל הטעון עם גודל גדול יותר ממשקל הקבצים בלבד, כיוון שארבעה חריצים (slots) של 8,192 טוקנים משריינים 32,768 טוקנים של cache לצידם. עמודת PROCESSOR שמציגה חלק מהמודל על ה-CPU כאשר ציפיתם שכולו ירוץ על ה-GPU, משמעותה שביקשתם יותר cache ממה שנותר בכרטיס. הקטינו את אחד משני המספרים.

ערך ברירת המחדל של התור דורש בחינה נוספת. Ollama מנהל תור של עד OLLAMA_MAX_QUEUE בקשות, כאשר "ברירת המחדל היא 512". מעבר לכך, הוא משיב "בשגיאת 503 המציינת שהשרת עמוס". תור באורך 512 על שרת שמשרת ארבע בקשות במקביל הוא הבטחה שלא ניתן לקיים, כיוון שהלקוח שנמצא במיקום 300 יקבל timeout זמן רב לפני שיגיע תורו. תור קצר מחזיר שגיאה שהיישום שלכם יכול לנסות שוב או לדווח עליה, וזה עדיף על חיווי טעינה שלעולם לא מסתיים.

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

מתי מנוע הגשה אמיתי מתחיל להצדיק את עצמו

vLLM מצדיק את המאמץ הנוסף בהתקנה כאשר ברשותכם GPU עם משאבים פנויים ויותר מארבע בקשות פעילות בו-זמנית. מתזמן המשימות שלו עובד ברמת ה-token, ה-cache שלו מנוהל בדפים כך שקטעי זיכרון פנויים מנוצלים מחדש, והוא ממיר VRAM פנוי ליכולת עיבוד מקבילי במקום להשאיר אותו ללא שימוש. נכון לאוגוסט 2026, ההתקנה וההפעלה המתועדות מסתכמות בשתי פקודות:

uv pip install vllm --torch-backend=auto
vllm serve Qwen/Qwen2.5-1.5B-Instruct
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "Qwen/Qwen2.5-1.5B-Instruct",
        "messages": [{"role": "user", "content": "Say hello."}]
    }'

תגובה המכילה מערך choices מעידה על כך שהשרת פעיל והמודל טעון. תחת עומס, שני הפרמטרים המשמעותיים הם --max-num-seqs, ה-"מספר המקסימלי של רצפים לעיבוד באיטרציה אחת", ו---max-num-batched-tokens, ה-"מספר המקסימלי של tokens שניתן לעבד באיטרציה אחת". הראשון מגביל את העיבוד המקבילי. השני הוא תקציב ה-prefill המקוטע שתואר קודם לכן.

מתחת לרף של כארבע בקשות פעילות, או בכל שרת ללא GPU נתמך, vLLM מייצר מורכבות ללא תמורה ממשית. הוא מצפה לכרטיס מסוג CUDA ותופס את רוב הזיכרון בעת העלייה, מה שמהווה בחירה שגויה עבור VPS עם 4 עד 8 GB זיכרון. במקרים אלו, הפתרון הוא מודל קטן יותר עם context קצר יותר ותור שאתם מנהלים. ההבדלים בין Ollama ל-vLLM כמנועי הגשה מכסה את הבחירה הזו במלואה, ו-הרצת Qwen 3 8B על גבי VPS מציג את הדרישות של מודל בינוני עוד לפני הוספת משתמש אחד נוסף.

הפשרה שהפולקלור מסתיר

Continuous batching מעלה את ה-throughput הכולל, ובדרך כלל משפר גם את ה-median latency, כיוון שבקשה שנמצאת בתור מתחילה מוקדם יותר. עם זאת, ה-tail latency מושפע לרעה, וצד זה כמעט אינו מוזכר.

כל רצף נוסף ב-step מוסיף מעט עבודה, ולכן ה-ITL עולה עבור כולם ככל שה-batch מתמלא. ה-prefill של בקשה חדשה גוזל נתח מ-step שהיה מוקצה אחרת למשתמשי ה-streaming. תחת לחץ על ה-cache, ה-scheduler מבצע preemption, מה ששולח בקשה שנוצרה בחלקה חזרה לתחילת ה-prefill שלה.

ממשק צ'אט מציג זנבות (tails), לא ממוצעים. stream שנעצר לשתי שניות באמצע משפט נתפס כמשובש, גם אם הזמן הכולל לסיום הבקשה הוא טוב. מדדו p95 TTFT ו-p95 ITL תחת העומס הצפוי, והתייחסו לממוצע ה-tokens per second כמדד לקיבולת ולא כתיאור של חוויית המשתמש.

ההגדרה המעשית נגזרת מכך. הגבילו את ה-concurrency לרמה נמוכה במעט ממה שהזיכרון מאפשר, כדי שהמנוע לעולם לא יצטרך לבצע preemption. תור קצר וצפוי עדיף על batch עמוק שגורם ל-thrashing, כיוון שמשתמש שממתין ארבע שניות ואז מקבל stream רציף מרוצה יותר ממשתמש שמתחיל מיידית אך נתקל בעצירות.

מה לבדוק כשהביצועים איטיים

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

שגיאת HTTP 503 מ-Ollama. התור מלא. ייתכן שהשרת הגיע לקיבולת המקסימלית שלו, או שהערך OLLAMA_MAX_QUEUE הוגדר נמוך בכוונה כדי להפחית עומס, שזו התנהגות רצויה במקרה כזה.

קצב ה-tokens לשנייה צונח תחת עומס בשרת מבוסס CPU. הריצו את vmstat 1 בזמן שהעומס מתרחש. ערכים שאינם אפס בעמודות si ו-so מעידים על כך שהמכונה מבצעת swapping, כלומר משקולות המודל נקראות מהדיסק עבור כל token. שום שינוי בתצורה לא יפתור זאת. עליכם להקטין את גודל המודל או את מספר ה-slots.

משתמש אחד מתוך עשרה ממתין זמן רב משמעותית מהשאר. חפשו בלוג של vLLM את הביטוי preempted. הסיבה הנפוצה לכך היא preemption וחישוב מחדש (recompute), מה שמעיד על כך שה-cache עמוס מעבר ליכולתו עבור אורך ה-context המוגדר.

זמן ה-TTFT גרוע גם כשהשרת אינו תחת עומס. זוהי בעיית prefill, לא בעיית מקביליות. פרומפטים ארוכים דורשים זמן עיבוד ממשי לפני הופעת ה-token הראשון; לכן, בדקו את גודל הפרומפט ואת ה-prefix caching לפני שאתם בוחנים את החומרה.

FAQ

מדוע ה-LLM שאני מארח בעצמי מואט כאשר אדם נוסף משתמש בו?

לרוב הוא אינו מואט כלל, אלא ממתין בתור. Ollama מגיע עם OLLAMA_NUM_PARALLEL מוגדר ל-1, לכן הבקשה השנייה ממתינה עד שהראשונה פולטת את ה-token האחרון שלה. ניתן להבחין בין המקרים על ידי מדידת זמן ה-stream של משתמש אחד בזמן שאחר ממתין: אם קצב ה-tokens לשנייה של המשתמש השני תקין ברגע שהוא מתחיל, הבעיה היא תור, והעלאת מספר המקביליות תפתור זאת. אם שני ה-streams רצים בחצי מהירות, אתם חולקים בפועל את רוחב הפס של הזיכרון, וזהו מגבלה חומרתית.

כמה משתמשים בו-זמנית יכול GPU קטן לשרת?

ספרו זיכרון, לא משתמשים. תחילה יש לחשב את ה-weights, ולאחר מכן את ה-KV cache, שעלותו היא 2 כפול מספר השכבות כפול מספר ה-key/value heads כפול ממד ה-head כפול מספר הבייטים, לכל token, לכל שיחה פעילה. מודל 8B טיפוסי עם 36 שכבות, 8 key/value heads וממד head של 128 צורך כ-144 KiB לכל token ב-16-bit, כך ששיחה של 8,192 tokens דורשת בערך 1.2 GB. כרטיס של 24 GB המריץ מודל זה ב-16-bit מותיר כ-6 GB פנויים ל-cache, מה שמאפשר כחמש שיחות ב-context מלא, או יותר אם תקצרו את ה-context.

האם continuous batching הופך את התגובה של כל משתמש לאיטית יותר?

החציון של ה-latency בדרך כלל משתפר, כיוון שבקשות מפסיקות להמתין לסיום של batch שלם. ה-tail latency מחמיר. כל רצף נוסף מוסיף עבודה לכל שלב פענוח, ה-prefill של בקשה חדשה גוזל חלק משלב ה-streaming של משתמשים קיימים, ובקשה שנקטעה צריכה לעבור prefill פעמיים. מדדו את ה-p95 inter-token latency, לא את הממוצע, כיוון שחלון צ'אט הופך השהיות לניכרות לעין באופן שהממוצעים מסתירים.

האם עליי להעלות את OLLAMA_NUM_PARALLEL או לעבור ל-vLLM?

העלו תחילה את מספר המקביליות. זה בחינם, דורש רק קובץ הגדרה אחד, ופותר את המקרה הנפוץ שבו ארבעה אנשים ממתינים בתור מאחורי תשובה ארוכה אחת. הזיכרון הוא המגבלה: בקשות מקבילות מכפילות את ה-context שעליכם להחזיק, לכן עקבו אחר זליגת שכבות ל-CPU. עברו ל-vLLM כאשר יש לכם GPU עם VRAM פנוי ויותר מארבע בקשות שרצות באמת בו-זמנית, שכן זו הנקודה שבה paged cache ותזמון ברמת ה-token מחזירים יותר ממה שהם עולים.

האם יותר ליבות CPU יתקנו שרת LLM איטי?

לא עבור החלק שהמשתמשים הכי שמים לב אליו. פענוח (decode) קורא את כל המודל מהזיכרון עבור כל token, לכן הוא מוגבל על ידי רוחב הפס של ה-RAM, וליבות נוספות מפסיקות לעזור ברגע שרוחב הפס רווי. ה-prefill אכן משתפר עם יותר ליבות, לכן יותר ליבות יקצרו את הזמן עד ל-token הראשון ב-prompts ארוכים. ב-VPS עם 4 עד 8 GB, המגבלה היא בדרך כלל נפח הזיכרון, והפתרון האפקטיבי הוא מודל קטן יותר או context קצר יותר, ולא יותר vCPUs.

#vllm#ollama#batching#throughput#self-hosted-ai