#2193: Автоматическое распределение тикетов: правила автоназначения и ребалансировщик

Отредактирована: вчера

Swarmica умеет распределять тикеты по агентам и группам без диспетчера. Это делают два механизма, и оба используют один и тот же упорядоченный список правил автоназначения (AutoAssign):

МеханизмКогда запускаетсяКакие тикеты обрабатывает
Автоназначение при создании тикетаОдин раз, сразу после создания тикетаНовый тикет, созданный без исполнителя и без группы
Ребалансировщик (Rebalancer)Периодически, по расписанию CRONТикеты в статусе Новый или Открыт, у которых нет исполнителя или исполнитель в статусе Офлайн, а тикет не заблокирован

Каждое изменение записывается в историю тикета событием «Применено правило автоназначения», автор события — системный пользователь Swarmica.


1. Правила автоназначения

Правила проверяются сверху вниз, в заданном порядке. Побеждает первое правило, которое дало результат; остальные для этого тикета уже не проверяются.

1.1 Опции правила

Опция (API)ЗначенияЧто делает
Название (name), описание (description)локализованный текстТолько для администраторов, на распределение не влияет.
Включено (enabled) / Порядок (order)—В работе участвуют только включённые правила. Эти параметры настраиваются через визуальный редактор в разделе Настройка > Автоматизация > Автоназначение заявок.
Условия заявки (ticket_conditions)фильтр тикетов (Query Language)К каким тикетам применяется правило. Те же условия, что в фильтрах тикетов (статус, приоритет, канал, продукт, навыки, кастомные поля, SLA и т. д.). Пусто — любой тикет. Настраивается через визуальный редактор.
Условия пользователя (user_conditions)фильтр пользователей (Query Language)Каких агентов может выбрать правило (например, по роли, навыкам, сегменту, кастомным полям). Пусто — любой агент. Настраивается через визуальный редактор.
Группа (group)группа или пустоЗадана: агент выбирается среди участников этой группы, а тикет переводится в эту группу. Пусто: агент выбирается среди всех агентов, группа тикета не меняется.
Искать исполнителя внутри текущей группы заявки (within_ticket_group)да / нетАгент выбирается среди участников текущей группы тикета (любой агент, если у тикета нет группы). Группа тикета никогда не меняется. Нельзя сочетать с group и с do_not_assign.
Назначение по навыкам (skill_match)пусто / ANY / FULLКак навыки тикета ограничивают пул агентов. Пусто: навыки не учитываются. ANY: у агента должен быть хотя бы один из навыков тикета. FULL: у агента должны быть все навыки тикета. Тикет без навыков не ограничивает пул.
Не назначать никого (do_not_assign)да / нетПравило никогда не назначает агента. Вместе с group оно только переводит тикет в группу (маршрутизация в очередь). Без группы правило ничего не делает, и проверка переходит к следующему правилу.
Не обрабатывать другие правила (skip_other_rules)да / нетСтоп-правило: если тикет под него подходит, тикет остаётся как есть (без агента и без смены группы), и следующие правила не проверяются. Используйте, чтобы исключить тикеты из автоматического распределения (VIP, определённый канал и т. п.).

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

1.2 Как выбирается агент

Из агентов, попавших в пул правила (user_conditions, группа, навыки), рассматриваются только доступные:

  • статус агента — Онлайн или В сессии (агенты в статусах Занят, Завершение работы, Отошёл и Офлайн не выбираются никогда);
  • агент не достиг личного лимита назначений (autoassign_limit в профиле агента; 0 — без лимита; значение по умолчанию для новых агентов берётся из переменной окружения DEFAULT_AUTOASSIGN_LIMIT). Нагрузка — это число тикетов агента в статусах Новый и Открыт.

