Pull to refresh

Comments 13

особенно интересно услышать про ваши кейсы с 429 и таймаутами.

Можно использовать СУПЕРСИЛУ ДЕНЯК и оплачивать API-запросы, чтобы почти никогда не сталкиваться с лимитами.

Тем более что вроде у вас не студенческий проект (там понятен поиск бесплатного), а решение для техподдержки. А API оплатить имхо быстрее, чем тратить время и силы разработчиков для сложной внутренней логики.

...впрочем, кеширование в любом случае пригодилось бы, да.

Позвольте покритиковать вас немножко, по-доброму:)
Во-первых, бесплатные тарифы - это для хобби-проектов и прочих экспериментов. И там специально режут лимиты, чтобы всякие хитрые коммерсанты не использовали спонсируемые мощности в целях зарабатывания денег. Для использования в корпоративных целях естественно не искать халяву, а платить, как положено:)

"Функциональный вызов (Function Calling) для расширения возможностей"

Можно также сделать командами, это надёжнее и защищает от пространных запросов и "от дурака".

Грабли №1: 429 ошибка в пятницу вечером
Решение: используйте rate limiter на стороне бота:

Это вообще не решение, что оно решает? Решение проблемы - это использование другой модели (даже "других моделей") при ошибках типа "нет доступа".

Грабли №2: Таймауты от Telegram

Telegram ждёт ответ от бота 10 секунд. Если Gemini думает дольше, вы получите таймаут и пользователь увидит ошибку. Решение — показывать промежуточные сообщения или использовать streaming

Это потому что вы неправильно делаете. Зачем вам потоковое соединение? Получили ВЕСЬ ответ от нейросети, сохранили(!), переслали сохранённое в чат. Так у вас будет контроль на каждом этапе. Если сообщение слишком большое - аккуратно разрезали на части, применили обработку незакрытых тегов, отослали в чат по частям. Ведь у вас бывают большие сообщения, или вы просто зажали длину ответов количеством исходящих от нейросети токенов?:)

Про стриминг - это тоже не решение "проблемы 10 секунд". Это про красоту (но стриминг нравится не всем) .
Стриминг работает хорошо при нормальных условиях, а при работе через средства обхода блокировок, он может прерываться, или зависнуть, или идти больше 10 секунд у клиента - и что вы будете делать в таком случае, как это обрабатывать? Вам всё равно нужен будет запасной план из сохранённого сообщения с предобработкой (см. предыдущий абзац). К тому же, для "показывать промежуточные сообщения" в Телеграме тоже есть свои лимиты, при любом сбое в сети или в телеграме вы легко получите каскад проблем. Я не знаю, может, Aiogram как-то сам с этим разберётся, но сомневаюсь.

Для предотвращения состояний гонки - везде, абсолютно везде используйте очереди выполнения, длинные сообщения не зажимайте лимитами, а режьте на куски с валидацией с аварийным fallback на текст без тегов, всегда имейте варианты на отказ API и отказы любого этапа работы. Относитесь к сетевым ресурсам как к ненадёжным элементам :)

Удачи в разработке:)

1. Про бесплатные тарифы и коммерцию

Абсолютно согласен. В статье я сознательно сделал акцент на бесплатном тарифе, потому что целевая аудитория туториала — разработчики, которые только начинают щупать Gemini API, пишут pet-проекты или внутренние утилиты для команды. Для них 5 RPM — уже проблема, о которой они узнают постфактум. Платный тариф, конечно, снимает большинство ограничений, но и там есть потолок, и rate limiter на стороне бота не помешает (хотя бы для защиты от случайных флудов). В корпоративной среде, как верно замечено, экономия на токенах через кэш и очереди — это не про халяву, а про архитектурную гигиену и снижение счетов на круглых цифрах.

2. Function Calling vs Команды

И снова правда. Команды (/schedule/book) — более надёжный и детерминированный способ. Function Calling я включил как демонстрацию возможностей API и как мостик к более сложным агентным сценариям, где пользователь формулирует запрос свободным текстом. В реальном проекте я бы делал гибрид:

  • Команды для критичных действий с чёткими параметрами.

  • Function Calling как fallback для «поговорить с ботом как с секретарём» с обязательной валидацией аргументов и подтверждением от пользователя перед вызовом реального сервиса.
    Так и «от дурака» защита, и UX приятнее.

3. Rate Limiter и ошибка 429

Тут позволю себе уточнить, потому что мы, кажется, немного о разном.

