07 β Tool use (funksiya chaqirish)¶
β¬ οΈ Oldingi: 06 β Strukturali chiqish (JSON) Β· π README Β· Keyingi: 08 β Tool runner va Zod β‘οΈ
Bu bobda: LLM nega yolg'iz ish bajara olmasligini va tool use (vosita ishlatish / funksiya chaqirish) buni qanday hal qilishini o'rganamiz. Tool ta'riflashni (
name,description,input_schema),tool_useβtool_resultsiklini va uni qo'lda agent loop sifatida yozishni ko'ramiz. Oxirida ob-havo + kalkulyator vositalari bilan to'liq, ishlaydigan misol quramiz. Bu β agentlar (19-bob) poydevori.
Nega tool kerak? β Claude yolg'iz nimani uddalay olmaydi¶
Tasavvur qiling: siz Claude'dan "Hozir Toshkentda ob-havo qanday?" deb so'radingiz. Claude qanchalik aqlli bo'lmasin, u bilmaydi β chunki u faqat o'zi o'rgatilgan matnga ega, va o'rgatish ma'lum bir sanada to'xtagan. Uning internetga, sizning baza'ngizga yoki real vaqtdagi narxlarga kirishi yo'q.
LLM yana ikki narsani ishonchli uddalay olmaydi:
- Aniq matematika. "240 ning 15% nechchi?" β LLM ko'pincha to'g'ri javob beradi, lekin u hisoblamaydi, balki javobni bashorat qiladi. Murakkab sonlarda u adashishi mumkin. Kalkulyator esa hech qachon adashmaydi.
- Harakat qilish. Email yuborish, bazaga yozish, buyurtma yaratish β bularning hammasi tashqi dunyoga ta'sir qiladi. Matn generatsiya qiluvchi model buni o'zi qila olmaydi.
Tool use (vositadan foydalanish) aynan shu bo'shliqni to'ldiradi. G'oya oddiy:
Siz Claude'ga vositalar (tools) β ya'ni u so'rab oladigan funksiyalar ro'yxatini berasiz. Claude qachon chaqirishni hal qiladi; funksiyani esa SIZ JavaScript'da bajarasiz va natijani qaytarasiz. Claude natijadan foydalanib javob beradi.
Analogiya. Claude β aqlli menejer. U hamma narsani o'zi qilmaydi. Aniq vazifa kerak bo'lganda β "ob-havoni tekshir", "bu sonni hisobla" β u buni sizning funksiyangizga topshiradi va natijani kutadi. Menejer qarorni qabul qiladi (kimga, qachon topshirish), lekin qo'l mehnatini xodim (sizning kodingiz) bajaradi.
β οΈ Eng muhim tushuncha (esda tuting): Model sizning kodingizni hech qachon o'zi ishlatmaydi. U faqat "iltimos,
get_weatherfunksiyasini{city: "Toshkent"}bilan chaqir" degan so'rovni chiqaradi. Funksiyani bajarish β sizning ilovangizning ishi. Bu butun bobning kaliti.
Tool ta'riflash β name, description, input_schema¶
Har bir vosita uchta narsadan iborat. Ularni messages.create() ga tools massivi sifatida berasiz:
const tools = [
{
name: "get_weather",
description:
"Berilgan shahar uchun joriy ob-havoni oladi. " +
"Foydalanuvchi biror joydagi ob-havo, harorat yoki ob-havo holatini so'raganda chaqir.",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "Shahar nomi, masalan: Toshkent" },
},
required: ["city"],
},
},
];
Uchta qism:
| Qism | Nima | Maslahat |
|---|---|---|
name |
Vositaning aniq nomi | Tushunarli bo'lsin: get_weather, send_email, search_db β weather emas. |
description |
Claude buni o'qib qachon chaqirishni hal qiladi | Eng muhim qism! Faqat "nima qiladi"ni emas, qachon chaqirish kerakligini ham aniq yozing. |
input_schema |
Argumentlarning JSON Schema'si | type, properties, har bir maydon description'i va required. |
π
descriptionβ Claude'ning yagona yo'riqnomasi. Claude qaysi vositani, qachon chaqirishni faqat shu matndan tushunadi. "Ob-havo so'ralganda chaqir" deb yozsangiz β to'g'ri chaqiradi. Bo'sh yoki noaniq qoldirsangiz β yo umuman chaqirmaydi, yo noto'g'ri vaqtda chaqiradi. Buyruq emas, kontekst bering: "X so'ralganda foydalan".
Yana bitta vosita β kalkulyator β qo'shaylik. Keyin ikkalasini bitta misolda ishlatamiz:
const tools = [
{
name: "get_weather",
description:
"Berilgan shahar uchun joriy ob-havoni oladi. " +
"Foydalanuvchi ob-havo yoki harorat so'raganda chaqir.",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "Shahar nomi" },
},
required: ["city"],
},
},
{
name: "calculate",
description:
"Matematik ifodani aniq hisoblaydi. Foydalanuvchi hisob-kitob, " +
"foiz yoki arifmetika so'raganda chaqir β sonlarni o'zing taxmin qilma.",
input_schema: {
type: "object",
properties: {
expression: {
type: "string",
description: "JavaScript arifmetik ifodasi, masalan: 240 * 0.15",
},
},
required: ["expression"],
},
},
];
Claude bu ta'rifni o'qiydi va, kerak bo'lsa, unga mos tool_use blokini chiqaradi β uning name va input maydonlari sizning funksiyangizni qanday chaqirishni aytadi:
Sikl (qo'lda) β asosiy fikrlash modeli¶
Mana butun bobning yuragi. Tool use β bu sikl (loop): Claude vosita so'raydi β siz bajarasiz β natijani qaytarasiz β Claude davom etadi. Buni qadamma-qadam ko'raylik.
- Yuborasiz:
messages.create({ tools, messages }). - Tekshirasiz: agar
stop_reason === "tool_use"bo'lsa, javobcontent'ida bir yoki bir nechtatool_usebloki bor:{ id, name, input }. - Bajarasiz:
name'ga mos JavaScript funksiyasiniinputbilan ishlatasiz. - Qo'shasiz: massivga assistant'ning to'liq javobini (
{ role: "assistant", content: msg.content }) va tool natijasini qo'shasiz: - Takrorlaysiz:
messages.createni qaytadan chaqirasiz.stop_reason === "end_turn"bo'lguncha davom etasiz.
π
stop_reasonnima ekanini eslatib o'tamiz: bu model nega to'xtaganini aytadi (end_turn,max_tokens,tool_use...). Batafsil 03 β Messages API da ko'rgansiz. Tool use'da bizni ikki holat qiziqtiradi:tool_use(vosita kerak β davom et) vaend_turn(tugadi β to'xta).
messages massivi har qadamda o'sib boradi. API holatsiz (stateless) β har safar butun tarixni qayta yuborasiz, shu jumladan assistant'ning oldingi tool_use bloki ham:
β οΈ
tool_use_idβ bog'lovchi ip.tool_resultichidagitool_use_idaynan qaysitool_usechaqiruviga javob ekanini ko'rsatadi. Unitool_useblokiningid'sidan so'zma-so'z ko'chiring. Bir nechta vosita bo'lsa, har bir natija o'zid'si bilan to'g'ri chaqiruvga bog'lanadi.
To'liq ishlaydigan misol β qo'lda loop¶
Endi hammasini birlashtiramiz. Foydalanuvchi savoli: "Toshkentda ob-havo qanday, va 240 ning 15% nechchi?" β bu ikkala vositani ham talab qiladi. To'liq while(true) siklini ko'ramiz: u tool_use'ni qayta ishlaydi, lokal toolFns xaritasidan funksiyani bajaradi, natijani qaytaradi va end_turn'da to'xtaydi.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // ANTHROPIC_API_KEY muhitdan o'qiladi
// 1) Vosita ta'riflari (Claude o'qiydi)
const tools = [
{
name: "get_weather",
description:
"Berilgan shahar uchun joriy ob-havoni oladi. " +
"Foydalanuvchi ob-havo yoki harorat so'raganda chaqir.",
input_schema: {
type: "object",
properties: { city: { type: "string", description: "Shahar nomi" } },
required: ["city"],
},
},
{
name: "calculate",
description:
"Matematik ifodani aniq hisoblaydi. Hisob-kitob yoki foiz " +
"so'ralganda chaqir β sonlarni taxmin qilma.",
input_schema: {
type: "object",
properties: {
expression: { type: "string", description: "Arifmetik ifoda, masalan 240 * 0.15" },
},
required: ["expression"],
},
},
];
// 2) Funksiyalar xaritasi (SIZNING kodingiz buni ishlatadi)
const toolFns = {
get_weather: ({ city }) => {
// Haqiqiy ilovada bu yerda ob-havo API'siga so'rov bo'lardi.
return `${city}da hozir 18Β°C, ochiq havo.`;
},
calculate: ({ expression }) => {
// Soddalik uchun; ishlab chiqarishda xavfsiz hisoblovchidan foydalaning.
const natija = Function(`"use strict"; return (${expression});`)();
return String(natija);
},
};
async function run(savol) {
const messages = [{ role: "user", content: savol }];
// 3) Agent loop: Claude vosita chaqirishni to'xtatguncha aylanadi
while (true) {
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools,
messages,
});
// Claude tugatdi β yakuniy matnni chiqaramiz
if (msg.stop_reason === "end_turn") {
const text = msg.content.find((b) => b.type === "text")?.text ?? "";
return text;
}
if (msg.stop_reason === "tool_use") {
// Assistant javobini (tool_use bloklari bilan) massivga qo'shamiz
messages.push({ role: "assistant", content: msg.content });
// Har bir tool_use blokini bajaramiz
const toolResults = [];
for (const block of msg.content) {
if (block.type !== "tool_use") continue;
let resultStr;
try {
const fn = toolFns[block.name];
resultStr = fn(block.input); // SIZ funksiyani bu yerda ishlatasiz
} catch (err) {
// Funksiya xato bersa β Claude'ga xabar beramiz, u moslashadi
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: `Xato: ${err.message}`,
is_error: true,
});
continue;
}
toolResults.push({
type: "tool_result",
tool_use_id: block.id, // chaqiruvga bog'lovchi ip
content: resultStr,
});
}
// Barcha natijalarni BITTA user xabarida qaytaramiz
messages.push({ role: "user", content: toolResults });
continue; // sikl davom etadi β Claude'ni qayta chaqiramiz
}
// Kutilmagan to'xtash sababi (max_tokens, refusal...) β chiqamiz
break;
}
}
const javob = await run("Toshkentda ob-havo qanday, va 240 ning 15% nechchi?");
console.log(javob);
// β "Toshkentda hozir 18Β°C, ochiq havo. 240 ning 15% β 36."
Bu yerda nima sodir bo'lganini bosqichma-bosqich kuzating:
- 1-aylanish: Claude ikkala vositani ham chaqirishi kerakligini ko'radi β
stop_reason: "tool_use". Javobida ikkitatool_usebloki bor (get_weathervacalculate). - Siz: ikkala funksiyani ham bajarasiz, ikkita
tool_result'ni bittauserxabarida qaytarasiz. - 2-aylanish: Claude natijalarni ko'radi, ularni jumlaga birlashtiradi β
stop_reason: "end_turn". Sikl to'xtaydi, yakuniy matn qaytadi.
Bir vaqtda bir nechta vosita¶
Yuqorida ko'rganingizdek, bitta javobda bir nechta tool_use bloki bo'lishi mumkin (Claude ob-havo va hisobni bir vaqtda so'radi). Qoida oddiy:
Hammasini bajaring, hamma
tool_result'ni BITTAuserxabarida qaytaring.
const toolResults = [];
for (const block of msg.content) {
if (block.type === "tool_use") {
const result = toolFns[block.name](block.input);
toolResults.push({
type: "tool_result",
tool_use_id: block.id, // har biri o'z id'si bilan
content: result,
});
}
}
// Bitta xabarda, bir nechta natija:
messages.push({ role: "user", content: toolResults });
Har bir tool_result'ning tool_use_id'si o'z tool_use blokining id'siga mos kelishi kerak β shunda Claude qaysi natija qaysi chaqiruvga tegishli ekanini biladi.
tool_choice β vosita ishlatishni boshqarish¶
Standartda Claude o'zi hal qiladi: vosita kerakmi yoki to'g'ridan-to'g'ri javob beradimi. Lekin tool_choice bilan buni majburlash mumkin:
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools,
tool_choice: { type: "auto" }, // standart
messages,
});
tool_choice |
Nima qiladi | Qachon ishlatasiz |
|---|---|---|
{ type: "auto" } |
Claude o'zi hal qiladi (standart) | Aksariyat hollarda. |
{ type: "any" } |
Albatta birorta vosita chaqirishi shart | Javob doim vosita orqali kelishi kerak bo'lsa. |
{ type: "tool", name: "calculate" } |
Aniq shu vositani majburlaydi | Aynan bitta funksiya kerakligini bilsangiz. |
{ type: "none" } |
Vosita ishlatolmaydi | Vositalar berilgan, lekin shu chaqiruvda kerakmas bo'lsa. |
π‘ Qachon majburlash kerak? Masalan, foydalanuvchi kiritmasidan strukturali ma'lumot ajratish uchun bitta vositani
{type: "tool", name: ...}bilan majburlash mumkin. Lekin ko'p hollardaautoeng yaxshi β Claude kontekstga qarab to'g'ri qaror qiladi.
Xatolarni qayta ishlash¶
Sizning funksiyangiz har doim ham muvaffaqiyatli ishlamaydi β API tushib qolishi, shahar topilmasligi mumkin. Bunda xatoni yashirmang β tool_result'da is_error: true bilan qaytaring:
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: "Xato: 'xyz' shahri topilmadi. To'g'ri shahar nomini bering.",
is_error: true,
});
Claude xato natijani ko'radi va moslashadi β ya'ni boshqa yondashuvni sinab ko'radi yoki foydalanuvchidan aniqlik so'raydi. Bu β tool use'ning kuchli tomoni: model real dunyodagi nosozliklarga ishonchli munosabat bildira oladi.
Eng yaxshi amaliyotlar¶
Tool use'ni ishonchli qurish uchun:
description'ni aniq yozing. Claude qaysi vositani qachon chaqirishni faqat shundan biladi. "X so'ralganda chaqir" deb kontekst bering. Bu β vosita to'g'ri ishlashining 1-sharti.input'ni bajarishdan oldin tekshiring. Claude yuborgan argumentlarni ishonchli deb qabul qilmang β funksiyangiz ichida validatsiya qiling (masalan,cityhaqiqatan ham mavjudligini).- Zararli amallarni darvozadan o'tkazing. Email yuborish, ma'lumot o'chirish kabi qaytarib bo'lmaydigan amallarni avtomatik bajarmang β foydalanuvchi tasdig'ini so'rang. Aynan shu sabab qo'lda loop (ne avtomatik runner) ko'pincha foydali: har chaqiruvdan oldin "to'xtab", tasdiq so'rashingiz mumkin.
- Vositalar to'plamini ixcham tuting. Juda ko'p vosita Claude'ni chalg'itadi. Faqat kerakli, fokuslangan to'plamni bering.
Bu β agentlarning poydevori¶
Siz hozir qurgani β vosita chaqiradigan, natijani kutadigan va davom etadigan sikl β bu aslida agentning eng oddiy ko'rinishi. Agent (19-bob) β bu xuddi shu loop, faqat ko'proq vosita, ko'proq mustaqillik va ko'proq qadam bilan. Claude o'z trayektoriyasini o'zi hal qiladi: qaysi vositani, qaysi tartibda, qachon to'xtashni.
Demak, bu bobda o'rgangan tool_use β bajar β tool_result β takrorla sikli β kitobning eng muhim asoslaridan biri. Agentlar asoslari da bunga qaytamiz.
Keyingi bobda esa SDK'ning avtomatik tool runner'ini (betaZodTool) ko'ramiz β u shu qo'lda loop'ni siz uchun yozadi va Zod bilan tipli vositalar beradi.
Mashqlar¶
1-mashq. O'z so'zingiz bilan tushuntiring: tool use'da Claude funksiyani o'zi ishlatadimi? Agar yo'q bo'lsa, funksiyani kim bajaradi va Claude aslida nima qiladi?
2-mashq. Quyidagi vosita ta'rifida bitta muhim kamchilik bor. Nima va nega muammo? Tuzating.
{
name: "tool1",
description: "Ma'lumot oladi",
input_schema: { type: "object", properties: { q: { type: "string" } } },
}
3-mashq. Qo'lda loop'da stop_reason === "tool_use" bo'lganda, messages massiviga ikkita narsa qo'shiladi. Ular qaysilar va qaysi tartibda? Nega assistant'ning tool_use blokini ham massivga qo'shish shart?
4-mashq. tool_result ichidagi tool_use_id nima vazifani bajaradi? Agar uni noto'g'ri (boshqa chaqiruvning id'si) qo'ysangiz nima bo'ladi?
5-mashq. get_time nomli vosita yozing β u argument olmaydi va joriy vaqtni satr sifatida qaytaradi. tools ta'rifini va toolFns xaritasidagi funksiyani yozing.
6-mashq. Foydalanuvchi "Parijdagi vaqtni va Toshkentdagi vaqtni ayt" desa, Claude bitta javobda nechta tool_use bloki chiqaradi (get_time har shahar uchun)? Siz natijalarni qanday qaytarasiz β har biri uchun alohida user xabaridami yoki bitta xabardami?
Yechimlar
1-yechim. Yo'q, Claude funksiyani o'zi ishlatmaydi. Claude faqat "shu funksiyani shu argumentlar bilan chaqir" degan so'rovni (tool_use blokini name va input bilan) chiqaradi. Funksiyani sizning ilovangiz (JavaScript kodingiz) bajaradi va natijani tool_result orqali qaytaradi. Claude esa: (a) qaysi vositani qachon chaqirishni hal qiladi, va (b) natijani olib, undan foydalanib yakuniy javobni shakllantiradi.
2-yechim. Ikki kamchilik:
- name ("tool1") va description ("Ma'lumot oladi") juda noaniq β Claude buni qachon chaqirishni bilolmaydi. Aniq nom va "X so'ralganda chaqir" tarzidagi kontekst kerak.
- required yo'q β q majburiymi yoki yo'qmi noma'lum.
Tuzatilgan:
{
name: "search_docs",
description:
"Hujjatlar bazasidan matn qidiradi. Foydalanuvchi hujjat, " +
"qo'llanma yoki ichki ma'lumot so'raganda chaqir.",
input_schema: {
type: "object",
properties: { q: { type: "string", description: "Qidiruv so'rovi" } },
required: ["q"],
},
}
3-yechim. Qo'shiladi:
1. Avval assistant'ning to'liq javobi: { role: "assistant", content: msg.content } (bu tool_use bloklarini saqlaydi).
2. Keyin tool natijalari: { role: "user", content: [{ type: "tool_result", tool_use_id, content }] }.
Assistant'ning tool_use blokini qo'shish shart, chunki API holatsiz β har safar butun tarixni yuborasiz. Agar tool_use blokini tashlab ketsangiz, tool_result'ning tool_use_id'si hech qaysi chaqiruvga bog'lanmaydi va API xato beradi (rollar/bloklar mos kelmaydi).
4-yechim. tool_use_id natijani aynan qaysi tool_use chaqiruviga javob ekanini ko'rsatadi β uni tool_use blokining id'sidan so'zma-so'z ko'chiriladi. Bu, ayniqsa, bir nechta vosita bir vaqtda chaqirilganda muhim. Noto'g'ri (boshqa chaqiruvning) id'si qo'ysangiz, API natijani to'g'ri chaqiruvga bog'lay olmaydi va xato qaytaradi (yoki Claude noto'g'ri natijani noto'g'ri savolga bog'laydi).
5-yechim.
// tools massiviga:
{
name: "get_time",
description: "Joriy vaqtni qaytaradi. Foydalanuvchi hozir soat nechchaligini so'raganda chaqir.",
input_schema: { type: "object", properties: {}, required: [] },
}
// toolFns xaritasiga:
get_time: () => new Date().toLocaleTimeString("uz-UZ"),
properties bo'sh va required bo'sh massiv.
6-yechim. Claude ikkita tool_use bloki chiqaradi (get_time Parij uchun, yana biri Toshkent uchun) β ehtimol har biri boshqa input bilan, masalan { timezone: "Europe/Paris" } va { timezone: "Asia/Tashkent" } (agar sxemada vaqt mintaqasi maydoni bo'lsa). Natijalarni bitta user xabarida, ikkita tool_result bloki bilan qaytarasiz β har biri o'z tool_use_id'si bilan to'g'ri chaqiruvga bog'langan. Har bir natija uchun alohida xabar yubormaysiz.
β¬ οΈ Oldingi: 06 β Strukturali chiqish (JSON) Β· π README Β· Keyingi: 08 β Tool runner va Zod β‘οΈ