Затем доступные агенты ранжируются, и выбирается первый:

  1. Статус: Онлайн раньше, чем В сессии.
  2. Нагрузка: сначала те, у кого меньше тикетов Новый/Открыт.
  3. Время ожидания: первым идёт агент, который дольше всех не получал тикет (из любого источника — вручную, правилом, триггером); агент, которому тикеты ещё ни разу не назначались, идёт самым первым.
  4. При равенстве — по ID агента.

Нагрузка пересчитывается для каждого тикета, поэтому за один запуск ребалансировщика тикеты распределяются по кругу между наименее загруженными агентами.

1.3 Сочетания опций

Поместить тикет в группуИскать исполнителя в текущей группеНе назначать никогоНе обрабатывать другие правилаРезультат для подходящего тикета
———✔Тикет не меняется; следующие правила не проверяются. (Остальные опции стоп-правила игнорируются.)
пустонетнетнетАгент из всех агентов; группа тикета не меняется. Если доступного агента нет — следующее правило.
Группа AнетнетнетАгент из группы A; тикет переводится в A и назначается. Если в A нет доступного агента — следующее правило (тикет не переводится).
Группа Aнет✔нетТикет переводится в A без агента. Срабатывает всегда — доступность агентов не важна.
пустонет✔нетНе действует: правило пропускается, проверяется следующее. (Такой настройки лучше избегать.)
пусто✔нетнетАгент из собственной группы тикета (любой агент, если у тикета нет группы); группа не меняется. Если агента нет — следующее правило.
Группа A✔любое—Запрещено (ошибка валидации).
пусто✔✔—Запрещено (ошибка валидации).

skill_match и user_conditions можно добавить к любой назначающей строке — они только сужают пул агентов.

Типовые настройки

  • Сначала маршрутизация в очередь, потом назначение: правило «Тикеты по биллингу → группа Биллинг, do_not_assign» стоит выше назначающего правила с within_ticket_group. Первое правило маршрутизирует, а ребалансировщик (в режиме GROUP) затем назначает агента внутри группы.
  • Цепочка с запасными вариантами: «Агенты L2 с навыками (skill_match = FULL)» → «Любой агент L2» → «Любой агент L1». Если в первом пуле никто не доступен, пробуется следующее правило.
  • Исключение: правило со skip_other_rules в самом верху для тикетов, которые нужно распределять вручную.

2. Автоназначение при создании тикета

Настройка: enable_autoassign в настройках ребалансировщика (по умолчанию включена).

  • Запускается один раз, в фоне, сразу после создания тикета.
  • Запускается только если тикет создан без исполнителя и без группы (тикет, созданный сразу в группе — например, каналом или триггером, — остаётся ребалансировщику).
  • Не зависит от режима ребалансировщика — работает и при выключенном ребалансировщике.
  • Проверяются все включённые правила (ограничение режима GROUP не действует — у тикета всё равно нет группы).
  • Если ни одно правило не дало результата, тикет остаётся неназначенным; позже его может подхватить ребалансировщик.
flowchart TD
    A([Тикет создан]) --> B{Есть исполнитель<br/>или группа?}
    B -- да --> Z1([Пропуск: оставить как создан])
    B -- нет --> C{enable_autoassign<br/>включён?}
    C -- нет --> Z2([Пропуск])
    C -- да --> D[Фоновая задача:<br/>включённые правила по порядку]
    D --> E{Следующее правило?}
    E -- правил не осталось --> Z3([Без изменений:<br/>тикет не назначен])
    E -- правило --> F{Тикет подходит под<br/>ticket_conditions?}
    F -- нет --> E
    F -- да --> G{skip_other_rules?}
    G -- да --> Z4([Стоп: тикет не меняется])
    G -- нет --> H{do_not_assign?}
    H -- да --> I{У правила есть группа?}
    I -- нет --> E
    I -- да --> J[Перевести тикет в группу<br/>правила, без агента]
    H -- нет --> K[Собрать пул агентов:<br/>user_conditions + skill_match<br/>+ группа правила / группа тикета / все]
    K --> L[Оставить агентов Онлайн / В сессии<br/>ниже их autoassign_limit]
    L --> M{Есть агент?}
    M -- нет --> E
    M -- да --> N[Выбрать лучшего агента:<br/>статус → нагрузка → дольше ждёт → id]
    N --> O[Назначить агента;<br/>перевести в группу правила, если задана<br/>и нет within_ticket_group]
    J --> P([Сохранить тикет + событие<br/>«Применено правило автоназначения»<br/>от Swarmica])
    O --> P

