Workflows מול Agents
שתי דרכים לבנות מערכת עם LLM
לא כל מערכת שמשתמשת ב-LLMרשת נוירונים ענקית, עם מיליארדי פרמטרים, שאומנה לחזות מהו הטוקן הבא ברצף טקסט. מתוך LLM, יסודות ה-AI. צריכה להיות סוכןLLM שמופעל בלולאה, עם מטרה וסט כלים, ובכל סיבוב מחליט אם להפעיל כלי נוסף או לסיים ולהחזיר תשובה. מתוך AI Agents, Agents והלולאה האגנטית.. יש שתי גישות בסיסיות, וההבדל ביניהן הוא שאלה אחת: מי קובע את המסלול?
ב-Workflow המסלול כתוב בקוד. המפתח קובע מראש את סדר השלבים, והמודל נקרא בנקודות קבועות כדי לבצע משימה מוגדרת בכל אחת מהן — לסווג, לסכם, לנסח. ב-Agent, כמו בפרק 2, המודל קובע את המסלול תוך כדי ריצה: הוא מחליט אילו כלים להפעיל, באיזה סדר, ומתי לסיים.
דוגמה: מערכת שעונה למיילים של לקוחות. כ-workflow: קריאה אחת למודל מסווגת את המייל, הקוד מנתב לפי הסיווג, וקריאה שנייה מנסחת תשובה לפי תבנית. כסוכן: המודל מקבל את המייל וכלים (חיפוש הזמנה, בדיקת מלאי, שליחת תשובה) ומחליט בעצמו מה לעשות.
הטרייד-אוף: גמישות מול צפיות
Workflow צפוי: אותו קלט עובר תמיד את אותם שלבים, כך שקל לבדוק אותו, לדבג אותו ולהעריך מראש כמה הוא יעלה וכמה זמן ייקח. המחיר הוא גמישות — הוא מטפל רק במקרים שהמפתח חשב עליהם מראש.
סוכןLLM שמופעל בלולאה, עם מטרה וסט כלים, ובכל סיבוב מחליט אם להפעיל כלי נוסף או לסיים ולהחזיר תשובה. מתוך AI Agents, Agents והלולאה האגנטית. גמיש: הוא מתמודד עם משימות פתוחות שבהן אי אפשר לדעת מראש כמה צעדים יידרשו ואילו — למשל תיקון באג בקוד לא מוכר. המחיר: יותר קריאות למודל, עלות וזמן ריצה שקשה לחזות, ויותר מקומות שבהם הוא יכול לטעות.
כלל אצבע: להתחיל מהפתרון הפשוט ביותר שעובד. קודם קריאה אחת למודל עם פרומפט טוב; אם זה לא מספיק — workflow; ורק כשהמשימה באמת פתוחה — סוכן. רוב המערכות בפרודקשן הן workflows, או workflows שאחד השלבים בהם הוא סוכן.
דפוס 1: Prompt Chaining
הדפוס הפשוט ביותר: מפרקים משימה לשלבים קבועים, והפלט של כל שלב הוא הקלט של הבא. כל קריאה למודל פשוטה וממוקדת יותר מקריאה אחת שמנסה לעשות הכול, ולכן גם מדויקת יותר.
היתרון החשוב: בין השלבים אפשר לשים "שער" — בדיקה בקוד שמוודאת שתוצר הביניים תקין לפני שממשיכים. בדוגמה למטה, generate היא קריאה בודדת למודל שמחזירה טקסט.
async function writeProductPage(specs: string): Promise<string> {
const outline = await generate(`כתוב ראשי פרקים לדף מוצר לפי המפרט:\n${specs}`);
// שער בקוד: בודקים את תוצר הביניים לפני שממשיכים
if (!outline.includes("מחיר")) {
throw new Error("ראשי הפרקים חסרים סעיף מחיר");
}
const draft = await generate(`כתוב דף מוצר לפי ראשי הפרקים:\n${outline}`);
return generate(`תרגם לאנגלית ושמור על הטון:\n${draft}`);
}דפוס 2: Routing ו-Parallelization
Routing: קריאה ראשונה למודל מסווגת את הקלט, והקוד מנתב אותו למסלול המתאים. כך כל מסלול מקבל פרומפט וכלים מותאמים, ואפשר לשלוח מקרים פשוטים למודל קטן וזול ולשמור את המודל החזק למקרים הקשים.
Parallelization: מריצים כמה קריאות למודל במקביל ומאחדים את התוצאות בקוד. יש שתי גרסאות: פיצול (sectioning) — כל קריאה מטפלת בחלק אחר של המשימה; והצבעה (voting) — אותה משימה רצה כמה פעמים, ומשווים את התשובות כדי לקבל תוצאה אמינה יותר.
בדוגמה למטה שימו לב למקרה של פנייה טכנית: שלב אחד בתוך ה-workflow הוא סוכןLLM שמופעל בלולאה, עם מטרה וסט כלים, ובכל סיבוב מחליט אם להפעיל כלי נוסף או לסיים ולהחזיר תשובה. מתוך AI Agents, Agents והלולאה האגנטית. מלא. ואם המודל מחזיר קטגוריה לא צפויה, היא נופלת ל-default ומגיעה לנציג אנושי.
async function handleTicket(ticket: string): Promise<string> {
const category = (
await generate(
`סווג את הפנייה: billing, technical או other. החזר מילה אחת בלבד.\n${ticket}`,
{ model: "small-fast-model" } // סיווג לא צריך את המודל החזק
)
).trim();
switch (category) {
case "billing":
return handleBilling(ticket); // workflow קבוע מול מערכת החיוב
case "technical":
return runAgentLoop(ticket, TECH_SUPPORT_TOOLS); // כאן באמת צריך סוכן
default:
return escalateToHuman(ticket);
}
}דפוס 3: Evaluator-Optimizer ו-Orchestrator-Workers
Evaluator-Optimizer: קריאה אחת למודל מייצרת תוצר, וקריאה שנייה בודקת אותו מול קריטריונים מפורשים ומחזירה הערות. התוצר משתפר בסבב נוסף, עד שהבודק מאשר או שמגיעים למספר סבבים מקסימלי. זה עובד טוב כשיש קריטריונים ברורים להצלחה — למשל תרגום שצריך לשמור על מונחים מקצועיים.
Orchestrator-Workers: מודל "מתאם" מפרק את המשימה לתתי-משימות ומחלק אותן לעובדים, ואז מאחד את התוצאות. ההבדל מ-parallelization: כאן החלוקה לא קבועה בקוד — המתאם מחליט עליה לפי הקלט. זה כבר קרוב מאוד לסוכןLLM שמופעל בלולאה, עם מטרה וסט כלים, ובכל סיבוב מחליט אם להפעיל כלי נוסף או לסיים ולהחזיר תשובה. מתוך AI Agents, Agents והלולאה האגנטית., ונרחיב עליו בפרק 4 (Subagentsסוכן שהסוכן הראשי מפעיל לחלק מוגדר מהמשימה, עם קונטקסט נפרד משלו; מבחינת ההורה זו עוד קריאת כלי. מתוך AI Agents, Subagents — האצלת משימות.) ובפרק 11 (תזמור רב-סוכנים).
איך בוחרים
השאלה הראשונה: האם אפשר לכתוב את השלבים מראש? אם כן — workflow. אם מספר השלבים וסוגם תלויים במה שמתגלה תוך כדי עבודה — סוכןLLM שמופעל בלולאה, עם מטרה וסט כלים, ובכל סיבוב מחליט אם להפעיל כלי נוסף או לסיים ולהחזיר תשובה. מתוך AI Agents, Agents והלולאה האגנטית..
השאלה השנייה: כמה עולה טעות? ככל שטעות יקרה יותר, כדאי יותר מסלול צפוי עם בדיקות בקוד ואישור אנושי בנקודות הרגישות.
ובפועל זו לא בחירה של הכול או כלום: workflow יכול להפעיל סוכן באחד השלבים (כמו בדוגמת ה-routing), וסוכן יכול לקבל workflow שלם ככלי. מכאן והלאה הנושא עוסק בסוכנים — אבל כדאי לזכור שהם הכלי הנכון רק כשהמשימה באמת דורשת אותם.
שאלות נפוצות
איך בודקים workflow שיש בו קריאות למודל, כשהתשובות לא דטרמיניסטיות?
בודקים כל שלב בנפרד. שערים בקוד בודקים את המבנה — JSON תקין, קטגוריה מתוך רשימה מותרת — ועל התוכן החופשי מריצים סט קבוע של דוגמאות ומודדים אחוז הצלחה, כמו ב-evals (פרק 12). היתרון של workflow הוא שכל שלב קטן וממוקד, ולכן קל לבודד איפה בדיוק משהו נשבר.
האם Routing לא מוסיף עלות של עוד קריאה למודל?
מוסיף, אבל קריאת סיווג קצרה במודל קטן זולה בדרך כלל ביחס למה שהיא חוסכת: רוב הפניות עוברות למסלול פשוט וזול, והמודל החזק נשמר למקרים הקשים. כשאפשר לסווג בלי מודל — לפי שדה בטופס או מילת מפתח ברורה — עדיף לנתב בקוד רגיל.
מה עושים כשב-workflow יש יותר ויותר מקרים שלא צפינו מראש?
זה סימן לשקול להפוך לסוכן את השלב הבעייתי, לא בהכרח את כל המערכת. בדרך כלל רואים את זה ב-default של ה-routing, כשיותר ויותר פניות נופלות לנציג אנושי. כדאי לבדוק אילו מהן חוזרות על עצמן ולהוסיף להן מסלול, ורק את מה שנשאר באמת פתוח להעביר לסוכן.