Игорь Градов
Игорь Градов
6 мин
ai

Бот «Мигалка» обрабатывает 1000 каналов за секунды: LLM, векторные базы данных и PostGIS

Телеграм-бот «Мигалка» собирает сообщения примерно из тысячи телеграм-каналов и за секунды превращает их в адресные оповещения об опасности для конкретной локации пользователя, заменяя ручной мониторинг конвейером из LLM, векторной базы данных Qdrant и геокодирования через PostGIS.

Почему это важно

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

Разработчики бота «Мигалка» описали архитектуру системы, которая круглосуточно обрабатывает несколько сотен событий в день. Ключевая инженерная проблема: неструктурированный текст из сотен каналов нужно превратить в типизированные события с привязкой к месту, убрать дубли и доставить оповещение именно тем, кому оно релевантно. Ниже разбираю, из каких компонентов это собрано и как повторить подход.

Какие инструменты нужны для сборки?

  • Telegram-скрейпер для чтения каналов и складывания постов во входящую очередь
  • LLM с API (основная модель плюс резервная на случай сбоев) для извлечения структуры из текста
  • Qdrant (векторные базы данных для хранения эмбеддингов, то есть числовых «отпечатков» текста, по которым ищут смысловые совпадения)
  • PostgreSQL с расширением PostGIS для хранения событий, настроек пользователей и полигонов административных границ
  • Redis для входящей очереди сообщений и контроля скорости отправки (чтобы не упереться в лимиты Telegram API)
  • Google Maps API для геокодирования (превращения названия места в координаты и официальный адрес)
  • Данные OpenStreetMap с полигонами административных границ
  • Время на настройку промптов под каждую категорию опасности

Как устроен конвейер шаг за шагом?

  1. Скрейпер читает каналы. Отдельный сервис забирает новые посты из примерно тысячи телеграм-каналов и кладёт их в очередь Redis.

  2. LLM извлекает структуру. Каждое сообщение проходит через языковую модель, которая выполняет сразу несколько задач в одном вызове:

Задачи LLM на каждое сообщение:

- Проверить релевантность публикации выбранной теме
- Извлечь пары «регион + локация» (один пост может описывать события в нескольких городах)
- Сформулировать краткое описание для пользователя
- Проверить: событие действительно произошло в указанном месте или место лишь упомянуто в тексте

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

  1. Промпты хранятся в базе. Промпты (инструкции для модели) настраиваются отдельно для каждой категории опасности и лежат в PostgreSQL. Их меняют без правки кода, поэтому добавление новой категории сводится к настройке инструкций и схемы результата.

  2. Обработка сбоев LLM. Для вызовов модели предусмотрены тайм-ауты, резервная модель и повторные попытки с экспоненциальной задержкой (каждая следующая попытка ждёт дольше предыдущей). Внешний API может отвечать медленно, быть временно недоступным или вернуть результат, не соответствующий ожидаемой схеме.

  3. Дедупликация через векторные базы данных. Одно событие за короткое время описывают десятки каналов. Сравнивать тексты напрямую бесполезно: «взрывы в районе промзоны» и «работа ПВО над городом» могут описывать одно и то же. Поэтому дедупликация двухуровневая:

  4. Сначала эмбеддинги (числовые представления смысла текста) в Qdrant быстро отбирают потенциально похожие события по семантической близости. Дословное совпадение не требуется.

  5. Затем отдельно сравниваются локации: семантически одинаковые сообщения из разных городов объединять нельзя.

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

  1. Геокодирование привязывает текст к карте. LLM возвращает строку вроде «Шебекино». Дальше её нужно превратить в точку на дереве административных границ:

  2. Название проходит через Google Maps API. Геокодер нормализует его и возвращает официальное название, регион, город и координаты. Если в посте написано «ТЦ Европейский», сервис поймёт, что это Москва, и определит точный адрес.

  3. По нормализованным данным ищется соответствующая территория среди полигонов OpenStreetMap в PostGIS. Цепочка административных уровней хранится в PostgreSQL как ltree (древовидная структура «Россия, Краснодарский край, Сочи, Центральный район»).

