מה ההבדל בין chatbot ל-agent?
chatbot עונה מהזיכרון. agent פועל בעולם. Tool Use הוא הגשר בין השניים.
כשאתה שואל את Claude "כמה לקוחות יש לנו היום?", הוא לא יודע. אבל אם תגדיר לו כלי בשם query_database, הוא יחליט לקרוא לו, יחכה לתוצאה, ויענה בדיוק. זה Tool Use (שנקרא גם Function Calling).
הרעיון: Claude מחזיר stop_reason: "tool_use" עם בלוק tool_use שמכיל שם הכלי ופרמטרים. הקוד שלך מבצע את הפעולה, DB query, קריאת API, שליחת מייל, ושולח את התוצאה חזרה. Claude קורא, ממשיך, עד ל-stop_reason: "end_turn".
הגדרת כלי, JSON Schema מלא
כל כלי מורכב משלושה שדות חובה: namedescription, ו-input_schema. ה-description הוא הגורם הכי קריטי לביצועים, תיעוד Anthropic מדגיש: "Provide extremely detailed descriptions. This is by far the most important factor in tool performance."
| שדה | מה לכלול | דוגמה רעה | דוגמה טובה |
|---|---|---|---|
| name | מזהה ייחודי, a-z/0-9/_/- | tool1 | search_customers |
| description | מה עושה, מתי לקרוא, מה מחזיר, מגבלות | "מחפש לקוחות" | "מחפש לקוחות לפי שם/מייל/מזהה. השתמש כשמשתמש שואל על לקוח ספציפי. מחזיר מקסימום 20 תוצאות. לא מחזיר פרטי תשלום." |
| input_schema | JSON Schema מלא עם types, enums, required | properties ריק | type, description, enum לכל פרמטר |
const tools = [{
name: "search_customers",
description: "מחפש לקוחות לפי קריטריונים. השתמש כשנדרש מידע על לקוח ספציפי. מחזיר עד 20 תוצאות עם שם, מייל, וסטטוס. לא מחזיר פרטי אשראי.",
input_schema: {
type: "object",
properties: {
query: { type: "string", description: "שם, מייל, או מזהה לחיפוש" },
status: { type: "string", enum: ["active","inactive","all"], description: "סנן לפי סטטוס" },
limit: { type: "integer", description: "מספר תוצאות, ברירת מחדל 10" }
},
required: ["query"]
}
}];
עדכון 2026: ניתן להוסיף שדה input_examples לtool definition עם מערך דוגמאות schema-validated. זה עוזר לClaude להבין פרמטרים מורכבים ופורמטים ספציפיים, מבלי להכביד על ה-description.
עדכון נוסף: strict: true בהגדרת הכלי מבטיח שClaude תמיד מחזיר inputs שתואמים לschema בדיוק, שימושי כשהקוד שלך לא סובל deviations.
הלולאה האגנטית, הקוד שמחזיק הכל יחד
הלולאה האגנטית היא while loop פשוט: שלח בקשה, בדוק stop_reason, אם tool_use, בצע ושלח תוצאה, אם end_turn, סיים.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function runAgentLoop(userMessage) {
const messages = [{ role: "user", content: userMessage }];
while (true) {
const response = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 4096,
tools,
messages
});
if (response.stop_reason === "end_turn") {
const text = response.content.find(b => b.type === "text");
return text?.text ?? "";
}
if (response.stop_reason === "tool_use") {
// 1. הוסף תשובת Claude להיסטוריה, חובה!
messages.push({ role: "assistant", content: response.content });
// 2. בצע את כל הכלים שClaude ביקש
const toolResults = [];
for (const block of response.content) {
if (block.type !== "tool_use") continue;
let result;
try {
result = await executeTool(block.name, block.input);
} catch (e) {
result = { error: String(e) };
}
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result)
});
}
// 3. שלח את כל התוצאות בהודעת user אחת
messages.push({ role: "user", content: toolResults });
}
}
}
3 טעויות קריטיות שמובילות ל-bugs
טעות 1, לא מוסיפים assistant message לפני tool_results: Claude צריך לראות את התשובה שלו עצמו כדי לקשר tool_result לקריאה שעשה. בלי זה, infinite loop או תשובות מבולגנות. כלל: תמיד push את response.content לmessages לפני שאתה מוסיף tool_results.
טעות 2, בדיקה רק על content[0]: Claude יכול להחזיר text block לפני tool_use block. קוד שמסתכל רק על content[0] מפספס את הקריאה לכלי. תמיד iterate על כל response.content ובדוק block.type.
טעות 3, tool_result אחד ל-multiple tool_use: כשClaude קורא לשני כלים במקביל, חייבים להחזיר tool_result נפרד לכל block.id. הכל באותה user message, אבל בנפרד.
tool_choice, שליטה על מתי Claude משתמש בכלים
ה-default הוא auto, Claude מחליט. אבל יש מצבים שצריך שליטה:
| tool_choice | מה קורה | מתי להשתמש |
|---|---|---|
| auto (ברירת מחדל) | Claude מחליט אם לקרוא לכלי | רוב המקרים |
| any | Claude חייב לקרוא לאחד הכלים | כשרוצים תמיד JSON structured output |
| tool (+ name) | Claude חייב לקרוא לכלי הספציפי | extraction מאולצת, classification |
| none | Claude לא יכול לקרוא לשום כלי | כשמעבירים tools אבל לא רוצים שישתמש |
שלב tool_choice: {type: "any"} עם strict: true לקבל JSON מובנה וvalidated בכל קריאה.
דוגמה ישראלית, מערכת CRM לסטארטאפ תל אביבי
סטארטאפ B2B בתל אביב רוצה שClaude יוכל לענות לשאלות של נציגי מכירות על לקוחות. הם מגדירים שני כלים: get_customer ו-list_open_deals. נציג שואל: "מה הסטטוס של Tamar Cohen מחברת BioTech IL?", Claude קורא ל-get_customer עם query="BioTech IL", מקבל ID, אח"כ קורא ל-list_open_deals עם customer_id, ועונה: "יש 2 עסקאות פתוחות ב-BioTech IL, אחת בסך 45K ש"ח בשלב נגוציאציה, השנייה 120K ש"ח ב-Proposal." הנציג לא נגע בCRM.
