Пока твой бот просто говорит. А ты хочешь, чтобы он ещё и делал: добавлял задачу в план пользователя, ставил напоминание через сутки, доставал из БД заметки о прошлой сессии, сохранял новую цель. В чистом чат-режиме модель этого не умеет — она только генерирует текст. Нужно научить её вызывать твои функции. Это и называется tool use (или function calling в терминологии OpenAI).
Ты описываешь свои функции модели: название, что делают, какие
принимают параметры. Во время диалога, если модель решит, что нужно
вызвать функцию — она вернёт не текст ответа, а структурный
объект вида «хочу вызвать add_task с параметрами {title: "позвонить маме", due: "завтра"}».
Твой код выполняет функцию (добавляет строчку в БД) и возвращает
результат обратно модели. Модель, видя результат, пишет
финальный текст пользователю.
Стек у тебя: 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: по этому тексту модель решит, когда его звать.
Чем понятнее описание, тем реже она промахивается.
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, он
защищает от инъекций.
@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); второй вызов —
модель формирует человеческий ответ, видя результат. Если инструмент
не нужен — просто отвечаем текстом, который пришёл.
add_task(title, due_date) — записать задачу в план.get_user_notes(user_id) — достать заметки о пользователе из БД.save_goal(text) — сохранить сформулированную долгосрочную цель.schedule_check_in(date) — поставить «через N дней напомни спросить, как идут дела».log_mood(mood, note) — зафиксировать настроение на текущий момент.
Пользователь написал: «поставь позвонить маме» без даты. Мини-модели
могут угадать «сегодня». Более умные переспрашивают: «на какой
день?». Для критичных параметров в description
дополнительно пиши: «если пользователь не указал, переспроси, не
угадывай».
add_task). Напиши её,
протестируй, только потом добавляй следующие.
tools.py — не в куче с промптом.