Tools

כלי (Tool) כיחידת היסוד — תזכורת קצרה

בפרק על יצירת ה-agent הראשון בנינו כלי בודד, getWeather, עם tool ו-schema של zod. עכשיו נעמיק: מה הופך תיאור כלי לטוב, איך כלי מקבל מידע שהמודל עצמו לא שולח, ואיך מרכיבים כמה כלים יחד ב-agent אחד.

מה הופך תיאור כלי לטוב

המודל לא רואה את קוד הכלי — הוא רואה רק את name, description וה-schema של הפרמטרים, ומחליט על סמך זה בלבד אם ומתי להפעיל את הכלי. תיאור עמום ("מחזיר מידע") משאיר למודל לנחש; תיאור טוב אומר במפורש מה הכלי עושה, מתי להשתמש בו, ומה כל פרמטר אמור להכיל.

אותו עיקרון חל על השדות בתוך ה-schema עצמו: תיאור (description) לכל פרמטר, לא רק שם וטיפוס, עוזר למודל למלא אותו נכון — למשל לציין שדה city מצפה לשם עיר ולא לקוד מדינה.

TypeScript
// תיאור גרוע — עמום מדי, המודל לא יודע מתי להשתמש בו
tool(getData, {
  name: "get_data",
  description: "מחזיר מידע",
  schema: z.object({ id: z.string() }),
});

// תיאור טוב — ברור מה הכלי עושה, מתי להשתמש בו, ומה הפרמטר אומר
tool(getWeather, {
  name: "get_weather",
  description:
    "מחזיר את מזג האוויר הנוכחי (טמפרטורה ותנאים) בעיר נתונה. " +
    "יש להשתמש בו רק כששואלים במפורש על מזג אוויר.",
  schema: z.object({
    city: z.string().describe("שם העיר, למשל 'תל אביב'"),
  }),
});

כלים שצריכים יותר מהפרמטרים המוצהרים: runtime context

לא כל מה שכלי צריך מגיע מהמודל — לעיתים צריך גם מידע שלא בטוח שרוצים שהמודל יבחר בעצמו, כמו מזהה המשתמש המחובר. LangChain מעביר לפונקציית הכלי ארגומנט שני, config, שמכיל את מה שהועבר ב-configurable בזמן agent.invoke (בדיוק כמו thread_id שראינו בפרק הקודם).

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

TypeScript
const getUserOrders = tool(
  async ({ status }: { status?: string }, config) => {
    const userId = config?.configurable?.userId;
    return await fetchOrders(userId, status);
  },
  {
    name: "get_user_orders",
    description: "מחזיר את ההזמנות של המשתמש המחובר, אפשר לסנן לפי סטטוס",
    schema: z.object({ status: z.string().optional() }),
  }
);

דוגמה מלאה: agent עם שני כלים

agent יכול לקבל כמה כלים במקביל ברשימת tools — בכל סיבוב בלולאה האגנטית המודל בוחר איזה כלי (אם בכלל) להפעיל, בהתאם לשאלה. בדוגמה הבאה יש לו גם getWeather וגם getUserOrders, ובבקשה אחת הוא מפעיל את שניהם.

TypeScript
const agent = createAgent({
  model: "anthropic:claude-sonnet-5",
  tools: [getWeather, getUserOrders],
  systemPrompt: "אתה עוזר אישי שיכול לבדוק מזג אוויר ולשלוף הזמנות של המשתמש.",
});

const result = await agent.invoke(
  {
    messages: [
      { role: "user", content: "מה מזג האוויר בתל אביב, ומה ההזמנות הפתוחות שלי?" },
    ],
  },
  { configurable: { thread_id: "chat-2", userId: "user-42" } }
);