עבור לתוכן הראשי
בנייה

איך בונים Agent שבאמת עובד

בניתם skill או שניים, והם עובדים יפה. עכשיו אתם רוצים משהו שרץ לבד, בלי שתשבו לידו. זה קפיצת מדרגה אחרת לגמרי - והרוב נופלים בה על אותם חמישה דברים.

ההבדל בין skill לאגנט, במשפט אחד

Skill זה משהו שאתם מפעילים. Agent זה משהו שמחליט.

זה כל ההבדל, והוא ענק. כשכתבתם skill, אתם קבעתם את הצעדים מראש: קבל קלט, עשה א', עשה ב', החזר פלט. המודל ממלא תבנית. באגנט אין תבנית - יש מטרה, יש כלים, ויש לולאה. המודל בוחר בעצמו מה הצעד הבא, על סמך מה שהוא ראה בצעד הקודם. אתם לא כותבים את התסריט. אתם כותבים את התנאים שבהם התסריט נכתב.

ובגלל שזה נשמע מגניב, כולם רצים לבנות אגנט גם כשלא צריך. הכלל שלי פשוט: אם אתם יכולים לרשום את הצעדים על דף לפני ההרצה - זה skill. אם הצעד השלישי תלוי במה שיקרה בצעד השני - רק אז זה אגנט. בדקו את עצמכם:

INTERACTIVESkill או Agent? בחרו משימה

הלולאה: מה באמת קורה בכל תור

כל אגנט, לא משנה כמה מתוחכם, רץ על אותה לולאה בת ארבעה שלבים: קולט את ההקשר הנוכחי, מחליט מה לעשות, פועל דרך כלי, וצופה בתוצאה. התוצאה נכנסת להקשר, והלולאה מתחילה מחדש. זהו. אין קסם מעבר לזה.

הנקודה החשובה: המודל מקבל החלטה פעם אחת בכל תור - בשלב "מחליט". כל השאר זה צנרת שאתם כתבתם. איכות האגנט נקבעת לפי מה שהמודל רואה ברגע ההחלטה הזה: אילו כלים מוצעים לו, איך הם מתוארים, ומה נשאר בהקשר מהתורות הקודמות.

עברו על ההרצה למטה תור-תור. ואז עברו למצב "לראות איך זה נשבר" - אותה משימה בדיוק, עם כלי אחד שמתואר גרוע. שימו לב לתור המדויק שבו הכל מתחיל להידרדר, ולמה שקורה למד ההקשר:

INTERACTIVEלולאת האגנט, תור אחרי תור
הקשר0.0K tokens
המשימה: "תקן את הטסט שנשבר ב-CI"
לחצו "תור הבא" כדי לראות מה קורה בכל סיבוב.

מה שרואים בהרצה השבורה זה לא "המודל טיפש". זה שההחלטה הראשונה הגרועה זיהמה את ההקשר, וכל החלטה אחריה התבססה על הקשר מזוהם. באגנטים, שגיאות לא מתחלפות - הן מצטברות.

כלים: מה לתת ומה לא

האינסטינקט אומר לתת לאגנט הכל: חיפוש, קבצים, טרמינל, דפדפן, עשרים כלים - שיסתדר. בפועל, כל כלי נוסף הוא עוד הזדמנות לבחירה שגויה. ראיתי אגנט עם 4 כלים חדים מנצח שוב ושוב אגנט עם 15 כלים כלליים, על אותן משימות בדיוק.

והחלק שכולם מפספסים: התיאור של הכלי הוא הממשק האמיתי. לא הקוד שלו. המודל לא רואה את המימוש - הוא רואה שם, תיאור, ופרמטרים. תיאור מעורפל מייצר בחירות מעורפלות. נסו את שלוש המשימות עם שני התיאורים:

INTERACTIVEאותו כלי, שני תיאורים
// תיאור מעורפל
search(query) // "searches stuff"
search("VAT calculation")
המודל לא יודע אם זה חיפוש רשת או קוד. קיבל מאמרי ויקיפדיה על מע"מ.
// תיאור חד
code_search(query) // "Searches ONLY this repo's source. // Returns up to 20 matching lines // with file paths. Not a web search."
code_search("vat")
ברור שזה חיפוש קוד. קיבל את pricing.ts:42 בתור הראשון.

ככה נראה תיאור שעובד - הוא אומר מה הכלי עושה, מה הוא לא עושה, ומה חוזר ממנו:

{
  "name": "code_search",
  "description": "Searches ONLY this repo's source code.
    Returns up to 20 matching lines with file paths.
    NOT a web search - for docs use fetch_docs.",
  "input": { "query": "string, a literal or regex pattern" }
}

שלושת השורות של "NOT a web search" שוות יותר מכל תיקון prompt שתעשו אחר כך. תכתבו לכלי תיאור כמו שהייתם כותבים לעובד חדש ביום הראשון: קצר, חד, עם הגבולות.

זיכרון והקשר: מה שורד בין תורות

