Люди проговаривают свои потребности вслух. Человек пишет в городском чате «переезжаю в Анталью в сентябре, есть нормальный агент, который отвечает?», получает три ответа от своих — и в поисковик не идёт вообще. Спрос существовал часа четыре и исчез.
Поймать его — это задача классификации до того, как она станет задачей лидогенерации. Ниже — пайплайн, который мы для этого построили: что в нём ломается, сколько это стоит и как понять, что он работает.
Настоящая задача: «мне это нужно» против «я это делаю»
Наивная постановка звучит как «найти сообщения про недвижимость». Она даёт бесполезный продукт: в любом чате по теме большинство говорящих о теме её продаёт.
Четыре сообщения с одинаковой лексикой:
| Сообщение | Вердикт |
|---|---|
| «Ищу 2+1 в Коньяалты, бюджет 30к, длительно» | запрос |
| «Есть 2+1 в Коньяалты от 28к, пишите в личку» | исполнитель |
| «А сколько сейчас стоит 2+1 в Коньяалты?» | интерес, ещё не запрос |
| «2+1 Коньяалты 30к 🔥🔥 ссылка в профиле» | реклама |
Фильтр по ключевым словам оценит все четыре одинаково. У него просто нет представления о разнице между «хочу» и «предлагаю» — эта разница живёт в намерении фразы, а не в её существительных. Ровно поэтому боты с алертами по словам ощущаются как поток мусора: они отвечают не на тот вопрос, который задал пользователь.
Значит, задача — не поиск. Задача — классификация по определению запроса, своему для каждой ниши. И это определение и есть продукт.
Почему предфильтр — не оптимизация, а условие существования
Возьмите пару сотен живых публичных источников. Это десятки тысяч сообщений в сутки, и число растёт линейно с каждым новым источником.
Гнать всё это через языковую модель — то место, где тихо умирает большинство проектов в категории. Арифметика беспощадна: расходы растут вместе с общим объёмом чатов, а выручка — вместе с числом доставленных лидов, которые составляют от этого объёма доли процента. Добавление источников ради полноты делает экономику хуже, а не лучше. Вы платите за то, чтобы модель десять тысяч раз в день прочитала «дд».
Поэтому первая ступень — дешёвый детерминированный фильтр, отсекающий 90–95% потока до любого вызова модели: длина и структура, лексическая близость к словарю ниши, очевидный мусор (стикеры, одиночные эмодзи, приветствия, пересланная реклама), дешёвые признаки автора. Никаких эмбеддингов, никакой модели, никаких сетевых вызовов.
Два свойства здесь важнее конкретных правил:
- Он настраивается на полноту, а не на точность. Единственная задача предфильтра — не выбросить настоящий запрос. Пропустить сомнительный мусор стоит доли цента; выбросить живой запрос стоит всего продукта, и вы об этом даже не узнаете.
- Он должен измеряться отдельно. Логируйте отсев и регулярно просматривайте выборку руками. Предфильтр, который начал молча съедать неожиданный формат сообщений — новый сленг, чат, перешедший на расшифровки голосовых, — невидим во всех метриках ниже по потоку. Лидов становится меньше, а все дашборды показывают, что система здорова.
Те 5–10%, что выжили, и читает модель.
Классификатор: ниша — это конфиг, а не промпт
Выжившие сообщения уходят в языковую модель вместе с определением ниши: словарь, явная формулировка того, что в этом бизнесе считается запросом, и контрпримеры — что похоже, но запросом не является.
Ключевое проектное решение: это определение — файл конфигурации, а не код и не промпт, написанный под каждого клиента отдельно. Новый рынок — новый город, новая услуга, новый язык — это новый конфиг: словарь, определение лида, список источников. Ничего не пересобирается и не выкатывается.
Это ограничение стоит защищать, даже когда частный случай быстрее закрыть кодом, и вот почему. Коммерчески — это честный ответ на вопрос «а по моей теме работает?»: работает, если мы можем написать определение, и мы за сутки скажем, можем или нет. Операционно — то, что вы правите при падении качества, оказывается текстовым файлом, который видно в диффе, а не веткой логики внутри классификатора.
Модель возвращает вердикт и причину. Хранить причину — не украшательство: когда приходит жалоба на плохой лид, строка причины за секунды показывает, что именно сломалось — определение, слишком широкий словарь или модель просто неверно прочитала сообщение. У этих трёх поломок три разных лечения.
Дедупликация, редактирования и скучные места, которые решают всё
Между «модель сказала да» и «человек это увидел» лежит слой, который выглядит неинтересно и наносит основной ущерб, когда сделан неправильно.
Дедуп по сообщению, а не по тексту. Уникальный индекс по (chat_id, message_id) — это пол, а не потолок. Люди ещё и кросс-постят один и тот же запрос в пять чатов: это один человек, и доставить его пять раз — превратить короткую ленту в спам.
Редактирование — исключение из дедупа. Очень частый сценарий: человек пишет «ищу виллу», а через двадцать секунд дописывает бюджет и даты. Если правки отсекаются ключом дедупликации, вы доставите бесполезную первую версию и никогда не увидите нормальную. Сообщения, отредактированные в коротком окне, переклассифицируются, и результат обновляет существующий вердикт, а не создаёт второй.
Задержка — почти никогда не модель. Цель «меньше минуты» тратится на чтение, очередь, вызов модели и доставку, а когда она срывается — виновата обычно очередь, забитая всплеском в одном крупном чате, а не инференс. Меряйте стадии по отдельности, иначе будете оптимизировать не то.
Как это измеряется: точность, полнота и обратная связь
Два числа, и они торгуются друг против друга.
Точность (precision) — какая доля доставленных лидов оказалась настоящими запросами. Наша цель — 80%. Мы называем это число вслух вместе с тем, что оно означает: примерно каждый пятый будет мимо. Продавец, обещающий 99%, либо работает в очень узкой нише, либо считает не так, как вы.
Полнота (recall) — какую долю реальных запросов, появившихся в источниках, мы доставили. Цель — 70%, и это заметно более трудное число, потому что его измерение требует знать про запросы, которые вы пропустили. Единственный честный способ — руками: взять чат, вычитать сутки глазами и сравнить с тем, что отдал пайплайн. Это не масштабируется — именно поэтому такую вычитку нужно ставить в расписание, а не оставлять на добрую волю.
Обратная связь — самая дешёвая часть и та, которую стоит построить первой. У каждого доставленного лида есть отклонение в один тап, и каждое отклонение — это размеченный пример, лучшие данные для оценки и настройки, какие вообще бывают, произведённые человеком, который знает нишу лучше нас. Из этих отклонений растут правки словаря, правки определения лида и отключение источников.
Последнее важнее, чем кажется: источник, не давший ни одного подтверждённого лида за две недели, не нейтрален — он тратит ёмкость впустую. Источникам нужны критерии отключения не меньше, чем механика их поиска.
Чего пайплайн не делает
Три ограничения, названные заранее, а не обнаруженные потом:
- Он не обещает клиентов, продаж и выручки. Он отдаёт запросы. Что происходит дальше — ответите ли вы в течение часа и как напишете первое сообщение — и решает сделку, и никакой классификатор к этому не причастен.
- Читаются только публичные супергруппы — ровно то, что видит любой из тысяч других участников. Закрытые чаты, куда человека не пустили бы, не читаются никак.
- Он никогда не пишет. Аккаунты работают только на чтение: ни рассылок, ни автоответов, ничего не публикуется от чьего-либо имени. В базе хранится сам запрос и ссылка на него, а не переписка человека.
Вопрос приватности — самое частое возражение в категории, и он заслуживает прямого ответа вместо абзаца обтекаемых формулировок: публичная супергруппа публична, быть в ней молчаливым читателем — это то, чем занят каждый второй участник, а правильная единица хранения — запрос, а не человек.
Это работает в проде
Описанный пайплайн — это Sonar: он слушает публичные Telegram-чаты по вашей нише и присылает уведомление в течение минуты после того, как человек написал, что ему нужно то, что вы продаёте. Только чтение, 30 дней бесплатно и честный ответ заранее — хватает ли в вашей нише объёма, чтобы это имело смысл.
Если строите что-то похожее, сжатая версия всего вышесказанного: поставьте дешёвый фильтр перед моделью, сделайте нишу конфигом, меряйте полноту руками, даже когда это больно, и называйте свою точность вслух.