PROJECT 02
LeadRadar — мониторинг
заказов с AI-скорингом
Сервис круглосуточно следит за 13 источниками, LLM отсеивает шум и оставляет только настоящие заявки, а нужное сразу прилетает в Telegram с кнопками и ложится в трекер. Ни один лид не теряется — даже если прогон упал на середине.
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 оказались мусором и были отсеяны — при этом ни одна настоящая заявка не потерялась.