3. Ребалансировщик

Ребалансировщик — одна глобальная настройка.

3.1 Опции ребалансировщика

Опция (API)ЗначенияЧто делает
modeNONE / GROUP / ALLNONE: периодическая ребалансировка выключена. GROUP: тикеты остаются в своей группе (см. ниже). ALL: каждое включённое правило применяется к каждому тикету, тикеты могут переводиться между группами.
cron_scheduleвыражение CRON, по умолчанию */30 * * * *Как часто запускается ребалансировщик (по умолчанию каждые 30 минут).
enable_autoassignда / нет, по умолчанию даВключает или выключает автоназначение при создании тикета (раздел 2). Не зависит от mode.

Переменная окружения: REBALANCER_LOCK_TIMEOUT (в секундах, по умолчанию 1800) — максимальное время, на которое один запуск удерживает блокировку.

3.2 Какие тикеты ребалансируются

Тикет ребалансируется, если выполнены все условия:

  • статус Новый или Открыт (тикеты в статусах Ожидание, Решён, Закрыт и т. д. не трогаются никогда);
  • у тикета нет исполнителя, или его исполнитель в статусе Офлайн, а тикет не заблокирован (заблокированный тикет остаётся за офлайн-исполнителем).

Тикеты обрабатываются начиная с самых срочных — по индексу нарушения SLA, по убыванию; тикеты без SLA идут последними.

3.3 Режимы GROUP и ALL

Режим определяет, какие правила может использовать тикет:

ТикетРежим ALLРежим GROUP
Без группывсе включённые правилавсе включённые правила
В группе Xвсе включённые правила (тикет может быть переведён в другую группу)только правила с group = X и правила с within_ticket_group; правила с другой группой и правила без группы пропускаются

Таким образом, в режиме GROUP тикет, уже находящийся в группе, никогда её не покидает и назначается только участникам этой группы. Тикет в группе, для которой нет подходящих правил, не меняется.

3.4 Алгоритм запуска

flowchart TD
    S([Срабатывание CRON]) --> L{Блокировка свободна?<br/>другой запуск не идёт}
    L -- нет --> X0([Пропустить запуск])
    L -- да --> M{mode = NONE?}
    M -- да --> X1([Стоп])
    M -- нет --> R{Есть включённое<br/>правило?}
    R -- нет --> X2([Стоп])
    R -- да --> T[Выбрать тикеты: статус Новый/Открыт<br/>и нет исполнителя, или исполнитель Офлайн<br/>и тикет не заблокирован]
    T --> T2{Есть тикеты?}
    T2 -- нет --> X3([Стоп])
    T2 -- да --> A{Есть агент Онлайн / В сессии<br/>ниже лимита ИЛИ правило do_not_assign<br/>с группой?}
    A -- нет --> X4([Стоп])
    A -- да --> O[Отсортировать тикеты по индексу<br/>нарушения SLA, самые срочные первыми]
    O --> NT{Следующий тикет?}
    NT -- не осталось --> DONE([Снять блокировку, завершить])
    NT -- тикет --> P[Подобрать правило и агента<br/>тем же алгоритмом, что при создании,<br/>с фильтром правил режима GROUP]
    P --> Q{Правило дало агента<br/>или группу?}
    Q -- нет --> NT
    Q -- да --> C{Изменится исполнитель<br/>или группа?}
    C -- нет --> NT
    C -- да --> RE[Перечитать тикет]
    RE --> V{Всё ещё Новый/Открыт, правило применимо,<br/>группа не менялась для правила within_ticket_group,<br/>изменение всё ещё есть?}
    V -- нет --> NT
    V -- да --> W[Сохранить исполнителя / группу<br/>+ событие «Применено правило автоназначения»<br/>от Swarmica]
    W --> NT

