Фильтр, который отсекал лучшее
Я строю автоматизацию для чужого бизнеса, а этот кейс - про свою. У меня есть конвейер: он читает ленту заказов на фриланс-бирже, отбирает подходящие, готовит черновик отклика и кладет карточку в базу. Я открываю, правлю, отправляю.
Полтора месяца он работал и приносил ерунду.
Как система училась говорить «нет»
Отбор был устроен честно и понятно. Каждый раз, когда система приносила мусор, я выносила вердикт: «это не мое». Вердикт превращался в правило. Правил становилось больше.
К августу отбор представлял собой под сотню строк стоп-слов. Копирайт, верстка, логотипы, парсинг, обзвон, курсы, геймдев, видеомонтаж - каждая строка стояла на реальном отказе, каждую можно было защитить. Система добросовестно выучила все, что я ей сказала.
Проблема в том, что я говорила ей только про отказы. Я поправляла ее, когда она ошибалась, и молчала, когда она была права. За полтора месяца она узнала сотню способов сказать «нет» и ни одного нового способа сказать «да».
Момент, когда это стало видно
За все время ровно один мой отклик дошел до встречи с заказчиком. Я села разобрать, чем он отличался от остальных, - и обнаружила, что мой собственный фильтр отсек бы его дважды: один раз по слову «маркетинг» в названии раздела, второй - по «поиску клиентов» в описании.
Единственное, что сработало, система считала мусором. И была последовательна: обе стоп-строки я написала сама, по своим же прошлым вердиктам.
Заодно рассыпалась вторая моя гипотеза. Я думала, что наши черновики проигрывают, потому что слишком длинные. Померила: мой рабочий отклик, тот самый, - 3800 знаков. Машинные - от 2400 до 4000. Он был длиннее. Дело было не в длине.
Разметка, которая лежала на виду
Дальше выяснилось смешное. Биржа сама размечает каждый заказ разделом и подразделом - «Программирование / Разработка чат-ботов», «Автоматизация бизнеса / Документооборот». Эта метка приходит в ленте, в каждом заказе, тем же полем, что заголовок и описание.
Мой скрипт читал заголовок, описание и дату. Поле с разделом он не читал никогда.
Полтора месяца я угадывала профиль заказа регулярными выражениями по тексту, имея рядом готовую разметку от самой площадки. Более того: там оказался целый раздел «AI - искусственный интеллект» на 29 подразделов - агенты, боты, RAG, промпт-инжиниринг. Мой профильный раздел целиком. Отбор не видел его в упор.
Это, наверное, главный урок кейса: прежде чем строить свою классификацию, проверь, не отдает ли источник готовую. Я потратила полтора месяца на то, чтобы плохо воспроизвести данные, которые лежали в том же ответе.
Но «просто категория» тоже не работает
Соблазн был очевидный: выбросить сотню строк стоп-слов, взять белый список разделов и жить спокойно. Я так и попробовала - и посмотрела, что получится на живой ленте.
Из 60 заказов по разделам прошло 8. Из этих восьми шесть оказались мусором. «Ищем технолога-кондитера» лежал в «Автоматизации бизнеса / Служба поддержки». «Менеджер по поиску заказов» - в «Бизнес-аналитике». Накрутка голосов и рассылка приглашений - в «Мессенджерах».
Причина простая: раздел выбирает сам заказчик из выпадающего списка, за десять секунд, и ему все равно. Разметка площадки точна ровно настолько, насколько внимателен человек, который ее ставил.
Решение оказалось не «или-или»
Обе схемы плохи поодиночке и хороши вместе, если каждой дать свою работу.
Раздел отвечает за полноту: он решает, попадает ли заказ в круг моих тем вообще. Здесь машинная разметка сильнее любых моих регулярок, потому что не зависит от того, какими словами заказчик описал задачу.
Стоп-лист отвечает за точность, но только внутри уже разрешенного раздела: он убирает то, что работой не считается, - накрутку, штатные вакансии под видом заказа, частный сыск.
Главное здесь - что стоп-лист не исчез, а сменил роль. Раньше он решал, моя ли это тема, и ошибался, потому что тему нельзя надежно вывести из отдельных слов. Теперь он отвечает на куда более простой вопрос: работа ли это вообще. На этот вопрос слова отвечают хорошо.
Проверила на своей же разметке: на 19 заказах, которые я в разное время признала своими, стоп-лист не срабатывает ни разу. То есть точность досталась бесплатно - она ничего не отнимает у полноты.
Цифры
Биржа публикует около 58 заказов в сутки. Раньше до меня доходило пять карточек за прогон, и мусора среди них было больше половины. Теперь из 60 заказов в ленте после разделов остается 8, после остаточного фильтра 1. Мой исторический темп ровно такой же - примерно один релевантный заказ в день.
Спорные разделы - те, где профиль близкий, но уверенности нет, - приходят отдельной пометкой «на решение» и без черновика. Черновик стоит денег, и тратить их на догадку я не хочу: скажу «да» - сгенерируется.
Регрессионных тестов стало 92. Категории в них настоящие: у прошедших взяты из заказов, которые я вела в работе, у отсеянных - из живой ленты.
Применить у себя
Что проверить на практике
Если у вас есть автоматический отбор - заказов, резюме, лидов, входящих писем, - я бы сделала эти четыре проверки первыми.
- Распакуйте ответ источника целиком и выпишите поля, которые вы не читаете. Я полтора месяца угадывала профиль заказа регулярками, имея готовую разметку площадки в том же самом ответе.
- Возьмите десять последних отказов и прочитайте их глазами. Отчет показывает прошедших; отсеянных не видит никто - а там лежал мой единственный отклик, дошедший до встречи.
- Посчитайте, сколько у вас накоплено правил «нет» и сколько сохраненных примеров «да». Если первых на порядок больше, вы обучили машину недоверия и не заметили этого.
- Разделите два вопроса, которые ваш фильтр решает одной кучей: «моя ли это тема» и «работа ли это вообще». На первый хорошо отвечает разметка источника, на второй - стоп-слова. Одним механизмом оба не решаются.
Как понять, что получилось
Правильный признак - не рост числа прошедших, а то, что вы можете назвать причину каждого отказа и она вас устраивает.
Еще два:
- на исторических примерах, которые вы сами признали своими, фильтр не срабатывает ни разу (у меня - 19 из 19)
- спорные случаи приходят отдельно и без дорогих действий: без черновика, без вызова модели, только с пометкой «на решение».
Что я забрала из этого кейса
Система, которую учат только на отказах, учится только отказывать. Если вы поправляете автоматизацию, когда она ошибается, и молчите, когда она была права, вы строите машину недоверия. Положительные примеры надо собирать так же дисциплинированно, как отрицательные, - иначе метрика качества станет односторонней и вы этого не заметите.
Проверьте, что уже есть в данных, прежде чем выводить это из текста. Готовая разметка от источника почти всегда лучше вашей эвристики - и почти всегда лежит в поле, которое вы не распаковали.
Чужая разметка точна ровно настолько, насколько внимателен тот, кто ее ставил. Пользовательская категория - сильный сигнал о теме и слабый сигнал о качестве. Не путайте эти две роли.
Не выбрасывайте старое решение - спросите, на какой вопрос оно отвечает хорошо. Мой стоп-лист был плох как классификатор темы и хорош как детектор «это вообще не работа». Та же сотня строк, другая должность.
И последнее, уже не про фильтры. Единственный способ увидеть, что система отсекает лучшее, - посмотреть на то, что она отсекла. Отчет показывает вам прошедших. Разбирать надо отказы.