Multi-Hop Agent Chains — כשסוכן קורא לסוכן שקורא לסוכן
מאת צוות מדיה דיל · 12.08.2026 · Agent Infrastructure · 5 דק׳
כשסוכן A קורא לסוכן B שקורא לסוכן C, כל כשל באמצע השרשרת עלול להיעלם בשקט. איך בונים שרשראות רב-קפיצה שאפשר לדבג ולסמוך עליהן.
מערכת תמיכת לקוחות מבוססת סוכן ראשי שמקבל את פניית המשתמש, ולפי הצורך קורא לסוכן משנה שמתמחה בבירורי חיוב, שבתורו קורא לסוכן שלישי שמבצע בפועל את הזיכוי מול מערכת התשלומים. יום אחד לקוח התלונן שהוא "אושר לזיכוי" אבל הכסף מעולם לא הגיע. בבדיקה התברר ששרשרת שלוש הקפיצות עבדה כמצופה עד לקריאה האחרונה, שנכשלה בגלל timeout — אבל אף אחד מהסוכנים באמצע לא ידע שהקצה נכשל, כי כל סוכן ראה רק את התשובה שקיבל מהסוכן הבא, לא את מה שקרה בפועל בקצה השרשרת. זו הבעיה המרכזית של Multi-Hop Agent Chains: ככל שיש יותר קפיצות בין סוכנים, כך גדל המרחק בין המקום שבו כשל קורה בפועל למקום שבו מישהו — אנושי או אוטומטי — מבחין בו.
למה שרשראות ריבוי-קפיצה שונות מקריאת כלי בודדת
קריאת כלי רגילה (Tool Call) היא סינכרונית ומהירה יחסית: הסוכן קורא לפונקציה, מקבל תוצאה, וממשיך. שרשרת רב-קפיצה שונה במהותה, כי כל "קפיצה" היא בעצמה סוכן עצמאי עם ה-context, ההחלטות והכשלים הפוטנציאליים שלו. המשמעות: כשל לא מוגבל עוד לקריאת API בודדת שנכשלה — הוא יכול להיות כשל לוגי בסוכן אמצעי שהבין לא נכון את הבקשה, כשל בזיהוי מתי לעצור, או אפילו לולאה בין שני סוכנים שקוראים זה לזה חזרה ולא מבחינים שהם חוזרים על אותה שאלה. ברמת המורכבות הזו, הרעיונות של מערכות Multi-Agent קלאסיות עדיין תקפים, אבל צריך שכבה נוספת שמטפלת ספציפית בשרשור: מעקב אחר כל קפיצה, זיהוי איפה בדיוק היא נכשלה, ומניעת אובדן מידע בדרך.
Trace ID אחיד לכל השרשרת
הכלי הבסיסי ביותר, ולמרבה הצער הכי לעיתים קרובות נשכח, הוא trace_id יחיד שמלווה את הבקשה המקורית דרך כל קפיצה בשרשרת. כשסוכן A קורא לסוכן B, הוא מעביר את אותו trace_id הלאה; כשסוכן B קורא לסוכן C, אותו trace_id ממשיך איתו. כל לוג, כל שגיאה, וכל תוצאה נרשמים עם אותו מזהה, כך שכשמשהו משתבש אפשר לשלוף בשאילתה אחת את כל שרשרת האירועים מההתחלה ועד הסוף — כולל הקפיצה השלישית שנכשלה בשקט. בלי trace_id אחיד, דיבוג שרשרת רב-קפיצה הופך לבלש עבודה: מחפשים ידנית בלוגים נפרדים של כל סוכן ומנסים לשחזר את סדר האירועים לפי חותמות זמן, שיטה שאיטית ולעיתים בלתי אפשרית כשיש עומס ומקבילות.
{
"trace_id": "trc_9f2a...",
"hop": 2,
"caller": "billing-agent",
"callee": "payment-execution-agent",
"status": "timeout",
"elapsed_ms": 30000
}
מי אחראי על הידיעה ש"זה נכשל"
ההחלטה הארכיטקטונית החשובה ביותר בשרשראות רב-קפיצה היא: מי אחראי לוודא שקפיצה הצליחה בפועל, לא רק שהיא "החזירה תשובה". תשובה יכולה להיות "הצלחה מדומה" — סוכן שמחזיר "בוצע" למרות שבפועל נתקל בשגיאה ולא ידע איך לדווח עליה נכון. הפתרון הוא פרוטוקול תשובה מפורש בין סוכנים: כל תשובה בין קפיצות חייבת לכלול status מפורש (success / failed / partial), לא רק טקסט חופשי שהסוכן הקורא צריך לפרש. סוכן קורא שמקבל status=failed יודע לעצור ולדווח למעלה בשרשרת, במקום להמשיך כאילו הכול תקין. כשמעורבים תשלומים או פעולות בלתי הפיכות, חובה גם שהקפיצה האחרונה בשרשרת — זו שמבצעת בפועל — תדווח אישור מפורש שהתקבל מהמערכת החיצונית, לא הנחה אופטימית שהקריאה "כנראה עברה" כי לא התקבלה שגיאה מיידית.
נקודה נוספת שקל לפספס: retry ברמת קפיצה בודדת מסוכן במיוחד בשרשראות ארוכות, כי retry על קפיצה אחת עלול לגרום להפעלה כפולה של כל מה שקרה אחריה בשרשרת המקורית. אם סוכן B קרא לסוכן C, קיבל timeout, וניסה שוב — אבל הקריאה הראשונה בפועל הצליחה רק באיחור — סוכן C עלול לבצע את אותה פעולה פעמיים. הפתרון היחיד שעובד באמת הוא לוודא שכל פעולה בקצה השרשרת אידמפוטנטית, עם מזהה ייחודי שמזהה ניסיונות כפולים ומונע ביצוע חוזר.
עומק שרשרת מקסימלי ומניעת לולאות
שרשרת ללא הגבלת עומק היא סיכון תפעולי אמיתי: סוכן A קורא לסוכן B, שמחליט (בטעות לוגית, או כי הוא לא בטוח בתשובה) לקרוא בחזרה לסוכן דומה לסוכן A, וכך נוצרת לולאה שצורכת טוקנים ומשאבים בלי גבול. הגנה בסיסית היא הגבלת עומק מקסימלי (hop limit) שמוזרקת לכל בקשה — כל קפיצה מקטינה מונה, וכשהמונה מגיע לאפס השרשרת נעצרת בכפייה ומדווחת שגיאה ברורה במקום להמשיך לנצח. הגנה נוספת היא זיהוי מעגליות: אם trace_id מסוים כבר עבר דרך סוכן מסוים, קריאה חוזרת לאותו סוכן באותה שרשרת מעוררת חשד ונבדקת לפני שהיא מתבצעת.
- trace_id יחיד שמלווה כל קפיצה בשרשרת, לצורך דיבוג ותצפית
- פרוטוקול תשובה מפורש (status) בין סוכנים, לא טקסט חופשי לפרשנות
- אישור מפורש בקצה השרשרת לפני שקפיצות למעלה מדווחות הצלחה
- עומק שרשרת מקסימלי, ואכיפת idempotency בכל קפיצה שמבצעת פעולה
מתי בכלל כדאי לפצל לשרשרת ולא לסוכן אחד
שרשרת רב-קפיצה מוסיפה מורכבות תפעולית משמעותית, ולכן היא לא ברירת המחדל. הסיבה הטובה ביותר לפצל היא הפרדת אחריות אמיתית — סוכן שמתמחה בבירור חיוב לא צריך גם לדעת איך לבצע חיוב בפועל מול ה-Payment Gateway, בדיוק כמו שבקוד רגיל מפרידים בין שכבת לוגיקה עסקית לשכבת גישה לנתונים. סיבה טובה נוספת היא שימוש חוזר: אם סוכן ביצוע תשלומים משמש כמה תהליכים שונים בארגון, עדיף לבנות אותו פעם אחת כשירות עצמאי מאשר לשכפל את הלוגיקה בכל סוכן שצריך לבצע תשלום. אבל כשאין סיבה כזו — כשהמשימה פשוטה מספיק שסוכן אחד עם כמה כלים יכול לבצע אותה בעצמו — עדיף להימנע משרשור, כי כל קפיצה נוספת היא נקודת כשל נוספת, latency נוספת, ומורכבות דיבוג נוספת שצריך להצדיק.
שאלה מעשית נוספת שצצה כמעט בכל שרשרת רב-קפיצה, גם כשההחלטה לפצל כבר התקבלה: כמה מההיסטוריה של סוכן A צריך להעביר לסוכן B? העברת כל השיחה המקורית לכל קפיצה נשמעת בטוחה — "שיהיה לו כל ההקשר" — אבל בפועל מנפחת את עלות הטוקנים בכל קפיצה, ולפעמים אף מבלבלת את הסוכן הבא עם מידע שלא רלוונטי למשימה הממוקדת שלו. הגישה שעובדת טוב יותר היא העברת חבילת הקשר ממוקדת: רק מה שהסוכן הבא צריך כדי לבצע את חלקו — לא את כל השיחה, אלא תמצית מובנית של הבקשה, האילוצים הרלוונטיים, ותוצאות ביניים שכבר התקבלו. זו בדיוק אותה בעיה שמופיעה בהעברת משימה בין מופעי סוכן, שמפורטת בהרחבה במדריך נפרד על Agent Session Handoff — העקרונות דומים גם כשההעברה היא בין תפקידים שונים באותה שרשרת ולא בין מופעים של אותו סוכן.
תגיות: Multi-Hop Agents · Agent Chains · Trace ID · Multi-Agent Systems · Idempotency