Всем привет! Вероятно, у каждого бывало: ты открываешь Телеграм-чат, а там тысячи новых сообщений за день. И где-то внутри этой «солянки» важный ответ на твой вопрос или обсуждение нужной темы. Или вам нужно отслеживать определённые сообщения для бизнес-целей.
Можно, конечно, потратить кучу времени на ручной поиск, но намного интереснее научить юзербота самостоятельно парсить историю чата и составлять из неё удобную базу для поиска по смыслу.
Здесь в дело вступает связка из векторной базы Qdrant и LLM:
Юзербот собирает сообщения и превращает их в эмбеддинги.
Qdrant хранит эти векторы и по запросу вытаскивает только самые близкие фрагменты.
LLM получает именно эти куски и формулирует итоговый ответ человеческим языком.
Если какой-то из терминов для вас непонятен, рекомендуем ознакомиться с нашими прошлыми статьями про работу с Qdrant. Ссылки на них будут предоставлены в конце статьи.
В этой статье разберёмся, как создать такое приложение: от простейшего парсинга чата до поиска по смыслу с помощью LLM.
В чём суть работы по парсингу Telegam через бота
Когда мы говорим «поиск по смыслу», важно понимать, что это не магия, а вполне конкретная цепочка шагов.
Давайте разберёмся со всем по порядку:
1. Сбор сообщений
Первый этап — это юзербот (например, на Telethon). Он подключается к вашему аккаунту Telegram и «слушает» выбранные чаты. Как только приходит новое сообщение, бот его сохраняет. При желании можно догрузить и старую историю, но чаще всего достаточно обрабатывать новые входящие.
Почему именно юзербот? Обычный бот не имеет доступа к истории чата (он видит только то, что пишут при нём). А юзербот = вы сами, только в виде программы, значит, у него полный доступ ко всем сообщениям.
2. Превращение текста в векторы (эмбеддинги)
Чтобы компьютер умел «понимать смысл» сообщений, нужно превратить текст в числовое представление.
Это и есть эмбеддинги — набор чисел (вектор), который описывает не форму слов, а их значение.
Пример:
«ошибка при оплате» и «не проходит платеж» — разные наборы слов, но их векторы окажутся близки друг к другу, потому что смысл одинаковый.
А вот «сегодня была хорошая погода» будет где-то далеко, потому что тематика другая.
Сейчас есть куча моделей для эмбеддингов: от OpenAI (text-embedding-3-small
) до полностью локальных (e5-base
, mxbai-embed-large
).
3. Хранение в Qdrant
Все полученные векторы мы складываем в векторную базу Qdrant. Она заточена именно под такие данные: быстро ищет ближайшие векторы среди миллионов записей.
Каждое сообщение в базе хранится с нашими настраиваемыми метаданными:
id
сообщения;сам текст;
автор (можно анонимизировать);
дата и время.
Это значит, что в любой момент мы можем спросить: «Дай мне самые похожие на это сообщение куски чата» и Qdrant найдёт их за миллисекунды.
4. Запрос пользователя
Теперь представим, что вы хотите узнать: «Какие цвета обсуждали вчера?»
Ваш вопрос точно так же превращается в вектор и отправляется в Qdrant.
База ищет самые близкие по смыслу фрагменты чата и возвращает их (например, 5–10 штук).
5. Обработка в LLM
И уже наступает время большой языковой модели (LLM).
Мы берём найденные фрагменты и подкладываем их в промпт:
Вопрос: "Какие цвета обсуждали вчера?"
Контекст из чата:
1) [12:30] user1: Мой любимый цвет — черный
2) [12:35] user2: Думаю перекрасить сайт в синий, будет посвежее
3) [12:40] user3: Я за зелёный, он спокойнее смотрится
4) [12:50] user4: Красный лучше привлекает внимание
...
Сформулируй ответ кратко и по делу.
LLM видит только этот маленький кусок контекста, а не весь чат целиком, и формулирует итог:
«Вчера обсуждали несколько цветов: чёрный, синий, зелёный и красный.»
6. Что мы получаем в итоге
Никаких километров скроллинга.
Ответ приходит в человеческом виде.
При желании можно прикладывать ссылки на оригинальные сообщения, чтобы проверить контекст, но пока будет достаточно времени.
Таким образом, LLM никогда не падает под весом тысячи сообщений: она работает только с выборкой, которую заранее подготовил Qdrant.
Дополнительно: могут ли за это забанить?
Технически Telegram не одобряет использование юзерботов, так как это доступ к аккаунту через неофициальные клиенты. Но на практике за чтение истории и хранение сообщений риска почти нет. Миллионы людей используют Telethon и Pyrogram. Бан чаще прилетает за спам или агрессивную активность. Для спокойствия можно завести отдельный аккаунт под юзербота, чтобы не рисковать основным.
Где развернем парсер
На помощь в развертывании нам приходит Amvera — сервис для простого и быстрого деплоя IT-приложений.
Сервис при регистрации предоставляет бонусные 111 рублей без дополнительных условий. Это дает нам возможность без страха тестировать приложение, дорабатывать его и даже некоторое время покрутить бесплатно.
Сервис также предоставляет бесплатное проксирование до OpenAI, Gemini, Grok AI и множества других сервисов, имеющих региональные ограничения.
Недавно в Amvera появилась возможность подключить инференс LLM LLaMA, что освобождает нас от нужны покупать через иностранные карты токены от того же OpenAI. Как раз его мы используем для обработки сообщений.
Приложение достаточно легко развернуть: достаточно лишь настроить несколько параметров в конфигурации и выполнить 4 команды в термиле для загрузки файлов через git push (и то можно обойтись без них - есть возможность загружать файлы через интерфейс).
Qdrant (как преднастроенный сервис) и юзербота мы развернем именно здесь. Также подключим инференс LLaMA от Amvera.
Почему это важно: удобно, когда доступ ко всем сервисам вашего приложения (в нашем случае - LLM, Qdrant и сам юзербот) лежит на одном аккаунте, а не на множестве разных.
Практическая часть: собираем MVP бота-парсера Telegram
Чтобы не углубляться в тонкие настройки, сделаем минимальный рабочий пример:
юзербот читает сообщения из чата;
превращает их в эмбеддинги;
складывает в Qdrant;
а потом по запросу достаёт релевантные куски и отдаёт их в LLM.
Само приложение будет запускаться как два отдельно живущих модуля, выполняющие свои функции. Первый — bot.py
будет собирать все новые входящие сообщения. Второй (search.py
) — выполнять поиск по ним.
1. Зависимости
В requirements.txt
добавим:
telethon==1.36.0
qdrant-client==1.12.1
httpx==0.27.2
python-dotenv==1.0.1
sentence-transformers==5.1.0
2. Переменные окружения
Рекомендуется все важные и секретные данные, такие как токен от ботов и пароль к Qdrant хранить в переменных окружения. В Amvera, где мы развернем наш сервис, это вкладка «Переменные».
Для данного проекта у нас используются следующие переменные:
API_ID = 123456
API_HASH = your_api_hash
SESSION_PATH = /data/tg.session # Сохраняем
QDRANT_URL = http://localhost:6333
QDRANT_COLLECTION = chat_messages
LLM_BASE_URL = https://kong-proxy.yc.amvera.ru/api/v1/models/llama
LLM_API_KEY = ключ
LLM_MODEL = llama70b
PYTHONUNBUFFERED = 1
Следить за актуальными методами можно в свагере
2.1. Как получить API_ID и API_HASH для юзербота
Чтобы юзербот мог подключаться к вашему аккаунту Telegram, нужны специальные ключи:
API_ID
API_HASH
Их можно получить на официальном сайте Telegram для разработчиков:
Зайдите на my.telegram.org под своим аккаунтом Telegram.
Выберите пункт API development tools.
Введите название приложения (можно любое, например
chat-search
), короткое имя и заполните форму.После сохранения появятся ваши
API_ID
иAPI_HASH
.
3. Юзербот на Telethon
import os, asyncio
from dotenv import load_dotenv
from telethon import TelegramClient, events
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct
from sentence_transformers import SentenceTransformer
import httpx
load_dotenv()
API_ID = int(os.getenv("API_ID"))
API_HASH = os.getenv("API_HASH")
SESSION_PATH = os.getenv("SESSION_PATH", "session")
QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6333")
COLLECTION = os.getenv("QDRANT_COLLECTION", "chat_messages")
LLM_BASE_URL = os.getenv("LLM_BASE_URL")
LLM_API_KEY = os.getenv("LLM_API_KEY")
LLM_MODEL = os.getenv("LLM_MODEL")
client = TelegramClient(SESSION_PATH, API_ID, API_HASH)
qdrant = QdrantClient(url=QDRANT_URL)
embedder = SentenceTransformer("intfloat/e5-small")
# создаём коллекцию (один раз)
try:
qdrant.get_collection(COLLECTION)
except:
qdrant.create_collection(
collection_name=COLLECTION,
vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)
async def embed_text(text: str):
return embedder.encode(text).tolist()
@client.on(events.NewMessage)
async def handler(event):
# Рекомендуем добавить условие для проверки чата. В данной реализации сохраняются все сообщения
text = event.message.message
if not text:
return
emb = await embed_text(text)
point = PointStruct(
id=event.message.id,
vector=emb,
payload={"text": text, "chat_id": event.chat_id}
)
qdrant.upsert(COLLECTION, points=[point])
print(f"Сохранили сообщение: {text[:50]}...")
async def main():
await client.start()
print("Юзербот запущен")
await client.run_until_disconnected()
if __name__ == "__main__":
asyncio.run(main())
4. Поиск по смыслу + LLM ответ
В отдельном файле search.py
:
import os
import asyncio
import httpx
from dotenv import load_dotenv
from qdrant_client import QdrantClient
from sentence_transformers import SentenceTransformer
load_dotenv()
QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6333")
QDRANT_COLLECTION = os.getenv("QDRANT_COLLECTION", "chat_messages")
LLM_BASE_URL = os.getenv("LLM_BASE_URL") # например: https://kong-proxy.yc.amvera.ru/api/v1/models/llama
LLM_API_KEY = os.getenv("LLM_API_KEY")
LLM_MODEL = os.getenv("LLM_MODEL", "llama8b")
qdrant = QdrantClient(url=QDRANT_URL)
embedder = SentenceTransformer("intfloat/e5-small")
def embed_text(text: str):
return embedder.encode([text], normalize_embeddings=True).tolist()[0]
async def llm_answer(question, context):
headers = {
"X-Auth-Token": f"Bearer {LLM_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": LLM_MODEL,
"messages": [
{"role": "system", "text": "Ты помогаешь находить важное в чате. Отвечай коротко, по делу. На русском языке"},
{"role": "user", "text": f"Вопрос: {question}\nКонтекст:\n{context}"}
]
}
async with httpx.AsyncClient(timeout=120.0) as http:
r = await http.post(LLM_BASE_URL, headers=headers, json=payload)
r.raise_for_status()
data = r.json()
return data["choices"][0]["message"]["text"]
async def search(question):
vec = embed_text(question)
results = qdrant.search(collection_name=QDRANT_COLLECTION, query_vector=vec, limit=5)
context = "\n".join([p.payload["text"] for p in results])
answer = await llm_answer(question, context)
print("Вопрос:", question)
print("Ответ:", answer)
if __name__ == "__main__":
q = input("Введите вопрос: ")
asyncio.run(search(q))
Пример входных выходных данных.
Вопрос: "Какие цвета обсуждали вчера?"
Контекст из чата:
1) [12:30] user1: Мой любимый цвет — черный
2) [12:35] user2: Думаю перекрасить сайт в синий, будет посвежее
3) [12:40] user3: Я за зелёный, он спокойнее смотрится
4) [12:50] user4: Красный лучше привлекает внимание
...
Сформулируй ответ кратко и по делу.
5. Как это работает вместе
Запускаем
bot.py
— юзербот слушает чат и сохраняет все новые сообщения в Qdrant.Запускаем
python
search.py
— вводим вопрос, получаем ответ от LLM.Дополнительно потребуется развернуть базу данных (Qdrant в нашем случае) и подключить LLM по API.
Пример:
Вопрос: Какие цвета обсуждали вчера?
Ответ: Вчера обсуждали несколько цветов: чёрный, синий, зелёный и красный.
Деплой парсера Telegram
Итак, когда у нас уже будет готова база юзербота и всего необходимого функционала, нам нужно будет где-то развернуть все сервисы.
Разберем всё по очереди.
Регистрация
Первое, что потребуется — завести аккаунт в Amvera.
После быстрой регистрации (почта) вы сразу получаете бонусные 111 рублей на баланс. Этого достаточно, чтобы:
протестировать юзербота;
погонять Qdrant;
приобрести тестовый пакет токенов для LLM.
Создание проекта с Qdrant
Прежде чем запускать юзербота, стоит подготовить хранилище — базу Qdrant. В Amvera это можно сделать буквально в несколько кликов.
Откройте панель проектов.
Нажмите «Создать проект».
В поле Тип сервиса выберите «Преднастроенное приложение из маркетплейса».
В разделе Задайте параметры сервиса откройте категорию Базы данных.
В списке выберите Qdrant.
Жмем «Далее», в новом окне выбираем название проекта и тариф.
Снова «Далее», задаем версию Qdrant. Рекомендуется оставить ту, что будет указана по умолчанию. Завершаем создание