Шаг подбора правила (P) — тот же, что в разделе 2, с одной дополнительной проверкой в начале каждого правила: в режиме GROUP правило, не подходящее к группе тикета (раздел 3.3), пропускается.

flowchart TD
    E{Следующее правило?} -- не осталось --> N0([Правила нет: тикет не меняется])
    E -- правило --> G{Режим GROUP и тикет в группе X:<br/>группа правила = X или within_ticket_group?}
    G -- нет --> E
    G -- да / режим ALL / тикет без группы --> F{Тикет подходит под<br/>ticket_conditions?}
    F -- нет --> E
    F -- да --> SK{skip_other_rules?}
    SK -- да --> N1([Стоп: тикет не меняется])
    SK -- нет --> DN{do_not_assign?}
    DN -- да, с группой --> RG([Перевести в группу правила, без агента])
    DN -- да, без группы --> E
    DN -- нет --> AG{Есть доступный агент в пуле?}
    AG -- нет --> E
    AG -- да --> OK([Назначить лучшего агента;<br/>перевести в группу правила, если задана])

3.5 Важные детали

  • Один запуск за раз. Если запуск ещё идёт, когда наступает следующее срабатывание CRON, новый запуск пропускается. Запуск, простоявший в очереди дольше кратчайшего интервала расписания, тоже отбрасывается — следующий уже в очереди.
  • Ранние выходы. Запуск ничего не делает (и почти ничего не стоит), если режим NONE, нет включённых правил, нет тикетов для ребалансировки, или никто не доступен и нет правила, которое маршрутизирует без агента.
  • Изменения, сделанные во время запуска, важнее. Перед записью ребалансировщик перечитывает тикет. Если агент за это время перевёл его в Ожидание, назначил или перенёс в другую группу, тикет пропускается.
  • Агент, вышедший в онлайн во время запуска, будет учтён в следующем запуске.
  • Офлайн-исполнитель + правило do_not_assign. Такое правило меняет только группу: тикет переводится в группу правила, но остаётся за офлайн-исполнителем.
  • Переназначение тикета офлайн-агента не затрагивает другие настройки агента; чтобы тикет остался за офлайн-владельцем, заблокируйте тикет.

4. Сочетание автоназначения при создании и ребалансировщика

enable_autoassignmodeПоведение
вклNONEНовые тикеты (без группы и исполнителя) назначаются один раз при создании. Если доступного агента не было, повторной попытки не будет, а тикеты офлайн-агентов остаются за ними.
вклGROUPНазначение при создании плюс периодическая доводка: неназначенные тикеты и тикеты офлайн-агентов переназначаются внутри своей группы. Рекомендуется для команд, организованных по группам.
вклALLНазначение при создании плюс периодическая доводка по всему хелпдеску; правила могут переводить тикеты между группами.
выклGROUP / ALLПри создании ничего не происходит; тикеты распределяются только по расписанию ребалансировщика (задержка — до одного интервала CRON). Удобно, когда группу сначала проставляют каналы или триггеры.
выклNONEАвтоматическое распределение полностью выключено.

Примечания:

  • Тикеты, созданные с группой (каналом, формой, триггером или агентом), при создании никогда не обрабатываются — назначить их может только ребалансировщик. Для этого используйте режим GROUP с правилом within_ticket_group.
  • Оба механизма используют одни и те же правила в одном и том же порядке, поэтому правило ведёт себя в них одинаково, за исключением фильтра режима GROUP, который применяет только ребалансировщик.