Middleware

Middleware הוא המימוש הקונקרטי של ה-Harness

בפרק הראשון בנושא הזה קבענו ש-createAgent בונה בפועל את אותו "הארנס" שנלמד בנושא AI Agents — model, tools, ו-middleware. middleware הוא בדיוק החלק השלישי הזה: המנגנון שמאפשר להתערב בלולאה האגנטית עצמה, לא רק לספק לה כלים או מודל.

כל מה שראינו בפרק ה-Harness (הרשאות, sandboxing, תקציבים, לוגים) הוא דוגמה קונקרטית למה ש-middleware יכול לממש בקוד LangChain אמיתי.

ה-hook lifecycle: איפה middleware מתערב

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

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

Middleware מובנה מראש

LangChain מגיע עם קטגוריות שלמות של middleware מוכן לשימוש, בלי לכתוב אותו בעצמכם: guardrails לזיהוי מידע רגיש (PII) וסינון תוכן, fault tolerance עם retries ו-fallbacks כשקריאה למודל נכשלת, וsteering ל-human-in-the-loop — עצירה לאישור אנושי לפני פעולה מסוימת, בדיוק כמו שראינו ברמת העיקרון בפרק ה-Harness.

היתרון של middleware מובנה מראש הוא שאין צורך לממש מחדש לוגיקה גנרית כמו retry-with-backoff או זיהוי PII בכל פרויקט — מוסיפים אותו לרשימת ה-middleware ומקבלים את ההתנהגות מוכנה.

כתיבת middleware מותאם אישית

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

TypeScript
const loggingMiddleware = {
  beforeModel: async ({ messages }: { messages: Message[] }) => {
    console.log(`שולח ${messages.length} הודעות למודל`);
  },
  afterToolCall: async ({ toolName, result }: { toolName: string; result: unknown }) => {
    console.log(`כלי ${toolName} החזיר:`, result);
  },
};

const agent = createAgent({
  model: "anthropic:claude-sonnet-5",
  tools: [getWeather],
  middleware: [loggingMiddleware],
});

דוגמה מלאה: חסימת כלי מסוכן בלי אישור

בפרק ה-Harness בנושא AI Agents ראינו דוגמת JSON של agent עם הרשאות מוגבלות (code-review-worker עם scope שאוסר כתיבה ורשת). middleware הוא המקום שבו אכיפה כזו קורית בפועל בקוד: לפני שכלי רץ, ה-middleware יכול לבדוק את הפרמטרים שלו ולחסום את הקריאה אם היא חורגת מהמדיניות שהוגדרה — בלי לסמוך על כך שהמודל 'יבחר' לא לקרוא לכלי.

בדוגמה הבאה beforeToolCall בודק בקשת זיכוי גדולה מדי, וזורק שגיאה במקום לתת לכלי לרוץ — בדיוק אותו עקרון של least privilege ו-approval gates שכבר נלמד, רק הפעם אכוף ב-middleware אמיתי.

TypeScript
const approvalMiddleware = {
  beforeToolCall: async ({
    toolName,
    args,
  }: {
    toolName: string;
    args: Record<string, unknown>;
  }) => {
    if (toolName === "issue_refund" && Number(args.amount) > 1000) {
      throw new Error("זיכוי מעל 1000 ש\"ח דורש אישור אנושי לפני ביצוע");
    }
  },
};

const agent = createAgent({
  model: "anthropic:claude-sonnet-5",
  tools: [getWeather, issueRefundTool],
  middleware: [approvalMiddleware],
});