Мы трепетно относимся к телефонным звонкам клиентов. И раз уж клиент позвонил, стараемся сделать все, чтобы довести его до ручки покупки. Да, мы используем передовые технологии: заказ обратного звонка, динамическое и статическое отслеживания звонков, их аудит, но в этот раз поговорим о приземленном анализе входящих звонков.

Немного экономики

Примем стоимость перехода на сайт за 1$. Пусть конверсия посетителя сайта в звонящего составляет 10%. Тогда стоимость привлечения клиента составит 10$. Если мы оставляем без ответа 10 звонков клиентов в день (или 200 в месяц), значит, мы ежемесячно выкидываем 2000$.

ПроЛог

Мы установили себе телефонную станцию Asterisk и настроили хитрым образом маршрутизацию звонков. Например, звонок на линию продаж приходит оператору 1-й линии, и, если в течении 7 секунд оператор не ответил, звонок попадает операторам 2-й линии, если в течении 10 секунд — они не ответили, звонок уходит в отдел продаж. А если и там звонок не отработан, он уходит директору. Первое время после внедрения, телефон директора разрывался, но затем усилили команду операторов, разработали типовые скрипты работы с клиентами и телефон успокоился.

Немного истории

Астериск (Asterisk), согласно легенде, был придуман Марком Спенсером (Mark Spenser).  Марк основал бизнес по оказанию бесплатных консультаций пользователям линукса и обнаружил отсутствие на рынке эффективного (доступного, открытого, гибкого, свободного, добавить желаемое) механизма распределения звонков по операторам-экспертам. Тогда он решил написать Астериск. Подробнее можно посмотреть там https://ru.wikipedia.org/wiki/Asterisk

Да, мы знаем, что существует огромное множество (платных и бесплатных) модулей для анализа логов Астериска (CDR reports, QueueMetrics и т.д.), но мы их не стали использовать потому, что:

  1. не хотели пускать аналитиков на боевой сервер (эти модули ставятся на сервер);
  2. лелеяли мечту прикрутить звонки к продажам в имеющейся аналитической системе отчетности (QlikView)/

Поэтому и решили изобрести велосипед. Вот что из этого получилось:

АрхеоЛог

Изучение логов, подобно занятиям археологией. Мы можем только догадываться, какие реальные события привели к формированию именно таких логов. У нас остаются материальные свидетельства в виде записей разговоров, но предпосылки событий, мысли участников остаются за кадром. Нам достались для анализа логи очередей, хотя возможно, вам удастся получить и более простые логи звонков.

Немного лирики

Изучая логи, находили странные последовательности событий. Например, сотрудник звонит с внутреннего номера в бухгалтерию. Бухгалтерия не отвечает. Звонок сваливается на оператора. После этого сотрудник общается с оператором несколько минут. О чём это я?

К счастью, есть структура логов очередей

Астериск хранит логи обслуживания очередей в виде текстовых файлов queue_log в кодировке UTF-8 без заголовков с разделителем ‘|’. Продвинутый случай, когда логи сбрасываются в MySQL не рассматриваем, ибо он проще. Текстовые логи имеют вид:

Расшифровка полей

1) Дата время в Unix формате (количество секунд с 01.01.1970).

2) Идентификатор вызова.

3) Идентификатор очереди.

4) Идентификатор агента (оператора).

5) Название события.

6) Далее поля с 6 по 10 (как и 3 и 4) наполняются смыслом в зависимости от названия события (5).

В данном примере легко увидеть, что:

1) 06.08.15 в 00:27 произведена перезагрузка конфигурации сервера очередей.

2) 06.08.15 в 04:08 контрагент произвел звонок на линию CO1 с номера  4959371650 (так этот номер распознается на этой линии, на другой линии он может иметь префикс 7, а на третьей 8). Звонок попал в 900 очередь. Звонок раздавался одновременно у Operator1 и Operator2 10000мс, затем звонок покинул очередь по превышению времени ожидания 10с. Звонок вошел в очередь 901, откуда был извлечен оператором Irina через 4с. Разговор записывался по идентификатором 1438834133.2826. На 65 секунде разговора контрагент завершил звонок, а Irina на 66.

Немного заметок

1) Единицы измерения у разных событий могут различаться, например (секунды и милисекунды) и их надо приводить к единообразию.

2) Одно и то же поле хранит разные данные в зависимости от контекста.

3) Возникают неоднозначности (длительность разговора 65 и 66 секунд), которые нужно трактовать.

4) В номерах очередей странные значения (например, 111, при отсутствии 110), возможно мы не умеем их интерпретировать. 

АстроЛог

Увидев ключ — идентификатор вызова, сразу возникла мысль сделать модель данных по схеме звезда.Модель данных колл-центра QlikView

Вот скрипт загрузки:

Загрузив данные, мы можем начать увлекательное путешествие в мир очередей Астериска. В этом вам помогут выражения:

Количество вызовов (звонков) Count(DISTINCT CallId)
Сорвалось вызовов Count(ABANDON.WaitTime)
Клиент ждал и не дождался (с) Sum(ABANDON.WaitTime)