האגנט לא "זוכר" - יש לו context window, וכל מה שנכנס אליו נשאר שם עד שנגמר המקום. כל תוצאת כלי, כל שגיאה, כל ניסיון כושל - הכל מצטבר. אחרי 20 תורות, ההקשר של אגנט טיפוסי הוא 80% פסולת: פלטים ישנים שכבר לא רלוונטיים, שדוחקים החוצה את מה שכן חשוב.

זה מה שהורג אגנטים ארוכי טווח, ולזה קוראים context rot: המשימה המקורית נכתבה בתור #1, ובתור #30 היא כבר לא בחלון - או שהיא שם אבל קבורה מתחת ל-40K טוקנים של לוגים. האגנט ממשיך לרוץ, רק בלי לזכור בשביל מה.

שלושה כללים שעובדים לי:

  • קבצים, לא הקשר. מה שצריך לשרוד לאורך זמן נכתב לקובץ (סיכום התקדמות, החלטות, מה נוסה ונכשל) ונקרא מחדש בתחילת כל שלב. ההקשר הוא זיכרון עבודה, לא ארכיון.
  • קיצוץ תוצאות. כלי שמחזיר 3,000 שורות לוג צריך להחזיר 30 שורות רלוונטיות. הקיצוץ קורה בכלי, לא במודל.
  • המשימה חוזרת על עצמה. תזכורת קצרה של המטרה ותנאי העצירה מוזרקת כל כמה תורות, כדי שהיא לעולם לא תיפול מהחלון.

מעקות: מה שאגנט לעולם לא עושה לבד

אגנט בלי מעקות הוא לא "אוטונומי", הוא הפקרות עם API key. לפני שאתם משחררים משהו לרוץ בלי השגחה, ארבעה דברים חייבים להיות במקום: תקרת תורות, תקציב טוקנים, תנאי עצירה מוגדר, ו-checkpoint אנושי לכל פעולה בלתי הפיכה. כבו אחד מהם וראו מה זה עולה:

INTERACTIVEמה קורה כשמכבים מעקה?
הרצה נקייה
האגנט תיקן את הבאג ב-9 תורות, ביקש אישור פעם אחת (לפני מחיקת branch ישן), ועצר כשהטסטים הוריקו.
9תורות
$0.42עלות
לאנזק בלתי הפיך?

שימו לב לאסימטריה: תקרת תורות ותקציב חוסכים כסף וזמן. אבל האישור האנושי הוא היחיד שמונע נזק בלתי הפיך. מחיקה, force push, שליחת מייל ללקוח, deploy - כל אלה עוצרים ושואלים. תמיד. גם כשהאגנט "בטוח". במיוחד כשהאגנט בטוח.

תנאי עצירה טוב הוא חיצוני ומדיד, לא תחושה של המודל:

// stop when ALL of these hold - not when the model "feels done"
stop_when:
  tests_pass: true          // measured, not self-reported
  turns_used: "<= 15"
  tokens_used: "<= 50_000"
  destructive_actions: 0    // anything else requires approval

Evals ו-Traces: לשפוט מסלול, לא תשובה

ב-skill בודקים פלט: קלט נכנס, פלט יוצא, נכון או לא. באגנט זה לא מספיק - אגנט יכול להגיע לתשובה נכונה במסלול מזעזע (30 תורות, שני קבצים שנמחקו בטעות ושוחזרו), או להיכשל בנימוס אחרי מסלול מושלם. מה שצריך לשפוט זה את הtrajectory: רצף ההחלטות, לא רק הסוף.

ובגלל שאגנטים לא דטרמיניסטיים, הרצה אחת לא אומרת כלום. אותה משימה רצה אצלי 10 פעמים לפני כל שינוי: אם 8 מצליחות ו-2 נתקעות בלולאה, יש לי בעיית יציבות, לא בעיית יכולת - והתיקון שונה לגמרי.

ההרגל הזה עובד גם מחוץ לאגנטים. כשרציתי לדעת איזה backend מהיר יותר בכלי התמלול שלי, נתתי למספרים להחליט במקום לנחש. התוצאה הייתה פי 5.81, ולא הייתי מנחש את זה נכון.

הכלי הכי חשוב בארגז הוא קריאת trace. כשהרצה נכשלת, התשובה נמצאת תמיד בתור מסוים - התור שבו החלטה סבירה-לכאורה שלחה את הכל למקום הלא נכון. פתחו את ה-trace הזה תור-תור ונסו למצוא אותו לפני שתלחצו על הכפתור:

INTERACTIVEקריאת trace: "עדכן את התלויות ופתח PR"

רוב האנשים מנחשים שהכשל הוא איפה שהטסטים נשברו. הוא אף פעם לא שם. הוא תמיד כמה תורות קודם, בהחלטה שנראתה הגיונית באותו רגע. לקרוא traces זה skill - ומי שמפתח אותו מתקן אגנטים פי עשרה יותר מהר ממי שמסתכל רק על התשובה הסופית.

זהו. לולאה פשוטה, מעט כלים חדים, הקשר שמנוהל, מעקות שלא מתפשרים עליהם, ושיפוט לפי מסלול. אגנט שבנוי ככה לא מושלם - אבל הוא עובד, וכשהוא נשבר, אתם יודעים בדיוק איפה.