После этого сервис автоматически развернется, и у вас будет готовая векторная база, к которой можно подключать бота.
Как адрес для подключения используем внутреннее доменное имя, доступное во вкладке "Инфо" проекта. Сам же проект будет доступен в блоке «Преднастроенные сервисы».
Получение токена Amvera LLM Inference API
Осталась последняя зависимость нашего проекта - LLM. Мы будем использовать модель llama70b
LLaMA.
Список доступных моделей доступен в документации;
Доступные методы описаны в Swagger
Для подключения прежде всего необходимо приобрести пакет токенов. Для этого переходим в блок «LLM (Preview)», выбираем нужную модель и жмём соответствующую кнопку.

Выберем любой тариф, на первый раз можно использовать «20000 токенов бесплатно на месяц (однократно)».
После приобретения пакета, открываем страницу модели и во вкладке "Инфо" перевыпускаем и копируем токен.
Деплой юзербота
Теперь, когда все зависимости доступны, мы можем развернуть наше приложение как отдельный проект. Для этого также открываем панель проектов и жмём «Создать проект».
В поле Тип сервиса выберите «Приложение». Жмём «Далее».
Задаем название проекта и выбираем тариф. Рекомендуется использовать «Начальный» или «Начальный плюс».
На следующем этапе будет доступна загрузка данных. Вы можете как использовать Git, так и загрузку через интерфейс. На данный момент пропустим загрузку.
На этапе создания «Переменные» рекомендуется прописать все переменные окружения, которые мы задавали ранее.
Следующий этап пропускаем - конфигурацию создадим после загрузки кода. Завершаем создание проекта и открываем его.
Если вы планируете вдальнейшем переодически обновлять проект, мы рекомендуем использовать Git как способ загрузки данных. Если же обновлений не планируется — можно загрузить через интерфейс.
Загружаем данные проекта (вместе с requirements.txt
) любым удобным способом, убеждаемся в том, что переменные окружения созданы и переходим во вкладку «Конфигурация».
Во вкладке конфигурации мы можем сгенерировать amvera.yml
- файл с инструкциями для сборки проекта. Подробнее можно прочитать в документации.
Для Python-проекта выбираем окружение Python и инструмент Pip. В version
задаем версию Python, указываем в scriptName
название запускаемого .py файла.
В моем случае конфигурация выглядит так:

