On this page
Lesson 4 of 8
Tool use
What you'll learn
- Define a tool the model can call with proper input schema
- Handle the tool_use → tool_result loop end-to-end
- Compose multiple tools without losing context
Tool use turns Claude from a writer into a doer. Instead of asking Claude to guess at live data or compute arithmetic, you give it functions it can call. This lesson covers the protocol, the failure modes, and the design patterns that make tools work well.
Defining a tool
A tool is a JSON Schema that tells Claude what the function does and what inputs it accepts:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const tools: Anthropic.Tool[] = [
{
name: "get_weather",
description:
"Get the current weather for a given city. Returns temperature in Celsius and a short description.",
input_schema: {
type: "object" as const,
properties: {
city: {
type: "string",
description: "The city name, e.g. 'Paris' or 'Tunis'",
},
},
required: ["city"],
},
},
];
The description matters more than you think. Claude uses it to decide when to call the tool and how to fill in parameters. A vague description like "gets weather" produces worse tool selection than "Get the current weather for a given city. Returns temperature in Celsius and a short description."
The tool use loop
Tool use is a multi-step conversation. Here is the full loop:
// Step 1: Send the request with tools
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
tools,
messages: [{ role: "user", content: "What's the weather in Tunis?" }],
});
// Step 2: Check if Claude wants to use a tool
if (response.stop_reason === "tool_use") {
const toolBlock = response.content.find(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
if (toolBlock) {
// Step 3: Execute the tool yourself
const weatherResult = await fetchWeather(
(toolBlock.input as { city: string }).city
);
// Step 4: Send the result back
const followUp = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
tools,
messages: [
{ role: "user", content: "What's the weather in Tunis?" },
{ role: "assistant", content: response.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolBlock.id,
content: JSON.stringify(weatherResult),
},
],
},
],
});
// Step 5: Claude now responds with the final answer
console.log(followUp.content);
}
}
The critical insight: Claude does not call your function directly. It returns a tool_use content block with the tool name and input. You execute the function, then send a tool_result message back. Claude reads the result and generates a natural language response.
Multiple tools
You can provide many tools in a single request. Claude will pick the right one — or use multiple tools in sequence:
const tools: Anthropic.Tool[] = [
{
name: "get_weather",
description: "Get current weather for a city. Returns temp (C) and conditions.",
input_schema: {
type: "object" as const,
properties: {
city: { type: "string", description: "City name" },
},
required: ["city"],
},
},
{
name: "calculate",
description: "Evaluate a mathematical expression. Returns the numeric result.",
input_schema: {
type: "object" as const,
properties: {
expression: {
type: "string",
description: "A math expression, e.g. '(25 * 9/5) + 32'",
},
},
required: ["expression"],
},
},
];
When the user asks "What's the temperature in Tunis in Fahrenheit?", Claude might first call get_weather to get Celsius, then call calculate to convert. Each tool call is a separate loop iteration — you keep sending results back until stop_reason is end_turn.
The agentic loop
For multi-step tool use, wrap the logic in a loop:
let messages: Anthropic.MessageParam[] = [
{ role: "user", content: userQuestion },
];
let continueLoop = true;
while (continueLoop) {
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
tools,
messages,
});
// Add assistant response to history
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason === "tool_use") {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === "tool_use") {
const result = await executeTool(block.name, block.input);
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result),
});
}
}
messages.push({ role: "user", content: toolResults });
} else {
continueLoop = false;
}
}
This pattern handles any number of sequential tool calls. Set a maximum iteration count (for example, 10) to prevent infinite loops when something goes wrong.
Error handling in tool results
When a tool fails, tell Claude. Do not swallow the error — send it as the tool result so Claude can adapt:
{
type: "tool_result",
tool_use_id: toolBlock.id,
is_error: true,
content: "City not found. Available cities: Tunis, Paris, London, Tokyo.",
}
Setting is_error: true tells Claude the tool failed. Claude will typically apologize to the user or try a different approach. This is much better than returning an empty result, which Claude might misinterpret as "no data available."
Tool design principles
- Name tools clearly.
get_weatheris better thanweatherortool1. Claude uses the name to decide when to call it. - Write rich descriptions. Include what the tool returns, not just what it does. "Returns temperature in Celsius and a short weather description" is better than "Gets weather."
- Validate inputs. Claude usually sends well-formed input, but always validate before executing. A missing field should return an error tool result, not crash your server.
- Keep tools focused. One tool should do one thing. A
search_and_format_and_emailtool is harder for Claude to use correctly than three separate tools.
What's next
Tools let Claude act on the world. The next lesson — Vision — teaches Claude to see. You will learn how to pass images, extract structured data from screenshots, and understand the cost model for visual inputs.
استعمال الأدوات يحوّل Claude من كاتب إلى فاعل. بدل أن تطلب من Claude تخمين بيانات حيّة أو حساب عمليّات رياضيّة، تعطيه دوالّ يستدعيها. سنغطّي البروتوكول وأنماط الإخفاق وأنماط التّصميم.
تعريف أداة
الأداة هي مخطّط JSON يخبر Claude ماذا تفعل الدّالّة وأيّ مدخلات تقبل. الحقل description أهمّ ممّا تظنّ — Claude يستعمله ليقرّر متى يستدعي الأداة وكيف يملأ المعاملات.
حلقة استعمال الأداة
استعمال الأداة محادثة متعدّدة الخطوات: ترسل الطّلب مع الأدوات، تتحقّق إن أراد Claude استدعاء أداة (stop_reason === "tool_use")، تنفّذ الأداة بنفسك، ترسل النّتيجة في رسالة tool_result، ثمّ يُجيب Claude بالاستجابة النّهائيّة.
الفهم الحاسم: Claude لا يستدعي دالّتك مباشرة. يُرجع كتلة tool_use بالاسم والمدخل. أنت تنفّذ وتُرجع النّتيجة.
أدوات متعدّدة
يمكنك تقديم عدّة أدوات في طلب واحد. Claude يختار المناسبة — أو يستعمل عدّة أدوات تتابعيًّا. للاستعمال متعدّد الخطوات، غلّف المنطق في حلقة تستمرّ حتّى يكون stop_reason هو end_turn. ضع حدًّا أقصى للتّكرارات لمنع الحلقات اللّانهائيّة.
معالجة الأخطاء في نتائج الأدوات
حين تفشل أداة، أخبر Claude. لا تبتلع الخطأ — أرسله كنتيجة أداة مع is_error: true حتّى يتكيّف Claude. هذا أفضل بكثير من إرجاع نتيجة فارغة.
مبادئ تصميم الأدوات
- سمِّ الأدوات بوضوح.
get_weatherأفضل منweatherأوtool1. - اكتب أوصافًا غنيّة. اشمل ما تُرجعه الأداة وليس فقط ما تفعله.
- تحقّق من المدخلات. حتّى لو أرسل Claude مدخلات صحيحة عادةً، تحقّق دائمًا قبل التّنفيذ.
- اجعل الأدوات مركّزة. أداة واحدة تفعل شيئًا واحدًا.
ما التّالي
الأدوات تتيح لـ Claude الفعل في العالم. الدّرس القادم — الرّؤية — يعلّم Claude أن يرى. ستتعلّم كيف تمرّر الصّور وتستخرج بيانات منظّمة من لقطات الشّاشة وتفهم نموذج تكلفة المدخلات البصريّة.
Try it yourself
Build a tiny weather + calculator agent: 2 tools, model picks the right one. Log every tool call and verify the loop.
Reflect
How would you decide what to expose as a tool vs. what to handle in the prompt? Where is the boundary?