← Claude на русском
Перевод с разбором · для Сони
Адаптировал Claude Opus 4.7 (ИИ) на основе документации Anthropic. Полная версия — в docs/tool-use.html.

Tool use: функции для бота

Адаптация для Сони · 2026-04-23

Зачем тебе это нужно

Пока твой бот просто говорит. А ты хочешь, чтобы он ещё и делал: добавлял задачу в план пользователя, ставил напоминание через сутки, доставал из БД заметки о прошлой сессии, сохранял новую цель. В чистом чат-режиме модель этого не умеет — она только генерирует текст. Нужно научить её вызывать твои функции. Это и называется tool use (или function calling в терминологии OpenAI).

Как это устроено в общих чертах

Ты описываешь свои функции модели: название, что делают, какие принимают параметры. Во время диалога, если модель решит, что нужно вызвать функцию — она вернёт не текст ответа, а структурный объект вида «хочу вызвать add_task с параметрами {title: "позвонить маме", due: "завтра"}». Твой код выполняет функцию (добавляет строчку в БД) и возвращает результат обратно модели. Модель, видя результат, пишет финальный текст пользователю.

Как это выглядит в aiogram + SQLite

Стек у тебя: aiogram (Telegram), openai SDK, sqlite3 для локальной базы. Шаг 1 — описать инструмент модели:

import json, sqlite3
from openai import OpenAI
from aiogram import Dispatcher, types

openai = OpenAI()
db = sqlite3.connect("bot.db", check_same_thread=False)
dp = Dispatcher()

tools = [{
    "type": "function",
    "function": {
        "name": "add_task",
        "description": "Добавляет задачу в план пользователя на указанную дату.",
        "parameters": {
            "type": "object",
            "properties": {
                "title": {"type": "string", "description": "Что сделать"},
                "due_date": {"type": "string", "description": "YYYY-MM-DD, 'today' или 'tomorrow'"}
            },
            "required": ["title"]
        }
    }
}]

Что здесь происходит: описали один инструмент. Самое важное — description: по этому тексту модель решит, когда его звать. Чем понятнее описание, тем реже она промахивается.

Локальная функция в SQLite

def add_task_to_db(user_id: int, title: str, due_date: str = "today") -> dict:
    db.execute(
        "INSERT INTO tasks (user_id, title, due_date) VALUES (?, ?, ?)",
        (user_id, title, due_date),
    )
    db.commit()
    return {"ok": True, "title": title, "due_date": due_date}

Что здесь происходит: обычный INSERT. SQLite у тебя в файле bot.db. Таблицу tasks заранее создаёшь init-скриптом (CREATE TABLE IF NOT EXISTS tasks …). Вопросик ? в запросе — это параметризованный SQL, он защищает от инъекций.

Хэндлер aiogram с двумя вызовами модели

@dp.message()
async def on_message(msg: types.Message):
    user_id = msg.from_user.id
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": msg.text},
    ]

    # Первый вызов: модель решает, нужен ли tool
    response = openai.chat.completions.create(
        model="gpt-5.4-mini",
        messages=messages,
        tools=tools,
    )
    reply = response.choices[0].message

    if reply.tool_calls:
        for call in reply.tool_calls:
            if call.function.name == "add_task":
                args = json.loads(call.function.arguments)
                result = add_task_to_db(user_id, **args)
                messages.append(reply)                       # «хочу вызвать»
                messages.append({                             # результат
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": json.dumps(result),
                })
        # Второй вызов: модель пишет человеческий ответ
        response2 = openai.chat.completions.create(
            model="gpt-5.4-mini", messages=messages, tools=tools,
        )
        await msg.answer(response2.choices[0].message.content)
    else:
        # Обычный текстовый ответ, без инструментов
        await msg.answer(reply.content)

Что здесь происходит: aiogram ловит сообщение Telegram и передаёт в on_message. Дальше идёт «двухфазный» цикл: первый вызов — модель решает, звать ли функцию; мы выполняем функцию (запись в SQLite); второй вызов — модель формирует человеческий ответ, видя результат. Если инструмент не нужен — просто отвечаем текстом, который пришёл.

Какие функции имеет смысл делать у твоего бота

Когда параметров не хватает

Пользователь написал: «поставь позвонить маме» без даты. Мини-модели могут угадать «сегодня». Более умные переспрашивают: «на какой день?». Для критичных параметров в description дополнительно пиши: «если пользователь не указал, переспроси, не угадывай».

Что это значит для твоего бота

Полная версия с деталями API Anthropic — в docs/tool-use.html.