← Назад к портфолио

PROJECT 02

LeadRadar — мониторинг
заказов с AI-скорингом

Сервис круглосуточно следит за 13 источниками, LLM отсеивает шум и оставляет только настоящие заявки, а нужное сразу прилетает в Telegram с кнопками и ложится в трекер. Ни один лид не теряется — даже если прогон упал на середине.

Python Telethon LLM-скоринг Telegram Bot API Google Sheets API Планировщик
2194
заявки оценены за сутки
13
источников в одном потоке
0
дублей и потерянных лидов
// задача

Заявки приходят отовсюду: несколько площадок, десяток тематических чатов, почта. Просматривать всё руками — час в день, и всё равно половина теряется: сообщение уехало вверх, о заявке вспомнили через сутки, когда её уже забрали. При этом 9 из 10 сообщений в таких источниках — не заявки вовсе: чужая реклама, резюме, флуд.

// как проходит один прогон
Сбор13 источников
Префильтрбез LLM
LLM-скорингзаявка? 0–10
Дедупатомарный state
ТрекерGoogle Sheets
Telegramс кнопками
🎯 Новая заявка · score 9/10
Источник: биржа проектов
Задача: Telegram-бот с интеграцией CRM
Бюджет: 45 000 ₽
Почему прошло: заказ от клиента, стек совпадает
Черновик ответа: подготовлен
Ответил
Поправлю сам
Пропустить
// решение

КАК УСТРОЕНО

  • Двухшаговый скоринг — модель сперва решает «это вообще заявка от клиента?», и только потом ставит балл релевантности
  • Дешёвый префильтр — очевидный мусор режется по ключевым маркерам до вызова модели, без трат на токены
  • Дедупликация между прогонами — состояние пишется атомарно, одна и та же заявка не придёт дважды
  • Устойчивость к сбоям — найденное сохраняется до обработки, упавший прогон подхватывает остаток на следующем запуске
  • Резервный провайдер — если основной LLM-провайдер недоступен, запрос уходит на запасной, поток не встаёт

ЧТО ЭТО ДАЁТ

  • Час ручного просмотра лент в день превращается в несколько уведомлений с готовым контекстом
  • Реакция на заявку — минуты вместо «вспомнил вечером»
  • Все лиды в одной таблице со статусной воронкой: новый → в работе → ответ получен
  • Решение об ответе всегда за человеком: бот присылает черновик и кнопки, сам ничего не рассылает
  • Тот же конвейер переносится на любые источники — тендерные площадки, заявки с сайта, мониторинг конкурентов
// ядро фильтра: сначала тип, потом релевантность
relevance.py — почему обычный скоринг не работает
# Шаг 0. Дешёвый отсев без LLM: реклама, резюме, приветствия
if has_marker(text, NON_ORDER_MARKERS):
    return Score(is_order=False, score=0, reason="prefilter")

# Шаг 1. Тип сообщения. Без этого шага порог проходили
# объявления самих исполнителей: "Нужен бот? Сделаю!"
prompt = f"""Сначала определи тип сообщения:
is_order = true  — клиент ищет исполнителя
is_order = false — самореклама, резюме, флуд, спам

Если is_order = false, поставь score = 0 и не рассуждай дальше.
Если true — оцени релевантность профилю от 0 до 10.

Сообщение: {text}
Ответ строго JSON: {{"is_order": bool, "score": int, "reason": str}}"""

# Шаг 2. Балл имеет смысл только для настоящих заявок
result = ask_llm(prompt, model=SCORING_MODEL)
return Score(**result) if result.is_order else Score(score=0)

Проверка на исторических данных: из 26 сообщений, ранее прошедших порог, 14 оказались мусором и были отсеяны — при этом ни одна настоящая заявка не потерялась.