В Bot API 10.3 появилась остановка генерации. Но LLM-запрос придётся отменять самому
24 августа вышел Telegram Bot API 10.3. В нём появилась полезная функция для AI-ботов: пользователь может остановить генерацию ответа штатной кнопкой Telegram.
В методы sendMessageDraft и sendRichMessageDraft, которые позволяют показывать черновик ответа в личном чате, добавили два параметра:
can_stop=True— показывает кнопку остановки;keep_on_stop=True— временно оставляет уже сгенерированную часть ответа в чате.
Когда пользователь нажимает кнопку, бот получает обновление stopped_message_generation. В нём есть chat, message_thread_id и draft_id, поэтому событие можно связать с конкретной генерацией.
Если вы явно задаёте allowed_updates, новый тип обновления нужно добавить туда. Иначе нажатие кнопки просто не попадёт в обработчик.
Но Telegram останавливает только показ черновика. Запрос к LLM на стороне бота продолжит выполняться, пока разработчик сам его не отменит.
Например, можно хранить задачи по ключу из идентификаторов чата, темы и черновика:
key = (chat_id, message_thread_id, draft_id) active_generations[key] = asyncio.create_task( generate_answer() )
При получении stopped_message_generation находим задачу и отменяем её:
event = update.stopped_message_generation key = (event.chat.id, event.message_thread_id, event.draft_id) task = active_generations.pop(key, None) if task is not None: task.cancel() try: await task except asyncio.CancelledError: pass
Это упрощённый пример: конкретный обработчик зависит от используемого фреймворка.
Одного task.cancel() тоже не всегда достаточно. Отмена в asyncio кооперативная: задача остановится только тогда, когда управление вернётся в event loop. Если внутри работает синхронный код или отдельный поток, он может продолжить работу.
Нужно также закрыть потоковое HTTP-соединение с провайдером модели. А если провайдер поддерживает отдельный API отмены, вызвать и его. Иначе модель может продолжить генерацию — вместе с расходом токенов — даже после закрытия соединения.
По сути, здесь есть три независимых действия:
Telegram прекращает показывать черновик;
бэкенд отменяет локальную задачу и закрывает соединение;
провайдер модели останавливает генерацию, если умеет это делать.
Ещё один нюанс касается keep_on_stop=True. Остановленный черновик не превращается в обычное сообщение. Он исчезнет после следующего сообщения в чате или примерно через 30 секунд.
Если частичный ответ нужно сохранить, его придётся отдельно отправить через sendMessage или sendRichMessage.
В многопроцессной системе обычного словаря тоже будет недостаточно: событие остановки может попасть не в тот процесс, где выполняется генерация. Тогда понадобится общая маршрутизация или канал отмены через Redis, брокер сообщений либо другой внешний сервис.
Telegram добавил удобный интерфейс, но жизненный цикл генерации всё равно остаётся на стороне разработчика.
Вопрос: что вы бы делали после остановки: сохраняли частичный ответ, удаляли его или показывали кнопку «Продолжить», которая запускает новый запрос с уже полученным текстом?












