EvolCode
треки/Claude — глубокий разбор·04 / 07
9 мин чтения

Tool use — учим Claude вызывать функции

До этого Claude просто отвечал текстом. Tool use превращает его в агента: ты описываешь функции — он сам решает когда их вызвать, с какими параметрами, и встраивает результат в ответ. Это база для всего что мы делаем дальше — от чат-ботов с базой данных до агентов которые правят файлы на сервере.

Зачем tool use

Claude знает много, но не знает СВЕЖЕЕ. Не знает погоду в Киеве сейчас, не знает что в твоей базе данных, не умеет делать математику со 100% точностью на больших числах. Tools — это способ закрыть эти дыры: даёшь ему функцию get_weather(city) или query_db(sql) — и Claude использует её когда нужно. То же самое у OpenAI называется function calling — концепция идентичная.

Анатомия tool definition

Каждый tool — это объект с тремя полями: name (короткое имя функции), description (описание в свободной форме — что делает, когда вызывать), input_schema (JSON Schema параметров: какие поля, какого типа, какие обязательные). От качества description сильно зависит будет ли Claude вызывать функцию правильно. Пиши описания развёрнуто, с примерами входов и выходов.

Цикл tool_use → tool_result

1) Шлёшь запрос с массивом tools и messages. 2) Claude отвечает либо обычным текстом (stop_reason: end_turn), либо запросом на вызов функций (stop_reason: tool_use). 3) Если tool_use — в content будут блоки

$ { type: "tool_use", id, name, input }

Ты исполняешь эти функции у себя в коде. 4) Шлёшь следующий запрос со старой историей + новое user-сообщение с блоками

$ { type: "tool_result", tool_use_id, content }

5) Claude видит результаты и формирует финальный ответ или просит ещё вызовов.

Параллельные вызовы

Claude может попросить вызвать НЕСКОЛЬКО функций сразу за один раунд — например get_weather("Киев") и get_weather("Львов") параллельно. В content придёт несколько tool_use блоков. Исполняй их параллельно (Promise.all) и возвращай все результаты в одном следующем сообщении. Это ускоряет агента в разы.

Tool choice — управление поведением

Опциональный параметр tool_choice: auto (дефолт — Claude решает сам), any (обязательно вызвать какой-то tool), tool: { name: "X" } (обязательно вызвать конкретный). Полезно когда у тебя сценарий «всегда сначала проверь авторизацию» — заставляешь Claude в первом ходе вызвать check_auth().

примерjavascript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();

// === ОПИСЫВАЕМ TOOL ===
const tools = [
  {
    name: 'calculate',
    description:
      'Точно вычисляет математическое выражение. Используй когда нужны точные расчёты с большими числами или сложными операциями. Пример: input { expression: "1234 * 5678 + 999" } → результат "7008871".',
    input_schema: {
      type: 'object',
      properties: {
        expression: {
          type: 'string',
          description: 'Математическое выражение в JS-синтаксисе',
        },
      },
      required: ['expression'],
    },
  },
];

// === ИСПОЛНИТЕЛЬ ===
function calculate({ expression }) {
  // ВАЖНО: в реальном коде НЕ используй eval с произвольным input.
  // Это пример — для демо. Возьми expr-eval или mathjs.
  try {
    return { result: String(Function(`"use strict"; return (${expression})`)()) };
  } catch (e) {
    return { error: 'Не смог вычислить' };
  }
}

// === ЦИКЛ АГЕНТА ===
async function ask(userMessage) {
  const messages = [{ role: 'user', content: userMessage }];

  for (let i = 0; i < 5; i++) {
    const r = await client.messages.create({
      model: 'claude-sonnet-4-6',
      max_tokens: 1024,
      tools,
      messages,
    });
    messages.push({ role: 'assistant', content: r.content });

    if (r.stop_reason !== 'tool_use') {
      return r.content.find((b) => b.type === 'text')?.text;
    }

    // Параллельно исполняем все запрошенные tools
    const toolUses = r.content.filter((b) => b.type === 'tool_use');
    const results = await Promise.all(
      toolUses.map(async (use) => ({
        type: 'tool_result',
        tool_use_id: use.id,
        content: JSON.stringify(calculate(use.input)),
      }))
    );
    messages.push({ role: 'user', content: results });
  }
}

// Использование
const answer = await ask('Сколько будет 1234 × 5678 + 999?');
console.log(answer);
// → Claude вызывает calculate({expression: "1234 * 5678 + 999"})
//   получает 7008871, и отвечает «Получится 7,008,871»
//
// Без tool Claude мог бы ошибиться в третьей цифре —
// LLM плохо считает большие числа, это известное ограничение.

Простой пример: Claude вызывает калькулятор для точной математики

главное
  • 01Tool use = функции которые Claude может вызвать сам, когда нужно
  • 02Каждый tool: name + description (важно!) + input_schema (JSON Schema параметров)
  • 03Описание тула — главное что влияет на качество. Пиши развёрнуто, с примерами
  • 04Цикл: запрос → tool_use → ты исполняешь → tool_result → следующий запрос
  • 05Claude может попросить несколько tools за раз — исполняй параллельно через Promise.all
  • 06tool_choice = "any" / "auto" / { name } — когда нужно заставить Claude вызвать конкретный tool
  • 07Tools закрывают слабые места LLM: свежие данные, точная математика, доступ к твоим системам
проверь себя
01Какое поле tool definition больше всего влияет на то, правильно ли Claude вызовет функцию?
02Claude в одном ответе попросил вызвать get_user(id=1) и get_orders(user_id=1). Как лучше?
03В сценарии «бот должен ВСЕГДА проверить авторизацию первым делом» что использовать?
следующий урок: Claude как «руки» на твоём сервере