# Глава 12. Очереди автоматического распределения вызовов >Англичанин, даже если он один, формирует упорядоченную очередь из одного человека. > >-- Джордж Майкс Автоматическое распределение вызовов (ACD), или организация очереди вызовов позволяет УАТС ставить в очередь входящие вызовы от нескольких пользователей. Оно объединяет несколько вызовов в шаблон удержания, присваивает каждому вызову рейтинг и определяет порядок, в котором этот вызов должен быть доставлен доступному оператору (как правило, в порядке очереди). Когда агент становится доступным, вызывающий абонент с самым высоким рейтингом в очереди доставляется этому агенту, а все остальные повышаются в рейтинге. Если вы когда-либо звонили в организацию и слышали, что «все наши операторы заняты», вы испытали ACD. Преимущество ACD для вызывающих абонентов в том, что им не нужно продолжать набирать номер в попытке связаться с кем-то, а для организаций преимущества заключаются в том, что они могут лучше обслуживать своих клиентов и решать проблемы, когда звонящих больше, чем агентов.1
Существует два типа колл-центров: входящие и исходящие. ACD относится к технологии, которая обрабатывает входящие вызовы, тогда как термин Dialer (или Predictive Dialer) относится к технологии, которая обрабатывает центры обработки исходящих вызовов. В этой книге мы прежде всего сосредоточимся на входящих звонках. |
В этой главе мы можем переключаться между использованием терминов участники очереди и агенты. Так как мы не собираемся тратить много времени на модуль Asterisk с именем |
В Asterisk термин участник относится к каналу (обычно одноранговому узлу SIP), назначенному очереди, который можно набрать, например, |
musiconhold.conf
) |
`strategy`, которую мы будем использовать - это `rrmemory`, что означает круговой перебор с памятью. Стратегия `rrmemory` работает путем чередования агентов в очереди в последовательном порядке, отслеживая, какой агент получил последний вызов и предоставляя следующий вызов следующему агенту. Когда он попадает к последнему агенту - очередь возвращается к началу (при входе агентов они добавляются в конец списка).
Несколько примечаний по стратегиям
Звонит всем доступным участникам (по умолчанию). Эта стратегия распределения на самом деле не считается ACD. В традиционных терминах телефонии это называется "групповой вызов" (
Каждый следующий звонок будет получать участник, который в последний раз положил трубку раньше всех остальных. В очереди, где есть много вызовов примерно одинаковой продолжительности, это справедливо. Но это не будет справеливым, если агент был на вызове в течение часа а все его коллеги получили последний звонок 30 минут назад,потому что агент, который закончил последним свой 60-минутный вызов получит следующий звонок.
Вызывается первый свободный участник, который обработал наименьшее количество вызовов из данной очереди. Это может быть несправедливо, если звонки не всегда имеют одинаковую продолжительность. Агент мог обрабатывать три звонка по 15 минут каждый, а его коллега имел четыре 5-секундных звонка; агент, который обработал три звонка, получит следующий звонок.
Звонит случайный интерфейс. Это на самом деле может быть хорошо и в конечном итоге будет очень справедливым с точки зрения равномерного распределения вызовов между агентами.
Обзванивает участников по кругу, запоминается последний участник, ответивший на вызов. Это также может быть справедливым, но не так как
Звонит участникам в указанном порядке, всегда начиная с начала списка. Это работает, если у вас есть команда, в которой есть некоторые агенты, которые должны обрабатывать большинство вызовов, и другие агенты, которые должны получать вызовы, только если основные агенты заняты.
Звонит случайному участнику, но использует пенальти |
Вы можете установить это значение в |
С точки зрения бизнеса - вы должны сказать своим агентам, чтобы они завершили все звонки в очереди, прежде чем выходить из системы в течение дня. Если вы обнаружите, что в конце дня в очереди много вызовов - возможно, вы решите продлить чью-то смену, чтобы обслужить их. В противном случае, они просто добавят вам стресса, когда перезвонят на следующий день в худшем настроении. Вы можете использовать |
Следует отметить, что упомянутые |
\*CLI> queue add member channel to queue [[[penalty penalty] as membername]state_interface interface]
`channel` - это канал, который мы хотим добавить в очередь, например `SIP/0000FFFF0003`, а имя `queue` будет что-то вроде `support` или `sales` - любое имя очереди, которое существует в _/etc/asterisk/queues.conf_. Пока мы будем игнорировать вариант c `penalty`, но обсудим его в разделе [«Расширенные очереди»](#расширенные-очереди) (`penalty` используется для контроля ранга участника в очереди, что может быть важно для операторов, которые вошли в несколько очередей или имеют разные навыки). Мы можем определить `membername` чтобы предоставить подробные сведения для механизма регистрации очередей.
Опция `state_interface` информирует очередь о состоянии устройства, отслеживаемое для этого агента. Детали работы с состояниями устройств обсуждаются в [Главе 13](glava-13.md). Сходите и проработайте эту главу, а затем вернитесь сюда и продолжайте. Не волнуйтесь - мы подождем.
Теперь, когда вы добавили `callcounter=yes` в _sip.conf_ (мы будем использовать SIP-каналы во всех остальных наших примерах), давайте посмотрим, как добавлять участников в наши очереди из Asterisk CLI.
Добавление участника очереди в очередь `support` можно выполнить с помощью команды `queue add member`:
```
*CLI> queue add member PJSIP/SOFTPHONE_B to support
Added interface 'PJSIP/SOFTPHON_B' to queue 'support'
```
Запрос очереди подтвердит, что наш новый участник был добавлен:
```
*CLI> queue show support
support has 0 calls (max unlimited) in 'rrmemory' strategy (0s holdtime, 0s talktime),
W:0, C:0, A:0, SL:0.0%, SL2:0.0% within 0s
Members:
PJSIP/SOFTPHONE_B (ringinuse disabled) (dynamic)(Not in use) has taken no calls yet
No Callers
```
Чтобы удалить участника очереди, вы должны использовать команду `queue remove member`:
```
*CLI> queue remove member PJSIP/SOFTPHONE_B from support
Removed interface PJSIP/SOFTPHONE_B from queue 'support'
```
Конечно же вы можете снова использовать команду `queue show`, чтобы убедиться, что ваш участник был удален из очереди:
```
*CLI> queue show support
support has 0 calls (max unlimited) in 'rrmemory' strategy (0s holdtime, 0s talktime),
W:0, C:0, A:0, SL:0.0%, SL2:0.0% within 0s
Members:
PJSIP/SOFTPHONE_B (ringinuse disabled) (dynamic) (Not in use) has taken no calls yet
No Callers
```
Мы также можем приостанавливать и возобновлять участников в очереди из консоли Asterisk, используя команды `queue pause member` и `queue unpause member`. Они используют формат, аналогичный предыдущим командам, которые мы использовали:
```
*CLI> queue pause member PJSIP/SOFTPHONE_B queue support reason Callbacks
paused interface 'PJSIP/SOFTPHONE_B' in queue 'support' for reason 'Callbacks'
*CLI> queue show support
support has 0 calls (max unlimited) in 'rrmemory' strategy
(0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0% within 0s
Members:
SIP/0000FFFF0001 (dynamic) (paused) (Not in use) has taken no calls yet
No Callers
*CLI> queue show support
support has 0 calls (max unlimited) in 'rrmemory' strategy (0s holdtime, 0s talktime),
W:0, C:0, A:0, SL:0.0%, SL2:0.0% within 0s
Members:
PJSIP/SOFTPHONE_B (ringinuse disabled) (dynamic) (paused:Callbacks) (Not in use)
has taken no calls yet
No Callers
```
Добавляя причину (reason) приостановки работы участника очереди, например время обеда (lunchtime), вы гарантируете, что ваши журналы очереди будут содержать дополнительную информацию, которая может оказаться полезной. Вот как можно возобновить работу участника:
```
*CLI> queue unpause member PJSIP/SOFTPHONE_B queue support reason FinishedCallBacks
unpaused interface 'PJSIP/SOFTPHONE_B' in queue 'support' for reason 'FinishedCallbacks'
```
В производственной среде CLI (интерфейс командной строки) не является лучшим способом управления состоянием агентов в очереди. Вместо этого существуют приложения диалплана, которые позволяют агентам информировать очередь об их доступности.
### Определение участников очереди в таблице queue_members
Если вы определите участника очереди в таблице базы данных `asterisk.queue_members`, то он всегда будет зарегистрирован в очереди. Это как правило не очень хорошо, если ваши участники люди, так как люди, как правило, встают и передвигаются.
В каждом определении очереди вы просто определяете участников следующим образом:
```
MySQL> insert into `asterisk`.`queue_members`
(queue_name,interface,penalty)
VALUES
'hotline','PJSIP/SOME_NON_HUMAN','0');
```
В типичной очереди (в которой есть группа людей, отвечающих на вызовы), вы обнаружите, что определение участников в таблицу `queue_members` может навредить. Агенты должны иметь возможность входить и выходить из системы (а не автоматически регистрироваться всякий раз, когда очередь перезагружается). Мы не рекомендуем определять участников в таблице `queue_members`, если только нет других целей (таких как банк устройств, отвечающих на вызовы, где вы хотите использовать очередь для балансировки нагрузки вызовов в пул устройств или групповой вызов, где все телефоны звонят одновременно, независимо от того, сидит ли кто-нибудь рядом с телефоном).
### Управление участниками очереди с помощью логики диалплана
В колл-центре, в котором работают живые агенты, чаще всего агенты сами входят в систему и выходят из нее в начале и в конце своей смены (или когда они идут на обед, в ванную или иным образом недоступны для очереди).
Для этого мы будем использовать следующие приложения диалплана:
* `AddQueueMember()`
* `RemoveQueueMember()`
При входе в очередь может случиться так, что агенту необходимо перевести себя в состояние, когда он временно недоступен для приема вызовов. Следующие приложения позволят сделать это:
* `PauseQueueMember()`
* `UnpauseQueueMember()`
Приложения `Add`/`Remove` используются для входа и выхода из системы, а `Pause`/`Unpause` используются для коротких периодов отсутствия агента. Разница лишь в том, что `Pause` и `Unpause` устанавливают элемент как недоступный/доступный (`unavailable`/`available`), фактически не удаляя их из очереди. Это бывает полезно для отчетности (если участник приостановлен - администратор очереди может видеть, что он вошел в очередь, но просто недоступен для приема вызовов в данный момент). Если вы не уверены, какой из них использовать, мы рекомендуем агентам использовать `Add`/`Remove`, когда они физически не находятся у своего телефона и `Pause`/`Unpause`, когда они находятся на своем рабочем месте, но временно недоступны.
Если есть сомнения - будет лучше чтобы ваши агенты выходили из системы.
Использование Пауза и Снять с паузы В некоторых средах Некоторым руководителям нравится использовать настройки Здесь важно отметить, что параметр Короче говоря, агенты, которые не сидят за столами и не планируют принимать звонки в течение следующих нескольких минут, должны выйти из системы. |
[subSetupAvailableQueues]
; ...
; Получить список очередей, доступных для этого агента
same => n,Set(AvailableQueues=${DB(queue_agent/${MemberChannel}/available_queues)})
same => n,Set(MemberPenalties=${DB(queue_agent/${MemberChannel}/penalty)})
; если нет назначенных очередей ...
Контекст `[sets]` также требует нескольких новых строк (некоторый код был удален для краткости, заменен на `; ...`). Вставляйте/изменяйте только код, выделенный жирным шрифтом.
exten => \*736,1,Verbose(2,Logging into multiple queues per the database values)
; ...
same => n,Set(WorkingQueue=${CUT(AvailableQueues,^,${QueueCounter})})
same => n,Set(WorkingPenalty=${CUT(MemberPenalties,^,${QueueCounter})})
; While the WorkingQueue ...
; ...
same => n,Set(WorkingQueue=${CUT(AvailableQueues,^,${QueueCounter})})
same => n,Set(WorkingPenalty=${CUT(MemberPenalties,^,${QueueCounter})})
same => n,EndWhile()
; ...
Эти примеры, вероятно, не подходят для продакшена (мы бы использовали специально построенные таблицы MySQL для такого рода вещей, а не AstDB), но это дает вам представление о том, как диалплан может быть использован для применения динамической логики к более сложным сценариям конфигурации.
### Динамическое изменение пенальти (queuerules)
Используя таблицу `asterisk.queuerules` можно определить правила, изменяющие значения переменных канала `QUEUE_MIN_PENALTY` и `QUEUE_MAX_PENALTY`. Переменные канала `QUEUE_MIN_PENALTY` и `QUEUE_MAX_PENALTY` используются для управления тем, какие участники очереди предпочтительнее для обслуживания абонентов. Допустим, у нас есть очередь с названием `support` и имеется пять участников очереди с различными пенальти в диапазоне от `1` до `5`. Если до того, как абонент войдет в очередь, для переменной канала `QUEUE_MIN_PENALTY` задано значение `2`, а для `QUEUE_MAX_PENALTY` - `4`, то для ответа на этот вызов будут считаться доступными только участники очереди, пенальти которых находятся в диапазоне от `2` до `4`.:
```
same => n,Set(QUEUE_MIN_PENALTY=2) ; установить минимальный пенальти участника
same => n,Set(QUEUE_MAX_PENALTY=4) ; установить максимальное пенальти участника
same => n,Queue(support) ; вход в очередь с минимальными и максимальными пенальти
; для участников, которые будут использоваться
```
Более того, во время пребывания абонента в очереди мы можем динамически изменять значения `QUEUE_MIN_PENALTY` и `QUEUE_MAX_PENALTY` для этого абонента. Это позволяет использовать либо больше, либо другой набор участников очереди, в зависимости от того, как долго вызывающий абонент ожидает в очереди. Например, в предыдущем примере мы могли бы изменить минимальное значение пенальти на `1`, а максимальное - на `5`, если абонент находится более 60 секунд в очереди.
Файл примера _~/src/asterisk-15.*/configs/samples/queuerules.conf.sample_ содержит отличную справку о том, как работают правила очереди.
Правила определяются с использованием таблицы `asterisk.queuerules`. Несколько правил могут быть созданы для того, чтобы облегчить различные изменения пенальти на протяжении всего вызова. Давайте посмотрим, как мы можем определить правило.:
```
MySQL> insert into `asterisk`.`queue_rules`
(rule_name,time,min_penalty,max_penalty)
VALUES
('more_members',60,5,1);
```
Новые правила будут касаться только новых абонентов, входящих в очередь, а не существующих абонентов, которые уже находятся в ней. |
Воспроизведение объявлений между музыкальными файлами на удержании Вместо того, чтобы разбираться со сложностями объявлений для каждой из ваших очередей - вы можете альтернативно (или совместно) использовать функциональность объявлений, определенную в musiconhold.conf. Перед воспроизведением файла музыки на удержании - будет воспроизведен файл объявления, а затем воспроизведен снова между аудиофайлами. Допустим, у вас есть 5-минутный цикл аудио, но вы хотите воспроизводить сообщение “Спасибо за ожидание” каждые 30 секунд. Вы можете разбить аудиофайл на 30-секундные сегменты, задать их имена, начиная с |
n+1
(откуда было вызвано приложение Queue()
) не определен, вызов будет прерван. Другими словами, не используйте эту функцию, если ваш диалплан не делает что-то полезное на шаге, следующем сразу за Queue()
.Local/PJSIP/SOFTPHONE_A@localMemberConnector
, но мы чувствовали, что это приведёт к странным синтаксическим ошибкам и неудобным для фильтрации и анализа, поэтому мы пошли с -.Answer()
, Playback()
и т.д.