"Решение проблемы - это использование другой модели при ошибках типа 'нет доступа'"

Переключение на другую модель — это стратегия fallback, а не rate limiting. Rate limiter на стороне бота нужен, чтобы не доводить до 429 вообще. Он ограничивает поток запросов к API, соблюдая заявленный RPM (например, не чаще 10 запросов в секунду для платной Gemini 3 Flash). Если лимит всё же превысили (скажем, из-за пиковой нагрузки или сбоя самого Google), то fallback-стратегия — следующий эшелон: другая модель, кэшированный ответ, или "извините, повторите позже".

В статье я описал именно rate limiter для профилактики 429. Fallback-стратегии заслуживают отдельной статьи, и в комментарии отлично подсвечено, что о них нельзя забывать.

4. Таймауты Telegram и Streaming

Здесь самый сочный момент. Попробую разложить по полочкам.

"Получили ВЕСЬ ответ от нейросети, сохранили, переслали сохранённое"

Да, это идеальный сценарий. Именно так и надо делать в production: сначала дождаться полного ответа от LLM, потом обработать (разрезать, экранировать Markdown/HTML), потом отправлять.

Проблема, которую я решал стримингом — не техническая, а UX-психологическая. Пользователь жмёт кнопку «Отправить» и ждёт. Если ответ генерируется 15 секунд, а бот молчит, пользователь:

  • Начинает долбить кнопку повторно (создавая каскад запросов).

  • Думает, что бот сломался, и уходит.

Streaming + промежуточное редактирование сообщения (метод edit_message_text) — это способ сказать пользователю: «Я работаю, видишь? Буквы бегут». Это не решение таймаута, а маскировка задержки под активную работу.

Что касается обхода блокировок и нестабильного соединения — вы абсолютно правы: в таких условиях стриминг может стать источником проблем. Поэтому я всегда комбинирую:

  1. Стриминг для визуального фидбека.

  2. Параллельное накопление полного ответа в памяти.

  3. По завершении генерации — финальное редактирование сообщения целиком (или отправка частями, если длинное).

Если стрим оборвался — у меня есть полный ответ, и я могу отправить его обычным методом. Aiogram, кстати, предоставляет удобные декораторы для обработки ошибок редактирования (например, если сообщение было удалено), но основная логика резервирования ложится на плечи разработчика.

"длинные сообщения не зажимайте лимитами, а режьте на куски с валидацией"

Здесь +100500. В коде статьи я как раз привёл примитивный пример разрезания строки на куски по 4000 символов. Для MarkdownV2 это, конечно, недостаточно — нужно умное разрезание с учётом открытых/закрытых тегов, иначе сообщение не отправится.

Если кратко:

По тарифам — согласен, статья скорее для тех, кто только начинает. В проде — только платные модели и нормальный мониторинг.

По Function Calling — да, команды надёжнее. В гибридном подходе им самое место.

По rate limiter'у — вы правы, он именно профилактический. Fallback на другие модели — следующий уровень защиты, о котором стоило упомянуть.

По стримингу и таймаутам — тут мы говорим про одно и то же, но с разных углов. Я про UX-иллюзию, вы про надёжность инфраструктуры. Истина как всегда в комбинации: стримим для души, а сохраняем и режем — для гарантии доставки.

Про очереди — святая правда. Без них любое сетевое взаимодействие в асинхронном боте превращается в гонки.

Cпасибо, утащил несколько идей для доработки.

  1. Стриминг для визуального фидбека.

  2. Параллельное накопление полного ответа в памяти.

  3. По завершении генерации — финальное редактирование сообщения целиком (или отправка частями, если длинное).

    Я именно так и сделал, и огрёб кучу совершенно странных глюков, в итоге плюнул и выпилил стриминг:)

    Streaming + промежуточное редактирование сообщения (метод edit_message_text) — это способ сказать пользователю: «Я работаю, видишь? Буквы бегут». Это не решение таймаута, а маскировка задержки под активную работу.

    Можно посылать промежуточное сообщение, а финальное - заменой или новым.

    Вообще, не сочтите за рекламу, просто проще показать, вот мой бот в телеге@Vika_talk_Bot

Что за tts используется в @Vika_talk_Bot ?

Стриминг, или любой аналог, нужен что бы юзер мог остановить долгую генерацию или остановить + продолжить то есть заново начать если юзер еще что то написал пока бот думал, но это сложно для реализации, не видел ни разу такое.

