להוזיל עלויות LLM
בלי להתפשר על איכות
חשבונית ה-AI מטפסת מהר. הבשורה הטובה: רוב העלות מיותרת. עם prompt caching נכון חוסכים עד 90% על טוקנים חוזרים, עם batch חוסכים 50% על עבודה לא-דחופה, ובחירת מודל נכונה מורידה עוד. במדריך: איך כל טכניקה עובדת, ואיך לא לשבור את המטמון בטעות.
מאיפה בכלל מגיעה העלות
חיוב ב-LLM הוא לפי טוקנים — יחידות טקסט. משלמים בנפרד על קלט (מה ששולחים למודל: פרומפט, הקשר, מסמכים) ועל פלט (מה שהמודל מייצר), ופלט תמיד יקר בהרבה מקלט. שלוש עובדות שמסבירות למה החשבונית מתנפחת:
- הקלט חוזר על עצמו — בכל בקשה שולחים שוב את אותו system prompt, אותן הוראות ואותם מסמכים. משלמים עליהם כל פעם מחדש.
- ההקשר גדל — בשיחה או בסוכן, ההיסטוריה מצטברת. הבקשה ה-20 יקרה פי כמה מהראשונה כי היא נושאת את כל מה שקדם.
- מודל גדול מדי — משתמשים במודל הכי חזק גם למשימות פשוטות שמודל קטן וזול פי 5–25 היה עושה מצוין.
כל אחת מהבעיות האלה יש לה פתרון ישיר. נעבור עליהן לפי סדר ההשפעה.
סדר המנופים, לפי החזר
לפני הטכניקות עצמן — הסדר, כי עבודה במנוף הלא נכון היא הדרך הנפוצה לבזבז שבוע על חיסכון של אחוזים. המנופים מסודרים כאן לפי החזר ביחס למאמץ, וההמלצה היא ללכת לפי הסדר ולא לקפוץ:
- מטמון על ההקשר הקבוע. ההשפעה הגדולה ביותר, והיא עניין של סידור ולא של ויתור. שינוי של סדר הפרומפט, לא של תוכנו.
- לצמצם את מה שנשלח. פחות קטעים שנשלפים, תוצאות כלים גזומות, היסטוריה מסוכמת. כאן נמצא הרוב המכריע של מה שאפשר לחסוך במערכת בוגרת.
- מודל קטן יותר לשלבים הקלים. סיווג וחילוץ לא צריכים את המודל היקר.
- עיבוד באצווה לכל מה שלא דחוף.
- לקצר את הפלט. אמיתי, ובדרך כלל המנוף הקטן ביותר — פשוט כי הפלט קטן מהקלט מלכתחילה.
שימו לב למה שנמצא בראש ולמה שלא: שני המנופים הגדולים אינם "לבחור מודל זול יותר". זו האינטואיציה הראשונה של רוב האנשים, והיא בדרך כלל רק הרביעית בחשיבות — ובניגוד לשניים הראשונים, היא זו שעלולה לעלות באיכות.
ההרחבה על תמחור עצמו, על איך לאמוד חשבון מראש ועל מה לנטר נמצאת במדריך התמחור. הדף הזה עוסק בביצוע.
Prompt Caching — הטכניקה עם ההשפעה הגדולה ביותר
זה החיסכון הכי גדול, ורוב האנשים לא מנצלים אותו. Prompt caching מאפשר לספק ה-AI "לזכור" חלק קבוע מהפרומפט בין בקשות. במקום לעבד מחדש בכל פעם את ה-2,000 טוקנים של ה-system prompt והמסמכים, המודל טוען אותם מהמטמון — במחיר מוזל דרמטית (טוקן שנקרא מהמטמון עולה כעשירית מטוקן קלט רגיל).
המנגנון מבוסס על התאמת prefix: הספק מזהה שהתחלת הפרומפט זהה לבקשה קודמת וטוען אותה מהמטמון. סדר העיבוד קבוע — קודם הגדרות הכלים, אחר כך ה-system prompt, ואז ההודעות. לכן:
שים את התוכן הקבוע (system prompt, רשימת כלים, מסמכי רקע) בתחילת הפרומפט, ואת התוכן המשתנה (השאלה של המשתמש, timestamp, מזהה בקשה) בסוף. כך ה-prefix הקבוע נשאר במטמון והחלק שמשתנה לא שובר אותו.
נקודות מפתח מעשיות: יש מינימום טוקנים כדי שמטמון בכלל יופעל (סביב 1,024 טוקנים — קצר מזה פשוט לא ייכנס למטמון), למטמון יש תוקף קצר (מתאפס אחרי כמה דקות של חוסר שימוש, אלא אם מרעננים), ומוגבל מספר "נקודות השבירה" של המטמון בבקשה. את החיסכון האמיתי משיגים כשאותו prefix גדול חוזר בהרבה בקשות — למשל צ'אטבוט עם system prompt ארוך, או RAG עם אותם מסמכי הקשר.
איך לא לשבור את המטמון בטעות
זו הנקודה שמכשילה את רוב האנשים: המטמון עובד לפי התאמה מדויקת של ה-prefix. כל שינוי של בית אחד בהתחלה — פוסל את כל מה שאחריו. אלה ה"רוצחים השקטים" של המטמון:
- timestamp דינמי בפרומפט — הזרקת
datetime.now()לתוך ה-system prompt משנה אותו בכל בקשה ושוברת את המטמון לחלוטין. אם צריך זמן, שים אותו בסוף. - JSON לא ממוין — אם סדר המפתחות ב-JSON משתנה בין בקשות, ה-prefix שונה. מיין תמיד.
- רשימת כלים משתנה — כלים שמתווספים/מוסרים או משנים סדר פוסלים את המטמון. שמור סדר קבוע.
- ID ייחודי בהתחלה — מזהה בקשה או session בתחילת הפרומפט = מטמון חדש בכל פעם.
אל תנחש — תמדוד. בתשובת ה-API יש שדה שמדווח כמה טוקנים נקראו מהמטמון (למשל cache_read_input_tokens). אם הוא אפס על בקשות חוזרות, יש רוצח שקט שפועל. כלי observability יראו לך את זה מיד.
המנוף השני: לשלוח פחות
אחרי המטמון, זה המקום שבו נמצא רוב הכסף — ובניגוד למטמון, הוא דורש החלטות ולא רק סידור.
העיקרון פשוט: הקלט הוא רוב החשבון, ורוב הקלט אינו נחוץ. שלושה מקומות שבהם הוא מתנפח, לפי גודל התרומה:
- תוצאות כלים גולמיות. תשובת API עם ארבעים שדות שמתוכם שלושה רלוונטיים — ובסוכן היא נשלחת מחדש בכל צעד עד סוף הריצה. גיזום בנקודת המקור, בתוך מימוש הכלי, הוא האופטימיזציה עם ההחזר הגבוה ביותר בכל מערכת סוכן.
- קטעים שנשלפו ולא נוצלו. אם המערכת שולפת שמונה קטעים והתשובה נשענת בדרך כלל על שניים — שישה מהם משלמים מס בכל קריאה. הפתרון אינו לשלוף פחות אלא לדרג ולהעביר פחות: לשלוף רחב, להעביר צר.
- היסטוריה שנגררת. בשיחה ארוכה, ההודעות מלפני עשרים תורות רלוונטיות לעתים רחוקות במלואן. חלון גולש — לשמור את האחרונות במלואן ולסכם את מה שקדם — מטפל בזה.
וכלל שמפתיע מי שמנסה לראשונה: הבדיקה שווה יותר מהניחוש. ספרו טוקנים לפי מרכיב על קריאה אמיתית — הנחיה, כלים, ידע שנשלף, היסטוריה — ובמחצית מהמקרים מתברר שהמרכיב שתכננתם לצמצם אינו זה שתופס את המקום.
Batch Processing — 50% הנחה על עבודה לא-דחופה
לא כל בקשה צריכה תשובה מיידית. אם אתה מעבד 10,000 מסמכים בלילה, מסווג דאטהסט, או מייצר תיאורים למוצרים — זו עבודה a-סינכרונית. רוב הספקים מציעים Batch API שמעבד בקשות כאלה בתוך חלון זמן (בד"כ עד 24 שעות) תמורת 50% הנחה על המחיר הרגיל.
הכלל פשוט: כל דבר שלא צריך תשובה בשנייה — לתוך batch. משתמש שמחכה לצ'אט צריך זמן אמת; ריצת לילה של דוחות לא. חצי מהחשבונית על כל העבודה הזו פשוט נעלמת.
מטמון משלכם, מעל זה של הספק
מטמון הספק חוסך על ההקשר החוזר. יש שכבה נוספת שרוב המערכות לא מפעילות והיא חוסכת את הקריאה כולה: מטמון על הקלט שלכם.
הרעיון פשוט — אם אותה בקשה בדיוק כבר נענתה, החזירו את התשובה השמורה במקום לשלם עליה שוב. במערכות שירות זה משתלם יותר משנדמה, כי אותן שאלות חוזרות בלי סוף: שעות פתיחה, מדיניות החזרות, "איך מבטלים".
שלושה כללים שהופכים את זה לבטוח:
- המפתח חייב לכלול את כל מה שמשפיע. לא רק השאלה — גם גרסת ההנחיה, המודל, וכל פרמטר שמשנה את התשובה. מפתח חלקי מחזיר תשובה שנוצרה בתנאים אחרים.
- ובמערכת רב-לקוחית — גם מזהה הלקוח. זו לא אופטימיזציה אלא תנאי: מטמון בלי הפרדה בין לקוחות הוא דליפת מידע שנראית כמו שיפור ביצועים.
- תוקף קצר לתוכן שמשתנה. מחירים ומלאי לא שייכים למטמון של יום.
ומה לא לעשות: מטמון לפי דמיון סמנטי — להחזיר תשובה שמורה לשאלה "דומה". "מה המחיר של המסלול הבסיסי" ו"מה המחיר של המסלול העסקי" קרובות מאוד במרחב הווקטורי, והמילה שנושאת את ההבדל היא בדיוק זו שנבלעת בממוצע. בשאלות עם פרמטר זו דרך לענות תשובה שגויה בביטחון מלא.
לוודא שהמטמון באמת עובד
זה השלב שמדלגים עליו, והוא הופך את כל הסעיף הקודם מהנחה לעובדה. רוב מי שחושב שהמטמון שלו עובד לא בדק — ומכיוון שהוא נשבר בשקט, אין שום סימן חיצוני.
הבדיקה עצמה קצרה: תשובת ה-API מחזירה כמה טוקנים נקראו מהמטמון וכמה נכתבו אליו. אם הקריאה מהמטמון אפסית — הוא לא עובד, גם אם סידרתם את הפרומפט נכון.
r = client.messages.create(...)
u = r.usage
print("נכתב למטמון:", u.cache_creation_input_tokens)
print("נקרא ממטמון:", u.cache_read_input_tokens)
print("קלט רגיל: ", u.input_tokens)
# בקריאה הראשונה: כתיבה גבוהה, קריאה אפס — תקין.
# בקריאה השנייה על אותו prefix: הקריאה אמורה לקפוץ.
# אם היא נשארת אפס — משהו בפתיחה משתנה.
ומה עושים כשהיא נשארת אפס: להדפיס את הפרומפט המלא של שתי קריאות עוקבות ולהשוות אותן תו מול תו. ההבדל תמיד שם, והוא כמעט תמיד אחד מארבעה — חותמת זמן, מזהה בקשה, סדר מפתחות ב-JSON, או רשימת כלים שהשתנתה.
ושתי נקודות שקל לפספס: למטמון יש תוקף קצר, ולכן מערכת עם תעבורה דלילה עשויה לא ליהנות ממנו כלל; ויש מינימום טוקנים להפעלתו, כך שפרומפט קצר פשוט לא נכנס — וזה בסדר, כי שם גם אין הרבה מה לחסוך.
בחירת מודל וניהול context
הטעות היקרה ביותר היא להשתמש במודל הכי חזק לכל דבר. הפער בין מודל דגל למודל קטן הוא פי 5 עד פי 25 במחיר. הרוב המכריע של המשימות — סיווג, חילוץ, סיכום קצר, ניתוב — לא צריך את המודל הכי חזק.
- נתב לפי מורכבות — משימות פשוטות למודל קטן וזול, משימות מורכבות למודל דגל. אפשר אפילו לתת למודל קטן לנתב.
- מודל מקומי למשימות בנפח — למשימות חוזרות אפשר להריץ מודל מקומי (Llama/Qwen) באפס עלות פר-בקשה.
- גזום את ההקשר — בסוכנים ובשיחות ארוכות, אל תגרור היסטוריה אינסופית. סיכום או ניקוי של הקשר ישן חוסך טוקנים בכל בקשה.
- פלט קצר — פלט יקר פי כמה מקלט. בקש מהמודל תשובות תמציתיות והגבל
max_tokensבהתאם.
עברית: למה החשבון גבוה ממה שחישבתם
סעיף קצר עם השלכה גדולה. אותו תוכן בעברית נשבר ליותר טוקנים מאשר באנגלית, כי המפרקים אומנו בעיקר על טקסט אנגלי ומילה עברית שלמה מתפצלת לכמה חלקים.
שלוש השלכות ישירות על החשבון:
- הערכה לפי מספר מילים תצא נמוכה מדי. זה הפער שהכי מפתיע צוותים שתכננו תקציב מטבלה אמריקאית.
- חלון ההקשר מתמלא מוקדם יותר, מה שדוחף לחלק את העבודה לשלבים — וכל שלב הוא קריאה נוספת. כלומר העברית מייקרת פעמיים: גם לטוקן וגם במבנה.
- ולכן בחירה טובה של מה שנשלח משתלמת כאן יותר מאשר במערכת אנגלית מקבילה. כל קטע מיותר עולה יותר.
והדרך היחידה לדעת את המספר שלכם היא למדוד אותו על התוכן שלכם:
enc = tokenizer_for(MODEL) # לפי הספק שאתם עובדים מולו
he = open("sample_he.txt", encoding="utf-8").read()
en = open("sample_en.txt", encoding="utf-8").read()
print("HE:", len(he.split()), "מילים →", len(enc.encode(he)), "טוקנים")
print("EN:", len(en.split()), "מילים →", len(enc.encode(en)), "טוקנים")
# היחס בין השניים הוא המכפיל שצריך להיכנס לתקציב שלכם
למה סוכנים יקרים פי כמה
מערכת של סוכן מתנהגת אחרת מכל מערכת אחרת מבחינת עלות, ומי שלא מבין את המנגנון מופתע מהחשבון הראשון.
העלות אינה מספר הצעדים אלא סכום ההקשרים. בכל צעד נשלח מחדש כל מה שהצטבר עד כה — ההנחיה, הגדרות הכלים, וכל תוצאות הכלים מהצעדים הקודמים. סוכן של עשרה צעדים אינו פי עשרה מקריאה אחת; הוא יותר, כי ההקשר גדל בדרך.
שלושה מקומות שבהם הכסף בורח בשקט דווקא בסוכנים:
- תוצאות כלים שלא נגזמו. נשלחות מחדש בכל צעד עד סוף הריצה. זו הסיבה שהגיזום בנקודת המקור משתלם כאן יותר מבכל מקום אחר.
- רשימת כלים מלאה תמיד. הגדרות הכלים נשלחות בכל קריאה, כולל כשאינן רלוונטיות לשלב. בסוכן של חמישה־עשר צעדים אותו נתח קבוע משולם חמש־עשרה פעמים.
- ניסיונות חוזרים שלא נספרים. קריאה שנכשלה ורצה שוב מופיעה פעמיים בחשבון ופעם אחת בלוג — אלא אם תיעדתם אותה במפורש.
ושתי הגנות שחייבות להיות בקוד: תקרת צעדים, כי סוכן תקוע שמנסה שוב הוא חשבון שגדל בלי שאיש רואה; וזיהוי לולאה — אותה קריאה עם אותם פרמטרים פעמיים ברצף היא סימן לעצור.
הצד השני: לקצר את הפלט
המנוף הקטן ביותר ברשימה, וגם הקל ביותר ליישום — ויש בו פרט אחד שמצדיק סעיף.
הפלט יקר בהרבה לטוקן מהקלט, ובכל זאת הוא לרוב החלק הקטן בחשבון, פשוט כי הוא קצר בהרבה. לכן קיצור תשובות הוא שיפור אמיתי ומוגבל — למעט במקרה אחד.
המקרה הזה הוא מודלים שמייצרים שרשרת חשיבה לפני התשובה. החשיבה היא טוקני פלט לכל דבר, ולעתים היא ארוכה פי כמה מהתשובה עצמה. מערכת שמריצה מודל חושב על משימה פשוטה משלמת על נימוק שאף אחד לא יקרא — וזו אחת הדרכים הנפוצות ביותר לשלם פי כמה בלי לדעת.
שלוש פעולות מעשיות:
- להשתמש במודל חושב רק בשלב שדורש נימוק, ולא כברירת מחדל לכל המערכת.
- לבקש תמציתיות בהנחיה — ובאמת לנסח את זה, לא "בקצרה" אלא "שני משפטים, בלי הקדמה".
- לקבוע תקרת טוקנים לפלט. לא רק לחיסכון: היא גם מגלה תשובות שנקטעות, שבלעדיה נראות בלוג כמו תשובות קצרות ולא כמו תקלה.
מתי חיסכון עולה יותר ממה שהוא חוסך
לכל מנוף בדף הזה יש גבול, ושווה לדעת איפה הוא — כי מערכת זולה שעונה לא נכון אינה זולה, היא רק מעבירה את העלות לזמן תיקון ולאמון.
- לרדת מודל יותר מדי. מודל קטן מצוין בסיווג ובחילוץ, ונחלש בניסוח ובנימוק רב-שלבי. ההחלטה צריכה להיבדק על מערך מקרים, לא להיגזר מהמחיר.
- לגזום את ההקשר עד שחסר מידע. אם המודל מתחיל לשאול שאלות הבהרה שלא שאל קודם, גזמתם יותר מדי.
- לקצר תשובות עד שהן לא מועילות. תשובה שדורשת שאלת המשך היא שתי קריאות במקום אחת — לא חסכתם, הוספתם.
- אצווה על משהו שכן דחוף. ההנחה אמיתית והזמן גם, ומשתמש שמחכה שעה לתשובה לא ישוב.
- ולבזבז שבוע על אופטימיזציה בנפח נמוך. מערכת שעולה עשרות דולרים בחודש לא מצדיקה את זמן העבודה.
הכלל שמעל כולם: כל שינוי שנעשה לשם חיסכון צריך לעבור את אותו מערך מקרים כמו כל שינוי אחר. אחרת גיליתם את הפגיעה באיכות מהלקוחות, וזו הדרך היקרה ביותר לגלות.
מתי לא לעסוק בזה בכלל
אופטימיזציית עלות היא עבודה, ויש מצבים שבהם היא פשוט לא משתלמת:
- לפני שהמערכת מוכיחה את עצמה. לייעל משהו שאולי ייזרק זו עבודה על מה שלא יישאר. קודם שיעבוד, אחר כך שיהיה זול.
- בנפח נמוך. מתחת לכמה עשרות דולרים בחודש, שעת עבודה שווה יותר מהחיסכון השנתי.
- כשהצוואר אינו המודל. אם רוב ההשהיה או העלות הן בשליפה, במסד הנתונים או בתשתית — שם צריך להסתכל.
- כשהמערכת עוד משתנה כל יום. כל אופטימיזציה תיהרס בשינוי הבא, ותצטרכו לעשות אותה שוב.
- כשאין דרך למדוד אם האיכות נפגעה. בלי מערך מקרים, חיסכון הוא הימור.
והפרופורציה ששווה להחזיק: בחודש הראשון של מערכת חדשה עדיף להשקיע במדידת איכות מאשר במדידת עלות. מערכת שעובדת נכון אפשר להוזיל בכמה מנופים ידועים — כל אלה שבדף הזה. מערכת זולה שעונה לא נכון צריך לבנות מחדש.
טעויות שחוזרות
- להתחיל מבחירת מודל זול יותר. זה המנוף הרביעי, והיחיד שעלול לעלות באיכות.
- להניח שהמטמון עובד בלי לבדוק. הוא נשבר בשקט, ואין שום סימן חיצוני.
- חותמת זמן או מזהה בפתיחת ההנחיה. מבטלים את המטמון על כל הקריאה.
- JSON לא ממוין ורשימת כלים שמשתנה. אותו אפקט, פחות גלוי.
- להעביר למודל את כל מה שנשלף. הקשר מדולל ועלות כפולה בלי שיפור מקביל.
- תוצאות כלים גולמיות בסוכן. נשלחות מחדש בכל צעד עד סוף הריצה.
- בלי תקרת צעדים. סוכן תקוע הוא חשבון שגדל בלי שאיש רואה.
- מודל חושב על משימה פשוטה. משלמים על נימוק שאיש לא יקרא.
- מטמון לפי דמיון סמנטי. שאלות עם פרמטר יקבלו תשובה של שאלה אחרת.
- מטמון בלי הפרדת לקוחות. דליפה שנראית כמו שיפור ביצועים.
- לוותר על אצווה. הנחה ניכרת שמושארת על השולחן בכל מערכת שלא צריכה תשובה מיידית.
- לחשב תקציב בעברית לפי מספר מילים. יוצא נמוך מדי, ובמערכת רב-שלבית נמוך בהרבה.
צ'קליסט החיסכון
לפני שאתה מייעל — תמדוד. בלי מעקב עלויות אתה מנחש. חבר observability, גלה איזה פיצ'ר או מודל אוכל את התקציב, ואופטם את זה. 20% מהקוד אחראי בד"כ ל-80% מהעלות.