Эфир 18.11 · Поток 318 ноября в 19:00 МСК — бесплатный практический эфир по ИИ-агентам · Живой Поток 3 стартует 23.11Эфир 18 ноября →Поток 3 (23.11)
Безопасность и правоAPI / Продукт · В работуHabr AI→ оригинал

Агент закончил, а Telegram лежит: очередь доставки в agent-hub на Rust

Когда агент уже закончил работу, а Telegram недоступен, повторять запрос к модели нельзя: это стоит токенов и может снова изменить файлы. Автор agent-hub на Rust разделил получение результата и его доставку. Финальный текст сначала пишется на диск, а отдельная задача отправляет его частями и повторяет после сбоя или перезапуска.

AI-обработка оригинала Habr AI; редакция Hamidun News
Агент закончил, а Telegram лежит: очередь доставки в agent-hub на Rust
Источник: Habr AI. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникHabr AI ↗
Главный редактор
Ключевой факт #1Ответ хранится в файле заранее разбитым на части с прогрессом
Ключевой факт #2Пауза между повторами растёт с 5 до 600 секунд
Ключевой факт #3Дубликаты возможны, поэтому у каждой части есть ID хода и номер

Знакомая ситуация: агент прочитал код, поправил файлы, проверил результат и написал отличный ответ. А в этот момент Telegram недоступен. Для агента работа закончена, для пользователя не произошло ничего. Запускать задачу заново не хочется: это время, токены и риск, что агент снова что-то изменит. Именно с этим столкнулся автор agent-hub, приложения на Rust, которое запускает AI-агентов локально и общается с ними через темы Telegram-группы.

Разделить результат и доставку

Главная идея простая: получение ответа и его отправка — два разных события. Когда ход агента успешно завершён, хаб сначала сохраняет финальный текст в локальный файл topics.results.json и ставит его в очередь, и только потом обращается к Telegram. Отдельная задача занимается отправкой и повторами. После перезапуска она читает состояние с диска и продолжает доставку без нового вызова модели.

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

Важная деталь: хаб хранит уже подготовленные части, а не исходный Markdown. Если после обновления приложения изменится преобразование разметки, границы сообщений останутся прежними, и сохранённый номер следующей части не поедет на другой кусок текста.

Как это переживает сбои

Цикл такой: найти готовую запись, зарезервировать её на 60 секунд и сохранить это на диск, отправить текущую часть, записать подтверждение, перейти к следующей. Резервирование нужно на случай, если процесс оборвётся посреди сетевого запроса: запись не останется занятой навсегда. Запрос к Telegram ограничен 20 секундами, отправка идёт не чаще одной части в секунду.

При временной ошибке паузы растут: 5, 15, 30, 60, 120, 300, 600 секунд. После восьми неудач подряд доставка останавливается до ручного повтора. Если Telegram сам просит подождать (RetryAfter), эта пауза хранится для очереди всей группы и не сокращается ни ручным повтором, ни перезапуском. Если Telegram отклонил HTML, хаб пробует отправить обычный текст, а если и он не прошёл, ждёт вмешательства человека.

Управлять очередью можно из темы: /last показывает последний сохранённый ответ без вызова модели, /outbox — ожидающие доставки с кнопками «Повторить» и «Удалить». В интерфейсе при ошибке чтения хранилища показывается «неизвестно», а не ноль, чтобы сбой диска не выглядел как пустая очередь.

Где гарантии заканчиваются

Автор честно не обещает доставку ровно один раз. Telegram мог принять сообщение, а подтверждение потерялось; или хаб не успел записать его на диск до остановки. Тогда часть уйдёт повторно. Поэтому в начале каждой части стоит ID хода и номер вроде «часть 2/3»: метка не убирает дубликат, но показывает, что это повтор, а не новый ответ.

Есть и жёсткие лимиты: до 50 ожидающих ответов и 8 МиБ в очереди, хранение до 7 дней, до 64 КиБ на один текст. Если очередь полна, старые записи не вытесняются, а новый ответ отправляется без автоповтора и с предупреждением. Файл создаётся с правами 0600, но в нём лежат ответы агента, так что о бэкапах стоит помнить.

Тесты шли на Linux с подменой Telegram и временным хранилищем: недоступная сеть, перезапуск после частичной отправки, потеря подтверждения, RetryAfter, ошибка HTML, переполнение, смена группы. Отключение питания не моделировали.

Что забрать себе

Паттерн универсален для любого агентного инструмента: сохраняйте результат до доставки, храните прогресс по частям, давайте повторам идентификаторы и не обещайте exactly-once там, где его нет. Это по сути маленький outbox-паттерн, знакомый по бэкенду, только для агентов, где повторный запуск дорог и небезопасен. Код открыт под MIT.

Сюжет

Вопросы и ответы по материалу

Что известно по теме: разделить результат и доставку?

Главная идея простая: получение ответа и его отправка — два разных события. Когда ход агента успешно завершён, хаб сначала сохраняет финальный текст в локальный файл topics.results.json и ставит его в очередь, и только потом обращается к Telegram. Отдельная задача занимается отправкой и повторами. После перезапуска она читает состояние с диска и продолжает доставку без нового вызова модели. В очередь попадает не вся переписка, а последовательные текстовые блоки после последнего отображаемого вызова инструмента.

Что известно по теме: как это переживает сбои?

Цикл такой: найти готовую запись, зарезервировать её на 60 секунд и сохранить это на диск, отправить текущую часть, записать подтверждение, перейти к следующей. Резервирование нужно на случай, если процесс оборвётся посреди сетевого запроса: запись не останется занятой навсегда. Запрос к Telegram ограничен 20 секундами, отправка идёт не чаще одной части в секунду. При временной ошибке паузы растут: 5, 15, 30, 60, 120, 300, 600 секунд. После восьми неудач подряд доставка останавливается до ручного повтора.

Что известно по теме: где гарантии заканчиваются?

Автор честно не обещает доставку ровно один раз. Telegram мог принять сообщение, а подтверждение потерялось; или хаб не успел записать его на диск до остановки. Тогда часть уйдёт повторно. Поэтому в начале каждой части стоит ID хода и номер вроде «часть 2/3»: метка не убирает дубликат, но показывает, что это повтор, а не новый ответ. Есть и жёсткие лимиты: до 50 ожидающих ответов и 8 МиБ в очереди, хранение до 7 дней, до 64 КиБ на один текст.

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Единое AI-пространство · Nomad

Протестируйте новые LLM и мультимодальные модели в одном окне

Платформа Nomad AI (nomadnet.ai) даёт прямой доступ к Claude Opus 5.5, GPT-6, Gemini 3.1, DeepSeek и автономным агентам без VPN, зарубежных карт и зоопарка подписок.

Открыть Nomad AI →Автономный Nomad Agent
Что вы думаете?
Загружаем комментарии…