В телеграме вообще беда с ии ботами, а точнее с их разработчиками, подавляющее большинство из них даже просто текст от юзера до ллм донести не могут, не испортив по дороге. Вика например не реконструирует входящий маркдаун из за чего куски текста из него пропадают. Исходящий она тоже портит.

Про маркдаун в запросе.
LLM по сути работает с сырым текстом, маркдаун для неё просто набор символов (#, **, ``` и т.д.). Она не “видит” форматирование как человек.

Для "понимания" маркдауна нужно, во-первых, отключать предобработку запроса, и во-вторых, надо дать пользователю возможность задавать свой системный промт для работы, где будет явно описано использование маркдауна как семантической разметки, чтобы все нейросети точно понимали, что от них хотят. Это реально сделать, просто никому не было нужно:)

куски текста из него пропадают.

Ничего не пропадает, кроме разметки, по поводу её см. предыдущий абзац.

Исходящий она тоже портит.
Не портит, а отображает так, чтобы это выглядело нормально. Маркдаун в понимании Телеграма и вывод результатов от LLM это вообще разные вещи. Так что просто "пробросить" вывод LLM в Telegram не выйдет - будут либо ошибки парсинга, либо кривое отображение. Именно для этого разметка переделывается на html и упрощается, это не влияет на контент как таковой.

Или вы про использование Телеграм ботов для программирования? Боюсь, у меня для вас плохие новости:) Запросы на программирование с LLM требуют делать вывод в страницу в браузере или в программу, которая даёт вывод в браузер, Телеграм для этого не подходит.

Проблемы Телеграма для программирования:

  • ❌ Нет нормальной подсветки синтаксиса

  • ❌ Нельзя запустить код

  • ❌ Нет интерактивной отладки

  • ❌ Сложно копировать/вставлять большие блоки

  • ❌ Нет визуализации (графики, HTML, диаграммы)

  • ❌ Ограничение по длине сообщений

Что даёт браузер:

  • ✅ Syntax highlighting

  • ✅ Code execution (REPL, песочницы)

  • ✅ Интерактивные элементы

  • ✅ Визуализация результатов

  • ✅ Markdown/документация с предпросмотром

  • ✅ Копирование без искажений

Телеграм хорош для:

  • Уведомлений

  • Быстрых команд

  • Простых запросов

А для программирования — веб-интерфейс.
Что тоже можно, конечно, добавить:)


Пропадают символы из текста. Это меняет смысл текста. Пропадают целые куски текста - урлы из ссылок.

Причина банальная, ты неправильно получаешь присланный от юзера текст, он поступает из телеграма в разобраном виде, его надо собирать самостоятельно перед тем как передать в ллм.

В другую сторону это тоже работает, то что телеграм умеет не всё не значит что надо забить даже на то что он умеет. Конвертировать нестабильный маркдаун от ллм в строгий маркдаун для телеграма сложно но можно.

Пока бот что то стримит или просто ожидает окончания генерации его можно остановить. Ллм со стримингом так умеет делать и это реализовано на всех оригинальных сайтах, телеграм тоже не против, у него есть для этого возможности. После остановки можно убрать последний незаконченный ответ и начать снова. А можно оставить незаконченный ответ, и продолжить.

Пропадают символы из текста. Это меняет смысл текста. Пропадают целые куски текста - урлы из ссылок.


Ни одна нейросеть сама ничего искать в интернете не умеет:) Для этого она использует сторонние инструменты.
В боте для поиска в интернете есть команда /поиск, вообще почитайте про функции бота по команде /info

Можно сделать поиск исходя из контекста, чтобы по ключевым фразам типа "поищи в интернете", "погугли", но там есть свои вопросы, например, что считать окончанием фрагмента текста на запрос. Проще и надёжней искать - через команду. Сейчас сделано отдельно через команду.

И да, сейчас бот удаляет все HTML теги из входящего текста пользователя. Если пользователь отправляет ссылку в формате HTML (например, <a href="...">...</a>), она будет удалена. Потому, что зачем посылать ссылки и теги, которые нейросеть не сможет обработать, при текущих условиях (системный промт)? :)
Для корректной работы со ссылками "как в чате в браузере" нужно усложнить логику работы с входящим текстом от пользователя.

Но проблему со ссылками вы хорошо "подсветили", спасибо:) В ближайшее время займусь более аккуратным учётом ссылок при "разрезании" больших сообщений на куски и при режиме plain text.

Сейчас выдачу по поиску (по команде /поиск ) другие "персонажи" бота не видят. Можно, конечно, сделать, чтобы видели.

