בפוסט שפורסם בבלוג של n8n מוסבר כי state (מצב) הוא המידע שסוכן AI נושא עמו בין משימות שונות, החל מהיסטוריית שיחה ועד לזיכרון לטווח ארוך ולפרופילי משתמשים. ההחלטה הארכיטקטונית בין מערכת בעלת מצב (stateful) לבין מערכת חסרת מצב (stateless) מעצבת את האופן שבו תהליכי עבודה של סוכנים (agentic workflows) מנהלים התרחבות בעומס (scale) ומתאוששים מכשלים ותקלות. לפי n8n, מדובר בהחלטת תכנון מרכזית הנושאת השלכות על רמת האמינות ועל הביצועים של המערכת כולה. ההבדל היסודי בין שתי הגישות מסתכם בשאלה מה קורה למידע בין אינטראקציה אחת לאחרת: האם המערכת שומרת את מה שהתרחש בפניות קודמות, או שמא היא מתחילה כל בקשה ועיבוד מחדש כדף חלק לחלוטין.
מושגי יסוד: State, Session, Context ו-Scratchpad
לפי n8n, טרם השוואת יישומים בעלי מצב מול יישומים חסרי מצב, מועיל להגדיר שלושה מושגים קשורים:
- State (מצב): מידע שממשיך להתקיים מעבר לאינטראקציה בודדת, כדוגמת עגלת קניות, סטטוס אימות (authentication status) או היסטוריית שיחה.
- Session (הפעלה / סשן): סדרה של אינטראקציות קשורות המשויכות לאותו משתמש או לאותו תהליך. ה-session מעניק למערכת גבול להחלטה אילו אינטראקציות שייכות יחד.
- Context (הקשר): המידע שבו המערכת המבוססת על מודל שפה גדול (LLM) משתמשת כדי להבין את הבקשה הנוכחית ולהגיב עליה. מידע זה יכול להגיע מתוך הקלט הנוכחי, מאינטראקציות קודמות, או מנתונים שמורים במערכת.
בנוסף, בפוסט מצוין כי יישומי LLM מודרניים כוללים גם scratchpad (לוח טיוטה). זהו שטח אחסון זמני שבו סוכן ה-AI שומר תוצאות ביניים לפני שהוא משיב למשתמש. ה-scratchpad אינו חלק ממערכת בעלת מצב, ותפקידו העיקרי הוא לשמור מידע בזמן שהסוכן שולח שאילתות מרובות אל מודל השפה במהלך טיפול בבקשת משתמש בודדת.
יישומים בעלי מצב מול יישומים חסרי מצב וההבדלים המעשיים
יישום בעל מצב (stateful) שומר מידע מאינטראקציות קודמות ומשתמש במידע זה כדי לטפל באינטראקציות עתידיות. מידע זה עשוי לכלול היסטוריית שיחה, פרטי אימות, תוכן עגלת קניות, או שלב התקדמות בתוך תהליך רב-שלבי. היתרון שמציגה גישה בעלת מצב הוא המשכיות (continuity), שכן היישום יכול להמשיך מהנקודה שבה הסתיימה האינטראקציה הקודמת. עם זאת, הפשרה (trade-off) היא הצורך במקום לאחסון ולניהול המצב, תוך הבטחה שהמידע יהיה זמין ברגע שתגיע הבקשה הבאה.
לעומת זאת, יישום חסר מצב (stateless) מתייחס לכל בקשה באופן עצמאי. משמעות הדבר היא שכל מה שנדרש כדי לעבד את הבקשה חייב להגיע בצמוד אליה או להישלף מתוך מערכת אחרת. ביישום כזה אין הסתמכות על מידע שנשמר מתוך הבקשה הקודמת. ביישומים חסרי מצב קל יותר לפזר בקשות בין מופעים שונים (instances), מאחר שכל מופע מתאים יכול לטפל בבקשה מבלי שיידרש לשחזר מצב ממקום אחר. מאפיין זה יכול להפוך את היישום לבעל יכולת הרחבה (scalable) גבוהה יותר ולעמיד יותר בפני תקלות (fault-tolerant). כאשר המשכיות בכל זאת נדרשת, יש צורך להכניס מצב במקום כלשהו במערכת. מסיבה זו, ארכיטקטורות רבות משתמשות בשכבת עיבוד בקשות חסרת מצב, בעוד שנתונים מתמידים נשמרים במטמון (cache) או במערכת משותפת אחרת.
בפוסט של n8n מפורטים הבדלים מעשיים בין שתי התצורות בארבעה ממדים עיקריים:
- שמירת מצב (State retention): מערכת stateful שומרת מידע לאורך בקשות או sessions, בעוד מערכת stateless מעבדת כל בקשה באופן עצמאי.
- יכולת הרחבה (Scalability): במערכת stateful המצב חייב להישאר נגיש כשתעבורת הנתונים נעה בין מופעים; במערכת stateless ניתן לפזר בקשות באופן חופשי יותר בין המופעים הזמינים.
- עמידות לתקלות (Fault tolerance): במערכת stateful קריסת שרת עלולה לשבש את הגישה למצב, אלא אם הוא שוכפל או נשמר במקום אחר; במערכת stateless שרת אחר יכול בדרך כלל לעבד את הבקשה הבאה מבלי לשחזר מצב סשן מקומי.
- מורכבות ומשאבים (Complexity and resources): מערכת stateful דורשת תשתית לאחסון, סנכרון ושחזור של מצב; מערכת stateless מאפשרת מופעי יישום פשוטים יותר, אם כי נתונים מתמידים עשויים לדרוש אחסון מצב חיצוני.
בפוסט מודגש כי אין חובה להפוך מערכת שלמה לבעלת מצב או לחסרת מצב. ארכיטקטורות רבות שומרות על שכבת המחשוב (compute) כחסרת מצב לצורך התרחבות קלה יותר, בעוד שהמצב שחייב להישמר מועבר למסד נתונים, למטמון או למאגר משותף אחר.
מודלי שפה, סוכני AI ושימוש ב-APIs
לפי n8n, מודלי שפה גדולים (LLMs) אינם שומרים שיחות באופן אוטומטי מבקשת היסק (inference) אחת לבאה אחריה. אם יישום מעוניין שהמודל ישתמש בהודעות קודמות, יש להזין אותן בתוך הקלט של המודל או לשלוף אותן ממקום אחר במערכת. סוכני AI יכולים להתנהג באופן בעל מצב על ידי מתן גישה למודל למידע מאינטראקציות קודמות. כך פועל זיכרון של סוכן: הסוכן שומר ושולף מצב מחוץ למודל, ולאחר מכן מוסיף הקשר רלוונטי לבקשות עתידיות.
האופן שבו מצב זה מאוחסן תלוי במשך הזמן שבו הוא צריך להישמר ובגורמים הזקוקים לגישה אליו: חוצץ בזיכרון המקומי (in-memory buffer) יכול להחזיק הודעות אחרונות בתוך סשן, בעוד מאגר מתמיד (persistent store) יכול לשמר אותן מעבר לתהליך בודד או להפעלה מחדש (restart). במערכות מבוזרות, מאגר משותף יכול להנגיש את המצב בנקודות מרובות.
באשר לשימוש ב-APIs:
- ממשקי API חסרי מצב (Stateless APIs): מתאימים לצורכי קנה מידה ופשטות. דוגמה לכך היא REST APIs, שבהם כל בקשה מכילה את המידע הנחוץ לצורך אימות ועיבוד. בקשות חסרות מצב ניתנות לחלוקה קלה בין מופעים מרובים, דבר המסייע במיוחד כאשר יש צורך להגדיל את קיבולת ה-API מבלי להאט את הביצועים ומבלי לקרוס.
- ממשקי API בעלי מצב (Stateful APIs): מיועדים למקרים שבהם ההקשר חייב להישמר לאורך זמן. התנהגות בעלת מצב מתאימה לשיחות, לתהליכים מרובי שלבים ולאינטראקציות שבהן השלב הבא תלוי במה שהתרחש קודם לכן. ארכיטקטורה זו שימושית במיוחד עבור ממשקי API מבוססי עוגיות סשן לאימות (session-cookie authentication), ממשקי FTP APIs, וממשקי API בזמן אמת לפעילויות כגון צ'אט או משחקים.
ניהול מצב סוכנים ב-n8n: צומתי זיכרון ומאגרי מצב
בפוסט מוסבר כי n8n היא פלטפורמת אוטומציה מותאמת ל-AI ברישיון מקור זמין (source-available, AI-native), שבה צוותי הנדסה יכולים לבנות סוכני AI ותהליכי עבודה של סוכנים. ב-n8n ניתן לבחור היכן יישמר המצב בהתאם למה שצריך להישמר: צומת AI Agent יכול להשתמש בצומתי זיכרון (Memory nodes) עבור הקשר שיחתי, בעוד שמאגרי מצב (state stores) מחזיקים נתונים שצריכים להמשיך ולהתקיים מעבר לסשן של הסוכן. גישה זו מאפשרת להוסיף מצב במקומות שבהם הוא מועיל, מבלי להפוך את כל תהליך העבודה לבעל מצב.
כברירת מחדל, תהליכי עבודה ב-n8n הם חסרי מצב (stateless by default): הרצות של תהליכי עבודה הן עצמאיות, והרצה אחת אינה זוכרת באופן אוטומטי נתונים מהרצה קודמת. עובדה זו שומרת על שכבת ההרצה פשוטה יותר לצורכי התרחבות בעומס והתאוששות מתקלות. כאשר תהליך עבודה זקוק להמשכיות, מוסיפים במפורש את צורת המצב המתאימה. בנוסף, היסטוריית ההרצות (execution history) מספקת ראות לנתונים שעברו בכל ריצה, מה שהופך התנהגות בעלת מצב לקלה יותר לבדיקה ולניפוי שגיאות (debug).
לצורך ניהול מצב לטווח קצר ברמת הסשן, n8n מציעה מספר צומתי זיכרון:
- צומת Simple Memory: מספק חוצץ בזיכרון המקומי (in-memory buffer) עבור היסטוריית השיחה האחרונה, אך אינו תואם למצב תור (queue mode).
- צומת Postgres Chat Memory: משתמש במאגר מתמיד ומפריד שיחות לפי מזהה סשן (session ID), כאשר הזיכרון נדרש להישמר מעבר לתהליך הפעיל.
- צומת Redis Chat Memory: מספק אפשרות למטמון מבוזר מהיר שיכול לשתף את מצב הסשן בין עובדים (workers).
- עבור הרצה מבוזרת במצב תור (queue mode), n8n ממליצה להשתמש באפשרות זיכרון מתמידה כדי שמצב הסשן יישאר זמין לעובדים השונים.
- צומת Chat Memory Manager: כאשר נדרשת שליטה רבה יותר בהיסטוריית השיחה, צומת זה מאפשר לתהליכי עבודה לטעון, להכניס ולנקות הודעות באופן מפורש.
בנוסף, n8n מציינת טיפ לגבי מנגנון המטמון של מודלי שפה: לרוב ה-LLMs המודרניים יש מנגנון מטמון (caching) שמפחית עלויות באופן משמעותי. שימוש בצומת זיכרון עם חלון הזזה (sliding window, למשל 20 ההודעות האחרונות) מבטל את תוקף המטמון (invalidates the cache) במהלך שיחות ארוכות. במצב כזה, n8n ממליצה להגדיל את גודל חלון ההזזה או ליישם טכניקה מתקדמת יותר, כגון סיכום של X ההודעות האחרונות במקום שימוש בחלון הזזה נאיבי.
אחסון עמיד ומשותף והמלצה לבנייה הדרגתית
חלק מהמצב נדרש להאריך ימים מעבר לשיחה בודדת או להישאר זמין לאורך הרצות שונות של תהליכי עבודה. לפי n8n, טבלאות נתונים של n8n (n8n data tables) מספקות אחסון מובנה ומתמיד שתהליכי עבודה יכולים לקרוא ממנו ולכתוב אליו לאורך הרצות מרובות. בהתאם למקרה השימוש, ניתן להשתמש גם בנתונים סטטיים של תהליך העבודה (workflow static data) או במאגר חיצוני מסוג Postgres או Redis.
שימוש בצומתי זיכרון לצד מאגרי מצב יוצר שתי שכבות מצב נפרדות: צומתי זיכרון של צ'אט שומרים על ההקשר השיחתי עבור הסוכן, בעוד שמאגרי מצב שומרים על נתוני תהליך העבודה והיישום לאורך הרצות בתוך טבלת נתונים או מסד נתוני SQL.
לסיכום, n8n מציגה גישה מעשית: להתחיל בבנייה חסרת מצב, ולהוסיף מצב רק היכן שהוא נדרש. הבחירה בין stateful ל-stateless אינה חייבת להיות החלטה החלה על המערכת כולה. ההמלצה היא להתחיל בהרצה עצמאית וחסרת מצב ככל שניתן, ולאחר מכן להכניס מצב בכל נקודה שבה תהליך העבודה דורש המשכיות — בין אם מדובר בזיכרון סשן לשיחה פעילה, זיכרון מתמיד כאשר ההקשר חייב לשרוד הפעלות מחדש, או מאגר מצב משותף כאשר נתונים צריכים לעבור בין תהליכי עבודה והרצות שונות. בחירת השכבה המתאימה שומרת על ניהול המצב כמכוון ומתוכנן, במקום לאפשר לו להפוך למגבלה ארכיטקטונית.