Сравнивать названия как строки неудобно: «Шебекино» и «Шебекинский городской округ» относятся к одной территории, а одинаковые названия встречаются в разных регионах. Дерево границ решает обе проблемы.

  1. Подбор получателей и доставка. Пользователь при настройке бота указывает локацию (от целого региона до района в городе) и категории опасности. Система сопоставляет дерево локации события с деревом локации пользователя и ставит оповещение в очередь доставки в PostgreSQL. Redis управляет скоростью отправки, чтобы не превысить лимиты Telegram.
Как это выглядит на практике

Десять телеграм-каналов за три минуты публикуют сообщения о работе ПВО в Белгородской области. Формулировки разные: «громкие хлопки в районе Шебекино», «работа ПВО, Белгородская область», «над Шебекинским округом сбит дрон». Конвейер извлекает из каждого поста категорию «воздушная опасность» и локацию «Шебекино». Qdrant по эмбеддингам находит, что все десять сообщений семантически близки, PostGIS подтверждает совпадение по географии. Пользователь, подписанный на оповещения по Белгородской области, получает одно сообщение с кратким описанием и десятью источниками, а не десять одинаковых уведомлений.

Что делать с этим прямо сейчас, по ролям

Разработчику бота или сервиса оповещений. Связка LLM плюс Qdrant плюс PostGIS воспроизводима на любом потоке неструктурированных сообщений. Ключевой приём: хранить промпты в базе, а не в коде, тогда новые категории событий добавляются без деплоя.

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

Предпринимателю в РФ. Все компоненты доступны: Qdrant — опенсорс (открытая модель векторной базы данных, которую можно развернуть на своём сервере), PostgreSQL и PostGIS свободны, Redis свободен. Для LLM можно использовать как зарубежные API, так и российские модели. Google Maps API работает, но при ограничениях можно заменить на Nominatim (открытый геокодер на данных OpenStreetMap).

Частые ошибки

Нет резервной модели. Если LLM-провайдер лёг на пять минут, без фолбэка система перестаёт обрабатывать сотни постов. Обязательно настройте запасную модель и повторные попытки с экспоненциальной задержкой.

Дедупликация только по тексту. Без проверки географии система объединит «взрывы в Шебекино» и «взрывы в Курске» как один инцидент, потому что тексты семантически близки. Второй уровень с проверкой локации не опционален, а обязателен.

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

Игнорирование лимитов Telegram. Без контроля скорости отправки через Redis бот быстро упрётся в лимиты API и перестанет доставлять сообщения.

Мнение редакции dzen.guru

Архитектура «Мигалки» ценна не экзотическим стеком, а тем, что каждый компонент решает конкретную проблему: LLM превращает хаос в структуру, векторные базы данных (Qdrant) убирают дубли без дословного сравнения, PostGIS привязывает текст к карте. По моим наблюдениям, большинство попыток собрать подобную систему спотыкаются именно на дедупликации: без двухуровневой проверки (семантика плюс география) пользователь либо тонет в повторах, либо теряет разные события из похожих сообщений. Честная оговорка: система работает без постоянной ручной модерации, но LLM может галлюцинировать (уверенно выдумывать то, чего не было). В критичных для безопасности сценариях стоит добавить механизм, где пользователи проверяют сообщения друг друга, что авторы «Мигалки» и сделали.

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

Поделиться:TelegramVK
Игорь Градов
Игорь Градов

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».

Комментарии

Читайте также

Как отключить Gemini на телефоне как голосовой помощник и настроить его для быта
ai

Как отключить Gemini на телефоне как голосовой помощник и настроить его для быта

Google Gemini уже умеет помогать не только на работе, а и в быту: от диагностики сломанного крана до списка продуктов по содержимому холодильника, и 4 июня…

6 мин
Gemini Notebook записывает лекции и делает квизы на 100 языках: гайд для студентов
ai

Gemini Notebook записывает лекции и делает квизы на 100 языках: гайд для студентов

Gemini Notebook получил голосовой ввод лекций, разговор с конспектами на ~100 языках и аудиозапись прямо в мобильном приложении, и всё это уже можно применить…

6 мин
ai

Визуально-языковые модели за $200: разработчик собрал VLM на 628 млн параметров на одной GPU

Разработчик из сообщества открытых моделей собрал визуально-языковую модель на базе французской Baguettotron и визуального энкодера InternViT за 200 долларов…

6 мин