Конвертировать нестабильный маркдаун от ллм в строгий маркдаун для телеграма сложно но можно.

Теоретически, конечно, можно:) Но это большая сложность без особого смысла.


Пока бот что то стримит или просто ожидает окончания генерации его можно остановить. 
Да, но повторно запустить нельзя - токен будет потерян. Как сделать эмуляцию стриминга, я писал выше в комментариях.

Ллм со стримингом так умеет делать и это реализовано на всех оригинальных сайтах
Ну так на САЙТАХ работает БРАУЗЕР, про отличие браузера от среды Телеграма я тоже писал выше в комментарии.

телеграм тоже не против, у него есть для этого возможности. После остановки можно убрать последний незаконченный ответ и начать снова. А можно оставить незаконченный ответ, и продолжить

Продолжить что? Ответ от нейросети при остановке ПОТОКА будет прерван. Нейросеть закончила ответ и разорвала соединение, откуда мы возьмём продолжение ответа? Его просто нет в природе, мы же остановили нейросеть. Продолжить общение при прерывании стриминга будет можно, конечно. Для продолжения стриминга - только эмуляция его работы при получении и сохранении полного ответа на сервере.

Невозможно сравнивать телеграм-бот с сайтом в браузере или с программой типа Claude Code или Opencode, т.к. Телеграм это очень ограниченная среда. Да, там можно делать мини-приложения, но ИМХО проще уж запустить полноценный фронтенд с чат-ботом.

При чем тут поиск, ты вообще понимаешь что тебе пишут или просто копипастишь в ллм?

В сообщении который отправляет юзер нет хтмл тегов. Юзер отправляет маркдаун текст, ссылка в нем выглядит как то так

[текст ссылки](урл)

Телеграм клиент разделяет текст сообщения на 2 части, чистый текст и инфа о его форматировании, отказываясь соединять их обратно ты отбираешь у своего бота возможность правильно ответить, он не получает всю информацию и выглядит дураком.

У телеграма нет никаких проблем с остановкой генерации, для этого надо только что бы бот мог получить от юзера какой либо сигнал, нажатие кнопки или просто любое сообщение во время генерации ответа, ничего больше не надо что бы бот остановил генерацию в ллм - тут нет никакой разницы с браузером.

Ты пишешь боту запрос - напиши 10 страниц текста, они начинает писать, это заняло бы 2 минуты, через 10 секунд ты понимаешь что не хочешь ждать так долго и пишешь нет не 10 а 2, бот в это время настрочил уже 3, он останавливается и начинает писать снова, где ты тут видишь какие то ограничения телеграма, что помешает ему стереть всё что уже было написано, изменить запрос и начать выполнять последний запрос заново?

Что за tts используется в @Vika_talk_Bot ?

Бот умеет расшифровывать голосовые сообщение в текст (STT) и передавать их в нейросеть и озвучивать сообщения от нейросети (TTS). Для TTS и STT сейчас используются сервисы Яндекса.


Стриминг, или любой аналог, нужен что бы юзер мог остановить долгую генерацию или остановить + продолжить то есть заново начать если юзер еще что то написал пока бот думал, но это сложно для реализации, не видел ни разу такое.

Давайте не будем путать сущности:)

Сам по себе стриминг это поток от LLM. Прерывание генерации возможно, если бот получает новый message и может отменить текущую задачу. "Продолжить с места остановки" - вот это да, проблема. LLM не умеет останавливаться посередине токена и продолжать с того же места.

То, что вы описываете, возможно сделать лишь через эмуляцию стриминга на стороне сервера. Это будет работать так:

1. Получаем полный ответ от LLM

2. Показываем его кусками через editMessageText с интервалом

3. Пауза/продолжение — просто управление таймером показа (кнопка в инлайн-клавиатуре)

Преимущества такого подхода:

- Полный контроль над показом (пауза, продолжение, ускорение)

- Легко отменить текущий показ при новом сообщении

- Не требует остановки LLM

Ограничения:

- Юзер всё равно ждёт полный ответ от LLM до начала "стриминга"

- Нельзя прервать саму генерацию, только показ готового текста

Именно в таком варианте можно реализовать остановку, паузу и продолжение показа сообщения в "стриминге".


ЗЫ Теперь бот сохраняет URL из входящих сообщений, но нейросеть по ним всё ещё не пойдёт:)

Платить не пробовали? Реально помогает, и цены - не то, чтобы космические.

Sign up to leave a comment.

Articles