Собственно, вот и наше жемчужное зерно — теперь мы знаем, сколько вызовов сорвалось, поскольку клиент не хотел ждать. При желании можем построить зависимости времени ожидания и т.п.

Немного занудства

Не забудьте, что время голосового приветствия или голосового меню (IVR) в это время не входит, поскольку клиент попадает в очередь позже. Таким образом, если среднее время ожидания сорвавшегося клиента 17с, а длительность голосового приветствия, 22с, то полное время ожидания — 39с.

МоноЛог

Скептики возразят: «Но ведь могли звонить и старые клиенты, которые нас знают, любят и готовы перезвонить позже!  Возможно, они и перезвонили позже, но модель данных не позволяет просто сделать анализ в разрезе номера вызывающего абонента»

Общение с продавцами и руководством, выявило очевидный факт – им неинтересно смотреть, как звонок гулял по очередям, им важен простой ответ на вопрос: ”разговор состоялся?” — “да“ или “нет“. Поэтому от модели звезды решили отказаться в пользу простой таблицы. К тому же, мы хотели подключить к информации о звонках информацию о продажах.

Очередная версия модели данных резко упростилась до единственной таблицы:Asterisk

Немного оправданий

Мы немного изменили названия полей, ибо CallTime без контекста может означать и время разговора, и его длительность. CallID и CallerID – неудачные названия, они визуально близки и могут вызывать ошибки, но наши пользователи уже к ним привыкли.

Контрагент.Код — код контрагента в 1С (определяем по номеру телефона, у нас, как вы догадываетесь, 1С и в ней живут списки телефонов контрагентов)

Line – входящая линия

CallID – идентификатор звонка

CallDate – дата звонка (вынесена в отдельное поле, для уменьшения вариабельности данных)

CallTime – время звонка (вынесено в отдельное поле, для уменьшения вариабельности данных)

CallHour – час звонка, для контроля загрузки в течении дня  (позже перерастет в мастер-календарь)

CallerID – номер вызывающего абонента

CallerAge – возраст клиента, в данном случае если есть в 1С, то старый, если нет — новый

CallDuration – длительность вызова

ServiceDuration – длительность разговора, если время разговора равно 0, значит клиент сорвался.

Вот кусочек кода, заранее извиняюсь за активное использование mapping, он позволяет снизить неоднозначности, упомянутые выше:

Можно использовать выражения

Входящих звонков Count(Asterisk.CallID)
Входящих звонков с различных телефонов Count(DISTINCT Asterisk.CallerID)
Пропущено звонков Count({<Asterisk.ServiceDuration={0}>} Asterisk.CallID)
Упущено абонентов Count({<Asterisk.ServiceDuration={0}>} DISTINCT Asterisk.CallerID)

Используя измерение Asterisk.CallerAge удобно смотреть доли новых и старых клиентов. После интеграции этой таблички в систему отчетности, появилась возможность строить разрезы связанные с клиентами (ОсновнойМенеджерКонтрагента, Регион, Приоритет и т. п.), а так же анализировать частоту звонков и заказов.

ЭпиЛог

Первая версия модели данных (звезда) была подготовлена за день, только на основании предоставленных логов. Ранее с Астериском были не знакомы, пришлось изучить описание событий его очередей. Буквально к концу рабочего дня было показано, что за месяц мы теряем несколько сотен звонков поскольку клиент не дожидается ответа — ранее такой аналитики мы не вели.

Изучение работы очередей, заняло еще день, но стало понятно, что модель звезды неудобна пользователям, они складывают время всех событий RINGNOANSWER, получают мультипликативно завышенный на количество операторов результат, и говорят, что QlikView неправильно считает. Поэтому  еще один день заняло создание модели с нуля, в виде понятном пользователю, заодно к ней прикрутили признак клиента, позволяющий определить старый он или новый.

Анализ показал, что в пропущенных звонках соотношение клиентов старый/новый 2:1. Кто бы мог подумать, но:

  • доля тех, кто сумел после этого дозвониться, в старых клиентах, выше чем в новых,
  • ждут в очереди, старые клиенты дольше, чем новые.
  • тем не менее более сотни клиентов (новых и старых) за месяц так не перезвонили нам.

Вот они живые заказчики, вот их номера телефонов! Вот работа для SuperManSalesManа! Вот она, реальная отдача бизнес аналитики!

Немного оптимизма

Осталось обширное поле для оптимизации IVR, изменения настроек и структуры очередей, мы хотим разделить очереди для старых и новых клиентов (тем более, что Астериск это позволяет) и назначить им разные приоритеты, старых клиентов сразу переключать на персональных менеджеров, реализовать автоматический call-back по недозвону.

Вы тоже можете попробовать улучшить ваш бизнес с минимальными затратами ресурсов даже с помощью бесплатной QlikView Personal Edition.  

Примеры данных и скриптов выложил на GitHub.

Расскажите, а как ваши маленькие проекты (до 7 дней) помогли (могут помочь) вашему бизнесу?