Serverless AI Architecture — בניית AI על Functions
מאת צוות מדיה דיל · 09.08.2026 · Technology · 10 דק׳
בניית סוכני AI על Serverless Functions חוסכת ניהול תשתית ומשלמת רק על שימוש בפועל - אבל Cold Starts, מגבלות זמן ריצה ומצב חסר-שרת דורשים תכנון שונה לגמרי מהרגיל.
צוות פיתוח קטן רוצה להריץ סוכן AI שמסכם פניות תמיכה, בלי לנהל שרתים, בלי לדאוג ל-scaling, ובלי לשלם עבור זמן compute שלא בשימוש. Serverless נשמע כמו התאמה מושלמת - כותבים פונקציה, מעלים אותה, והפלטפורמה דואגת לכל השאר. אבל ברגע שהפונקציה הזו צריכה לקרוא ל-LLM שלוקח 40 שניות להשיב, לשמור מצב שיחה בין קריאות, ולהתמודד עם Cold Start שמוסיף עוד שתי שניות לכל בקשה ראשונה - מתגלה שבניית AI על Serverless דורשת החלטות ארכיטקטוניות ספציפיות שממש לא זהות לבניית API רגיל.
למה בכלל Serverless עבור AI Workloads
המודל הכלכלי של Serverless - תשלום לפי זמן ריצה בפועל, ללא עלות כשאין תעבורה - מתאים במיוחד לעומסי AI שהם לרוב Bursty: שיא בבוקר, שקט בלילה, קפיצה פתאומית סביב קמפיין שיווקי. שרת קבוע שרץ 24/7 כדי לטפל בעומסי שיא נדירים הוא בזבוז ברור. בנוסף, Serverless מסיר את הצורך בניהול תשתית - patching, scaling ידני, ניטור בריאות שרתים - ומאפשר לצוות לחשוב על לוגיקת הסוכן במקום על תפעול. זה מתחבר ישירות לעקרונות שמפורטים ב-פתרונות AI שאנחנו בונים ללקוחות.
Cold Starts: האויב השקט של סוכני AI
כשפונקציה לא רצה זמן מה, הפלטפורמה "מכבה" אותה, וכשבקשה חדשה מגיעה, נדרש זמן לאתחל סביבת ריצה חדשה - Cold Start. עבור API רגיל זה תוספת של עשרות עד מאות מילישניות, בדרך כלל בלתי מורגשת. עבור סוכן AI שכבר לוקח שניות ארוכות בגלל קריאת המודל עצמה, הוספת cold start עלולה להוציא את המשתמש מסבלנות, במיוחד בממשק interactive. אסטרטגיות הפחתה כוללות: Provisioned Concurrency - החזקת מספר instances "חמים" תמיד, במחיר נוסף אבל צפוי; צמצום גודל ה-dependencies שנטענות באתחול (SDK כבד של ספריית AI מלאה יכול להוסיף שניות שלמות); ו-Lazy Loading של רכיבים שלא נחוצים בכל בקשה.
Function Composition: פיצול נכון לעומת פיצול מיותר
כשמחליטים לפצל workflow מורכב לכמה פונקציות נפרדות בגלל מגבלת זמן ריצה, נוצרת שאלה עיצובית חדשה: היכן בדיוק לחתוך? חיתוך גס מדי (למשל שתי פונקציות ענקיות) לא באמת פותר את בעיית הזמן; חיתוך עדין מדי (פונקציה נפרדת לכל צעד בודד) מכביד על הביצועים בגלל cold start מצטבר ומקשה על מעקב אחרי הזרימה הכוללת. נקודת חיתוך טובה היא בגבול טבעי בין שלבים - למשל אחרי כל קריאת כלי חיצוני משמעותית, או אחרי שלב שמייצר תוצר ביניים שממילא צריך להישמר למקרה כשל. כל פונקציה כזו מקבלת קלט מוגדר וברור מהפונקציה הקודמת דרך מאגר מצב חיצוני, ולא באמצעות קריאה ישירה בזיכרון - מה שגם מקל על בדיקה ודיבוג של כל שלב בנפרד.
מגבלת זמן ריצה: כשהסוכן צריך יותר זמן מהמותר
לרוב פלטפורמות ה-Serverless יש תקרת זמן ריצה - דקות בודדות עד כרבע שעה, תלוי בפלטפורמה. משימת AI פשוטה (סיווג, סיכום קצר) בדרך כלל נכנסת בקלות. אבל workflow מורכב עם כמה קריאות עוקבות למודל, קריאה לכלים חיצוניים, וחזרות (loops) של תיקון-עצמי - יכול בקלות לחרוג. שתי גישות עיקריות לפתרון: פיצול ה-workflow לכמה פונקציות נפרדות שמעבירות מצב ביניהן דרך תור או מנוע Orchestration (ראו Agent Orchestration), או מעבר לפלטפורמת compute עם זמן ריצה ארוך יותר עבור המשימות הכבדות באמת, תוך שמירה על Serverless לחלקים הקלים. שילוב היברידי כזה נפוץ בפועל יותר מ"הכל serverless" טהור.
Statelessness: איפה שומרים את הזיכרון של הסוכן
פונקציית Serverless היא מטבעה חסרת מצב (Stateless) - כל הפעלה מתחילה נקייה, בלי זיכרון מהפעלה קודמת. עבור סוכן שינהל שיחה מרובת-תורות עם משתמש, זה אומר שכל ההקשר - היסטוריית שיחה, מצב ביניים, תוצאות כלים שכבר הופעלו - חייב להישמר מחוץ לפונקציה, במאגר persistent (Redis, בסיס נתונים, או שירות ניהול-מצב ייעודי). זה בדיוק ההבדל בין Stateless ל-Stateful AI Architecture, וב-Serverless ההחלטה הזו לא אופציונלית - היא נכפית על ידי המודל התפעולי עצמו.
// Pattern: state passed explicitly, not held in memory
export async function handler(event) {
const { session_id, message } = event.body;
const history = await stateStore.get(session_id);
const result = await runAgent({ history, message });
await stateStore.save(session_id, result.newHistory);
return { statusCode: 200, body: result.reply };
}
עלות: מודל תשלום שיכול להפתיע
לתשלום לפי זמן ריצה יש צד שני: קריאת LLM איטית (למשל 20 שניות המתנה לתשובה) "נועלת" את הפונקציה כל אותו זמן, ומחייבת אתכם על משך ההמתנה עצמה, גם אם הפונקציה בפועל לא עושה כלום מלבד לחכות לתשובה מה-API החיצוני. בעומסים גבוהים, זה יכול להתברר יקר יותר משרת קבוע עם ניצולת גבוהה. חישוב עלות אמיתי צריך לכלול את זמן ההמתנה למודל, לא רק את זמן העיבוד "האמיתי" - נושא שמורחב ב-AI Cost Engineering.
Streaming מתוך Serverless: אתגר טכני של ממש
משתמשים מצפים לראות תשובה של LLM "נכתבת" בזמן אמת (Streaming), לא לחכות לתשובה שלמה. חלק מפלטפורמות ה-Serverless תומכות ב-streaming responses באופן טבעי, אחרות דורשות מעקף (כמו חיבור WebSocket דרך שירות נפרד, כי הפונקציה עצמה לא יכולה להחזיק חיבור פתוח ארוך טווח). זו החלטת ארכיטקטורה שכדאי לקבל מוקדם, כי שינוי מ-request-response ל-streaming אחרי שהמערכת כבר בנויה דורש רה-ארכיטקטורה משמעותית. הנושא מפורט יותר ב-AI Streaming Architecture.
דוגמה מהשטח: סוכן סיכום פניות תמיכה
פונקציית Serverless מופעלת מ-Webhook כשפנייה חדשה נסגרת, קוראת ל-LLM לסכם את השיחה בפסקה אחת ולחלץ תגיות (קטגוריה, סנטימנט, האם נדרשת מעקב). הפונקציה חסרת מצב לחלוטין - היא מקבלת את מזהה הפנייה, שולפת את התמלול מבסיס הנתונים, מריצה סיכום, וכותבת את התוצאה חזרה. אין צורך בזיכרון בין הפעלות, אין workflow מורכב מרובה-שלבים - זה בדיוק סוג המשימה שבו Serverless מנצח: קצרה, עצמאית, מופעלת לפי אירוע.
ניהול Dependencies וגודל החבילה
גודל חבילת הפריסה (Deployment Package) משפיע ישירות על זמן ה-cold start - SDK כבד לספריית AI, ספריות עיבוד תמונה או NLP מקומיות, כל אלה מוסיפים משקל שנטען בכל אתחול קר. הפרקטיקה הנכונה כוללת שלושה עקרונות: לייבא רק את מה שבאמת נדרש (import סלקטיבי במקום ספרייה שלמה), להפריד פונקציות לפי אחריות כך שכל אחת נושאת רק את ה-dependencies שהיא צריכה בפועל, ולשקול Layers או Container Images משותפים כשיש dependencies כבדים שחוזרים על עצמם בכמה פונקציות - כדי לא לשכפל את אותו משקל שוב ושוב בכל פריסה.
הפעלה מקבילה (Concurrency Limits) ברמת הפלטפורמה
פלטפורמות Serverless מגבילות את מספר ההפעלות המקבילות של אותה פונקציה - ברירת מחדל שנועדה למנוע ממערכת בודדת "לצרוך" את כל קיבולת הפלטפורמה, אבל שגם יכולה להפוך לצוואר בקבוק בלתי צפוי כשהעומס גדל. חשוב לבדוק מראש מה תקרת ה-concurrency בפועל, ולא להניח שהיא "בלתי מוגבלת" רק כי אין שרת שצריך לנהל. כשמגיעים לתקרה, בקשות נוספות נדחות או ממתינות - התנהגות שצריכה טיפול מפורש בקוד הצד הקורא (retry עם backoff), כדי שהמערכת לא תיכשל בשקט תחת עומס. תכנון קיבולת מראש, כולל בקשה מהספק להעלאת תקרה כשצפוי עומס שיא ידוע (כמו קמפיין מתוכנן), חוסך הפתעות לא נעימות.
Observability בסביבה חסרת-שרת
ניפוי שגיאות ב-Serverless מאתגר יותר מבשרת מסורתי - אין גישה ל-SSH, אין תהליך רץ שאפשר "להיכנס אליו" ולבדוק מצב חי, וכל הפעלה היא instance נפרד וזמני. לכן מבנה לוגים מובנה (Structured Logging) עם מזהה בקשה עקבי הוא לא נוחות אלא תנאי לניתוח תקלות בדיעבד. חשוב במיוחד לתעד את משך הזמן שהתבזבז בהמתנה למודל בנפרד מזמן העיבוד הפנימי של הפונקציה עצמה - כי זה מה שמסביר בפועל את רוב עלות ה-compute וזמן הריצה במערכות AI Serverless.
עלות שולית לעומת עלות בסיס: מודל חשיבה שונה
בתשתית מסורתית חושבים על עלות בסיס קבועה (השרת עולה X בחודש, בין אם הוא בשימוש או לא). ב-Serverless, כמעט כל העלות היא שולית - כל הפעלה נספרת בנפרד, וכשאין תעבורה, העלות בפועל קרובה לאפס. זה משנה את הדרך שבה כדאי לחשוב על אופטימיזציה: במקום לשאול "איך מנצלים טוב יותר משאב קבוע שכבר שילמנו עליו", השאלה הופכת ל"איך מקטינים את העלות של כל הפעלה בודדת" - הקטנת זמן ריצה ממוצע, הפחתת כמות הטוקנים שנשלחים למודל, וצמצום הפעלות מיותרות (retries שאין להם צורך אמיתי) הופכים לכלי האופטימיזציה המרכזיים, ולא ניצול גבוה יותר של קיבולת קבועה.
Vendor Lock-in: מה שקורה כשרוצים לעבור פלטפורמה
פלטפורמות Serverless שונות זו מזו במגבלות (זמן ריצה, זיכרון, תמיכה ב-streaming), במודל התמחור, ובממשקי ה-API הפנימיים שלהן להפעלת פונקציות. מעבר בין ספקים אחרי שהמערכת כבר בנויה סביב API ייחודי לספק מסוים דורש refactoring משמעותי. הפרקטיקה המומלצת: להפריד את לוגיקת הסוכן עצמה (קריאה למודל, עיבוד תוצאה) משכבת ה-handler הספציפית לפלטפורמה, כך שרק שכבת ה-glue הדקה תלויה בספק, ולא הלוגיקה העסקית המרכזית. זה מקל משמעותית על מעבר עתידי, אם וכאשר יידרש.
טעויות נפוצות
- הנחה שהפונקציה "זוכרת" בין קריאות - Serverless לא שומר state מקומי אמין, גם אם לפעמים נדמה שכן בגלל warm instances.
- אי-חישוב עלות זמן המתנה למודל - מוביל להפתעות בחשבון בסוף החודש.
- Workflow מורכב בפונקציה בודדת - חורג ממגבלת זמן ריצה בלי אזהרה מוקדמת בבדיקות.
- התעלמות מ-Cold Start בממשק אינטראקטיבי - חוויית משתמש נפגעת בלי שקל לאתר את הסיבה בהתחלה.
שאלות נפוצות
מתי Serverless עדיף על שרת AI קבוע?
כשהעומס לא צפוי ומשתנה משמעותית, כשהמשימות קצרות ועצמאיות, וכשעדיפות פשטות תפעולית על שליטה מלאה בסביבת הריצה. עומס קבוע וגבוה לרוב יעיל וזול יותר על תשתית מנוהלת קבועה.
איך פותרים בעיית Cold Start במוצר שדורש תגובה מיידית?
Provisioned Concurrency לפונקציות קריטיות, הקטנת dependencies בזמן אתחול, או שילוב היברידי שמריץ את הרכיב הרגיש ל-latency על תשתית "חמה" קבועה ומשאיר את השאר Serverless.
איך שומרים היסטוריית שיחה כשהפונקציה חסרת מצב?
במאגר חיצוני persistent (Redis לזמינות מהירה, בסיס נתונים לשמירה ארוכת טווח), שנטען בתחילת כל הפעלה ונשמר בסופה.
האם אפשר להריץ Multi-Agent Workflow שלם על Serverless?
כן, אבל צריך לפצל אותו לשלבים נפרדים שמתואמים דרך תור או מנוע orchestration חיצוני, ולא לנסות להריץ הכל בתוך הרצה בודדת שעלולה לחרוג ממגבלת הזמן.
סיכום
Serverless מתאים מאוד לחלק גדול מעומסי ה-AI, אבל דורש לתכנן מראש סביב Cold Starts, מגבלות זמן, וניהול מצב חיצוני. השילוב הנכון הוא לרוב היברידי - Serverless למשימות קצרות ועצמאיות, ותשתית ייעודית לזרימות מורכבות. אם אתם שוקלים איך לבנות את זה נכון, בתשתית פרודקשן של מדיה דיל יש לנו ניסיון בבחירת הארכיטקטורה הנכונה - נשמח לדבר בוואטסאפ.
תגיות: Serverless · AI Architecture · Cold Start · Functions · Stateless · Cloud Functions · AI Agents