Сохраняем конфигурацию и жмём кнопку сборки.
После выполненных действий ожидаем сборку и если все пройдет без ошибок — проект запустится и будет работать.
Нюанс запуска
Важно, что доступа к консоли проекта нет. Поэтому возможности указать номер телефона и код от Telegram для запуска сессии нет.
Однако, это все достаточно легко обойти, загрузив файл сессии в репозиторий проекта по пути, который мы указывали ранее в переменной SESSION_PATH
переменных окружения.
Тут /data
— пусть к постоянному хранилищу Amvera. В нашем случае его использовать не обязательно, т.к. файл сессии неизменяемый. Но все изменяемые в процессе работы приложения файлы необходимо сохранять в постоянное хранилище Data, иначе после каждой пересборки/перезапуска файлы обнулятся. Это относится к любым файлам, будь то .txt или файл базы SQLite.
Подробнее здесь: https://docs.amvera.ru/applications/storage.html#data
Ни в коем случае не публикуйте файл сессии в GitHub или любые другие Git-сервисы, если будете использовать их для деплоя!
Это только пример парсинга каналов, групп и чатов Telegram через бота
Мы показали самый простой pipeline, который можно собрать на Python, Qdrant и LLaMA. Такой код работает, но это больше учебный каркас, чем готовое приложение на прод.
Почему так:
у каждого проекта разный масштаб (от маленькой группы до корпоративного чата на сотни тысяч сообщений);
разные требования к приватности (где-то можно хранить историю целиком, где-то нужно анонимизировать авторов или чистить персональные данные);
разные модели эмбеддингов и LLM дают разные результаты (одни лучше подходят для коротких сообщений, другие для длинных диалогов).
Поэтому не следует воспринимать пример как последнее слово техники. Гораздо полезнее взять этот шаблон и попробовать самим.
Релевантные статьи
Комментарии (8)
PashaPodolsky
31.08.2025 12:13У Телеграма в связке с RAGом хороший потенциал. Я несколько месяцев назад с другого конца решил зайти и добавил в себе в поисковик кроулинг и индексацию публичных каналов. Ссылка есть в профиле, если интересно.
Данные из телеги могут хорошо отвечать на запросы свежести, типа новостей, на локальные запросы - а-ля "рестораны в Москве", "события в Берлине", и на OSINT - тут все понятно. Внезапно интересным оказался кейс поиска вакансий - в каналах много чего постится, о чем на сайтах не пишут. В итоге, одним поисковым запросом удается выгрести вакансий за фиксированный период больше, чем показывают профильные сайты.
Короче, данные в Телеге хорошие, осталось только AI правильно приложить.
Kahelman
31.08.2025 12:13Что-то из серии как нарисовать сову….
Как юзер бота-то сделать?
MarkovM Автор
31.08.2025 12:13Как пример, вот как в этой статье - https://habr.com/ru/companies/amvera/articles/838204/
Zakhir
31.08.2025 12:13Получится ли использовать описанный инструмент для оптимизации времени ознакомления с новостями. Пример так - за меня новости в епнпла читает userbot, а я могу задать вопрос - самая часто встречающая новость тут топ 5 по упоминаемости
Artiik
31.08.2025 12:13Ну по сути там сказано что сообщения обрабатываются и даётся нормальный ответ с человеческим языком, то есть можно сказать что там мини -нейросеть и если всё сообщение удастся впихать то да
Artiik
31.08.2025 12:13А получается он сможет автоматически собирать сообщения в кучку пока люди пишут и потом обрабатывать информацию с нескольких чатов?
NikitinIlya
Данный бот-парсер телеграма подойдет для использования в качестве антиспама/модератора?
MarkovM Автор
Как основу использовать можно, но если сообщений много, будет дорого за счет API LLM. Для такого лучше использовать что-то более специализированное. Как пример вот из этой статьи.