Всем привет! Меня зовут Наталья Багрова, сегодня расскажу, какие есть возможности у крупного телеком-оператора для борьбы с таким неприятным явлением как голосовой спам; какие логические и технические трудности ждали нас на этом пути, как мы их решали и к чему пришли. Мы сконцентрируемся в первую очередь на том, как мы строили модель с нуля до первого жизнеспособного прототипа.
Давайте начнем с краткого обзора рынка антиспам-услуг.
Очень условно всех поставщиков антиспам услуг можно разделить на две категории: те, кто видят трафик (телеком-операторы) и те, кто видят отзывы (приложения Яндекса, Тинькофф или Kaspersky, которые собирают отзывы с абонентов). Если посмотреть на то, как устроен дизайн услуги, то это либо блокировки, когда спам-звонок в принципе не доводится до абонента или же уводится на голосового ассистента, а затем присылается текстовая расшифровка, либо же просто подсвечивается, кто сейчас звонит, и всю ответственность за решение, разговаривать сейчас или нет, несет сам клиент. Если мы говорим о билайне, то мы себя относим в первую очередь к тем, кто видит трафик, и идем путем голосового ассистента.
Какие у нас есть сильные стороны? Во-первых, мы как телеком-оператор видим много транзакций, поэтому можем опираться не только на отзыв, но и на фактическое поведение номера. Потенциально, так как мы первыми видим эти транзакции, мы можем предоставить более быструю защиту и не ждать, пока этот отзыв появится где-то в интернете. Также мы не требуем установки программного обеспечения на устройство, не требуется доступ к интернету и книге контактов, что так же может быть приятно для тех, кто будет пользоваться нашей услугой. Поскольку мы пошли по пути голосового ассистента, а не этикетки, потенциально мы сможем предоставить лучшую защиту, чем просто этикетка.
На этом крупные плюсы заканчиваются, и минусов будет гораздо больше.
Какие сложности у нас есть? Одни и те же номера могут использоваться как для холодного обзвона, так и для обслуживания, то есть вести себя как хорошо, так и плохо. Особенно грешат этим, например, фитнес-центры. Кроме того, у нас нет никаких возможностей идентифицировать трафик до конкретного абонента и понять, какие транзакции желанные, а какие - нет. Есть неприятная особенность, заключающаяся в том, что спамеры умеют в подстановку номеров - это технология, которая позволяет вместо своего истинного номера показывать хороший номер как конечному абоненту, так и самому телеком-оператору. То есть абонент будет думать, что ему звонит, например, курьер или Сбербанк, хотя звонит ему мошенник или кто-то другой.
Но и без этих проблем с подстановками активные полезные номера ведут себя очень похоже на спам - интернет-магазины звонят много и часто на разные номера, сложно делить, хороший это трафик или плохой. Более того, понятие спамер весьма относительное. Мы в команде занимаемся этой проблемой уже больше года, и все равно возникают некоторые трудности с определением спамера. Мы все равно иногда собираемся и спорим: эту ситуацию считать как положительный или плохой трафик?
Бывают ситуации, когда, например, человек работает в сфере недвижимости, и для большинства абонентов предложение кредита - спам, а этот человек как раз работает с такими клиентами, или наоборот ждет случая рефинансировать свою ипотеку. Либо предложение проверить бесплатно спину кому-то может быть актуально, кто-то же разговаривает со спамерами, принимает эти решения. Для кого-то это может быть полезно, хотя это не всегда может быть очевидным.
Если же мы подключаем внешнюю разметку, то есть данные из открытых источников, то такая разметка очень быстро устаревает или в принципе не имеет четкого датирования. То есть мы можем найти какую-то информацию в интернете, но связать ее с настоящим днем или понять, что она была актуальна на какой-то момент в прошлом, довольно тяжело. Помимо этого, номера часто влияют своих владельцев, многие из них живут недолго. Если по своим абонентам у нас есть хотя бы какая-то возможность узнать, когда номер был активен, потом ушел в Cancel и перепродан, то по внешним номерам, среди которых и скрывается большая часть трафика, такой возможности нет, что затрудняет анализ.
Также спамеры адаптируются, могут жаловаться на блокировки и пытаться себя разблокировать. Каждый спамер в глубине души считает, что именно его трафик полезен и он ведет себя хорошо. Поэтому они иногда звонят нам или в колл-центр и пытаются разблокировать сами себя. Последнее: для нас важно построить такую модель, которая обладала бы высокой точностью. Для нас крайне важны и критичны False Positive Rate - доля ложно определенных ошибок. Это важно, так как мы пошли по пути голосового ассистента, а не этикетки, и будет очень неприятно, если курьер или кто-то не сможет до вас дозвониться. Если бы мы пошли по пути этикетки, то вся ответственность принималась бы самим абонентом, но мы пошли другим путем, поэтому для нас крайне важно построить такую модель, которая обладала бы максимальной точностью.
Мы будем решать проблему с помощью наших сильных сторон, а именно — данных. Но, когда мы начали, получилось так, что ни одного правильного источника у нас не существовало. Не было готовых данных, которые можно бы было взять и использовать. Нам нужно было получить историю вызовов, которая охватывала бы историю вызовов, которая охватывала бы весь трафик в своей максимальной полноте и с минимальной задержкой.
У нас на тот момент было пять источников, каждый со своими особенностями и недостатками. Для нас были критичны следующие пункты. Во-первых, чтобы в этом источнике отражались нулевые звонки, поскольку это весьма полезная фича, с помощью которой можно узнать, дозвонился ли абонент до другого абонента, был ли принят звонок и кто положил трубку. Также нам нужно было, чтобы эти источники содержали все виды трафика: мобильный, фиксированный транзитный - и чтобы этот источник был горячим, то есть появлялся для нас без задержки, поскольку любая задержка означает, что спамер в этот момент времени может наворотить дел и обзвонить большое количество абонентов. Кроме того, нам было важно, чтобы правильно отображалась длительность звонка и чтобы была история. Не все источники обладали этим свойством, хотя оно очень важно для построения модели машинного обучения. Без истории на глубине несколько дней и даже месяцев не всегда это получается.
В качестве целевого варианта мы выбрали два источника, они очень органично друг друга дополняли (где у одного стоят минусы, у другого - плюсы). Следующим этапом мы хотим взять все транзакции из одного источника и из другого, но на этом также возникают проблемы, поскольку просто взять и объединить эти источники нельзя - они не взаимоисключающие, мы не можем просто сделать Union. К сожалению, есть некоторые транзакции, которые дублируются - записываются и в одном месте, и в другом, при этом с разными своими особенностями. Поэтому перед нами стояла задача по тому, как же соединить эти источники.
Как выглядят данные? По сути, это всего лишь четыре колонки: захэшированный номер абонента, который звонит, захэшированный номер абонента, которому звонят, дата начала звонка и его длительность. Один и тот же звонок может быть записан как одна транзакция, если абонент билайн звонит внешнему абоненту, как две транзакции, если разговаривают два абонента билайн, или как несколько разных транзакций, если у одной или второй стороны подключены дополнительные услуги, например, переадресация. Также присутствует множество технических записей, которые не являются реальными звонками.
При этом нет самой первой колонки, которая обозначена на скрине серым - нет сквозного ID звонка, мы не можем понять, что первая и вторая запись представляет собой один звонок.
А у них есть некоторые особенности. Во-первых, особенность с часовым поясом. Бывает, что для одного абонента и второго абонента фиксируется разное время начала звонка из-за того, что они находятся в разных часовых поясах. Кроме того, бывает некоторая погрешность во времени начала звонка, буквально несколько секунд, и в длительности. Все это делает для нас эту запись как уникальную, как новый звонок.
Как мы устранили эти проблемы? Мы устранили переадресации, нашли для каждого абонента, где это было возможно, правильные часовые пояса, перевели это все в московское время. Далее округлили время начала и длительности до пяти секунд и уже потом взяли уникальные значения по четырем колонкам, избавившись от дублей. Из этих четырех колонок мы перешли к тому, что начали придумывать признаки. Финальные признаки, которые реально присутствуют в нашей модели, раскрывать не буду, но я попросила вместо этого популярную языковую модель ChatGPT сгенерировать несколько идей. Она советует посчитать следующие признаки:
частоту звонков,
количество пропущенных звонков,
среднюю длительность звонка,
lifetime звонка,
время, которое прошло с последней активности номера,
количество попыток до того, как звонок был принят,
количество звонков, сделанных на разные номера в короткий период времени,
типичное время дня, когда номер был активен,
количество звонков в выходные или будние дни,
соотношение входящих и исходящих звонков для номера.
Действительно, эти признаки очень разумные. Наверное, начинать стоит с них, в этом есть смысл. Но мы финально остановились на другом пуле признаков, их сейчас в разработке более сотни.
Следующим вопросом встает глубина расчета признаков. Для нас важно, что глубина расчета должна быть кратна семи дням, потому что это удобно. Всегда любые семь дней, когда бы они ни были рассчитаны, будут содержать одинаковое количество будней и выходных, кроме некоторых исключений. Мы рассчитали все фичи сразу в шести вариантах: на одной глубины, двух, трех, четырех, восьми и двенадцати неделях глубины. Дальше мы выбирали среди них.
На какие критерии мы обращали внимание?
Во-первых, это доля заполненности признака, по оси Y показывается доля нулевых значений для каждого признака, по оси X - глубина расчета, каждая линия - определенный признак или группа признаков. Разумно получается, что чем больше глубина, тем звонков получается больше и тем более заполненный признак. Это важно, потому что фича, которая заполнена только на 30% - это вовсе не фича, а больше шум для модели. То же самое мы видим на картинке с корреляцией признаков в зависимости от глубины с показанием спама - чем глубина больше, тем выше сила каждого признака. При этом мы понимаем, что использовать максимальную глубину не получится, поскольку, во-первых, обрабатывать такое количество данных технически сложно, а во-вторых, чем больше глубина, тем меньше скорость нашего реагирования и тем менее гибкая наша модель.
Кроме тех двух показателей, которые я уже обозначила, для нас была важна стабильность признаков. Под стабильностью я понимаю примерно одинаковые значения параметров для одного и того же юзера в зависимости от времени. На слайде (13.42) приведен признак доля, измеряемый от нуля до ста процентов, в динамике по ста случайным абонентам. Мы видим, что он достаточно волатилен - бывает, что признаки достигают ста процентов, проваливаются до пятидесяти, снова вверх и так далее. Почему это важно, почему стоит за этим следить? Потому что если признаки такие волатильные, то и output модели также будет волатилен, а это значит, что модель будет принимать то одно решение, то другое. Сегодня мы считаем, что это спамер, завтра - нет. С таким работать очень неудобно. Когда мы перешли на глубину в 14 дней, мы уже получили более гладкую картинку, но все равно есть некоторые пики и некоторая рваность. 21 день выглядит еще более гладким, 28 дней выглядит весьма и весьма приятно.
С признаками и глубиной расчетов определились, теперь нужно определиться с таргетом - кого считать спамером. Есть несколько идей: может быть, это тот, кто много звонит, или тот, кто звонит много и на разные номера? Но как же быть с тем, что курьеры, такси, доставки, интернет-магазины часто звонят часто на разные номера, но при этом это желанный трафик? Может быть, это тот, у кого короткие звонки? Но как же быть с подтверждением записи в клинику роботом, как, например, это делает Медси? Это довольно короткие и так же полезные звонки? Может быть, это тот, у кого нет входящих? Но у типичного такси тоже их не очень много. Поэтому это все весьма и весьма неоднозначно.
Но такие же проблемы возникают и с хорошими абонентами - кого считать хорошим? Может быть того, кто в принципе мало звонит, или того, кому много звонят? Но сделать дозвон с номера и добиться, чтобы тебе перезвонили, тоже не так сложно, поэтому это не совсем показатель. Может быть, это тот, кто часто звонит на одни и те же номера, или тот, у кого длительные звонки? Но тут опять вступает в силу и подстановка номера, и ротация номеров. Можно часто менять номера, использовать короткоживущие номера, и тогда на каждом номере будет не так много звонков. Мошенники вообще имеют тенденцию обрабатывать одну и ту же жертву, они ей часто перезванивают и очень долго с ней разговаривают, поэтому это тоже не показатель того, что номер является хорошим.
Что же мы сделали в этой ситуации? Во-первых, нам очень помогали наши коллеги и альфа-тестировщики. Мы создали Telegram-бота или тогда это был Slack-канал, этот источник был очень надежным, так как там присутствовали наши сотрудники, которые понимали, для чего это делают. Они отправляли нам отзывы как на хорошие номера, так и на плохие. Здесь очень важно, что на хорошие номера тоже были отзывы, то есть это ошибки каких-то других моделей или установленных приложений. Но, к сожалению, таких данных было очень мало. Также в качестве источника у нас использовалась лендинг-страница или обращения в колл-центр, где любой наш клиент или клиент другого оператора может оставить отзыв о спамере. Здесь возникает такая же проблема, что данных тоже мало (буквально 100 в неделю), что явно недостаточно для того, чтобы мы построили модель машинного обучения. И опять мы сталкиваемся с тем, что спамеры могут попытаться разблокировать себя, оставив на себя хороший отзыв.
Следующие источники - открытые данные, сайты по типу “Не бери трубку” и аналоги. Здесь нас ждет целый пул других проблем. Во-первых, скошенность данных. Она возникает из-за того, что на хорошие номера никто не оставляет отзывы, никто не тратит на это время, поэтому получить оттуда разметку по хорошим номерам мы не можем. Также у каждого сайта свое понимание спама и категорий - у кого-то их десять по финансам, у кого-то только одна - и подружить их между собой бывает очень непросто. Актуальность отзывов не поддерживается или поддерживается довольно тяжело, то есть мы видим отзыв, мы можем видеть даже дату последнего отзыва, но все равно непонятно, актуален ли этот номер сейчас или там уже кто-то другой. Кроме прочего, формулировки на таких сайтах часто имеют слово “возможно”: возможно, это спам; возможно, это мошенники; возможно, это финансовые услуги. То есть такие отзывы не гарантируют, что это действительно спам или мошенники. Они только подсвечивают, что это потенциально кто-то из такого разряда, а дальше уже принимайте на веру. И, конечно же, такие отзывы подвержены подстановкам номеров. Например, от этого может пострадать какой-нибудь Сбербанк, на который будут постоянно жаловаться, хотя на самом деле он не обзванивал абонентов, а кто-то взял и подставил его номер, скомпрометировал его.
Также у нас есть возможность обмениваться с другими операторами, и такой процесс идет, но он крайне нерегулярен, носит ad hoc характер, здесь возникают вопросы интерпретации и доверия. У каждого своя модель, у каждого свое понимание, что такое спам. Чтобы в режиме prod использовать информацию друг от друга, нужно понимать, кто и что понимает под спамом, у кого какой score, что означают эти цифры. Самый последний способ, который нам доступен - использовать те признаки, которые мы разработали, и строить свои экспертные правила на них. Для нас основными вариантами являются Telegram-бот, открытые источники и экспертные правила.
В следующем посте мы поговорим о том, как мы эти экспертные правила создавали.