The Harness — מי בפועל מריץ את הסוכן

ה-harness כמתווך בין המודל למציאות

בפרק 1 הגדרנו את העיקרון: המודל מציע, וה-harness מחליט. כשהמודל "מוחק קובץ", הוא רק מייצר טקסט שמבקש למחוק — הביצוע כולו בידי ה-harness.

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

תרשים המציג בועת דיבור (המודל, כחול) עם חץ אל צורת מגן (ה-harness) עם סימן ✓ במרכזו. מהמגן יוצא חץ כחול אחד כלפי מעלה אל סמל קובץ (פעולה מותרת שמתבצעת) וחץ כתום נוסף כלפי מטה אל סימן X בתוך עיגול (פעולה שנחסמת) — ממחיש שהמודל רק מציע פעולה בטקסט, וה-harness הוא שמחליט אם לבצע אותה בפועל.
המודל מציע פעולה כטקסט בלבד; ה-harness הוא שמחליט אם ואיך לבצע אותה בפועל מול העולם האמיתי

הרשאות ו-Approval Gates

הדרך הנפוצה להכניס שליטה אנושית היא approval gate: לפני פעולה רגישה (מחיקת קובץ, שליחת הודעה, הרצת פקודת shell, ביצוע תשלום) ה-harness עוצר ומבקש אישור מפורש מהמשתמש.

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

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

Sandboxing — הגבלת מרחב הפעולה

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

ההבדל מ-approval gate: sandboxing לא שואל אף אחד — הוא הופך פעולה לבלתי אפשרית מלכתחילה, גם אם המודל ינסה. שתי הגישות משלימות: sandboxing תוחם את הנזק המקסימלי, ו-approval gates מוסיפים שליטה אנושית על מה שכן מותר.

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

תקציבים ותצפית: Step Limits, עלות ולוגים

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

לצד זה, harness רציני שומר לוג מלא של כל פעולה שהמודל ביקש ושל כל החלטה שהתקבלה לגביה. זה לא רק כלי דיבוג — זו רשומת ביקורת (audit trail) שמאפשרת לבדוק בדיעבד מה בדיוק קרה, מי אישר מה, ולמה. בפרק 12 נראה איך אותם לוגים (traces) משמשים גם להערכת סוכנים.

תרשים המציג מד תקציב אופקי מלבני, מלא בחלקו הגדול בכחול, עם קו מקווקו כתום וחץ אזהרה המסמנים את קו הגבול העליון (limit) שעוד לא נחצה. מתחתיו תיבת יומן ביקורת (audit log) עם ארבע שורות רשומה, כל אחת עם נקודה בתחילתה — שלוש כחולות ואחת כתומה — המסמנת רשומה שסומנה לתשומת לב.
מד תקציב (מספר סיבובים/עלות) המתקרב לגבול, לצד לוג ביקורת שמתעד כל פעולה והחלטה

דוגמה מלאה: ה-harness עוצר פעולה הרסנית

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

קודם כול הנתיב: ה-harness ממיר אותו לנתיב מלא ומנורמל לפני הבדיקה. בלי זה, בקשה כמו src/../../etc "מתחילה ב-src" ועוברת בדיקה נאיבית, למרות שהיא מצביעה אל מחוץ לפרויקט. אם הנתיב נמצא מחוץ לתיקיות המותרות — הבקשה נחסמת.

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

TypeScript
import path from "node:path";

const WORKSPACE = "/home/user/project";
const ALLOWED_PATHS = [path.join(WORKSPACE, "src"), path.join(WORKSPACE, "tmp")];
const DESTRUCTIVE_ACTIONS = ["delete_file", "run_shell", "send_email"];

function isInside(target: string, dir: string): boolean {
  const relative = path.relative(dir, target);
  return !relative.startsWith("..") && !path.isAbsolute(relative);
}

function shouldExecute(action: ToolCall): "auto" | "ask" | "deny" {
  if (action.path !== undefined) {
    // מנרמלים קודם: "src/../../etc" הופך ל-"/home/user/etc"
    const resolved = path.resolve(WORKSPACE, action.path);
    if (!ALLOWED_PATHS.some((dir) => isInside(resolved, dir))) {
      return "deny"; // מחוץ לתיקיות המותרות - נחסם לגמרי
    }
  }
  if (DESTRUCTIVE_ACTIONS.includes(action.name)) {
    return "ask"; // דורש אישור אנושי מפורש
  }
  return "auto"; // פעולה בטוחה - מתבצעת מיד
}

שאלות נפוצות

איפה בפועל רץ ה-harness?

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

האם אפשר לתת למודל עצמו להחליט אילו פעולות דורשות אישור?

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

מה ההבדל בין sandbox לבין הרצה על המחשב שלי עם משתמש מוגבל?

sandbox מבודד את הסוכן מכל מה שלא ניתן לו במפורש: מערכת קבצים נפרדת, רשת חסומה או מסוננת, ובלי גישה לסודות של הסביבה שלכם. הרצה ישירה על המחשב, גם עם משתמש מוגבל, עדיין חושפת קבצים, משתני סביבה וגישה לרשת שקל לשכוח מהם. לכן להרצת קוד שהמודל כתב, sandbox אמיתי (container או VM) הוא ברירת המחדל הבטוחה.