Аналитика разговоров

Загрузка записей, разбор по характеристикам и отчёты в Voxagent

Модуль аналитики разбирает записи живых продаж так же, как Voxagent разбирает разговоры AI-агентов: запись превращается в диалог по ролям, диалог оценивается по набору характеристик, оценки складываются в отчёты по отделу.

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

Как это устроено

Загрузка записи → Транскрипция с диаризацией → Разбор по характеристикам → Отчёты
ШагЧто происходит
ЗагрузкаАудио уезжает в хранилище напрямую, минуя бэкенд; в системе появляется разговор
ТранскрипцияВнешний сервис разбирает запись на реплики с ролями и тайм-кодами
РазборСчитаемые метрики вычисляет бэкенд, оценочные — языковая модель
ОтчётыЗначения агрегируются по сотруднику, дате, компании

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

Если расшифровка уже есть, шаг транскрипции пропускается. Это единственный способ разобрать записи из системы, которая отдаёт текст, но не отдаёт аудио.

Загрузка записей

Раздел Analytics → Звонки, кнопка Загрузить записи. Поддерживаются три варианта:

  • только аудио — обычный случай, транскрипцию сделает сервис разбора;
  • аудио и транскрипт — расшифровка ваша, звук нужен для прослушивания и тайм-кодов;
  • только транскрипт — без записи, разбор по тексту.

Аудио и транскрипт связываются по имени файла без расширения: call-12.mp3 и call-12.json — это один разговор.

В окне загрузки выбираются сотрудник и клиент — оба из справочника пространства, и оба заводятся прямо здесь кнопкой рядом с выбором. Галочка сразу отправить в разбор ставит записи в очередь немедленно; без неё они лягут в список со статусом «в очереди» и будут ждать массового прогона.

Там же — название загрузки и дата записей. Название нужно, чтобы потом найти в фильтре именно свою выгрузку; оставите пустым — загрузка назовётся сама и возьмёт в имя момент: «Загрузка 21.09.2026 18:20, файлов: 3». Дата применяется только к тем файлам, которые нигде не несут свою собственную: то, что известно о самом файле, она не перебивает.

Формат транскрипта

{
  "language": "ru",
  "duration_ms": 356000,
  "segments": [
    { "start_ms": 2000, "end_ms": 4100, "role": "Operator", "text": "Добрый день, меня зовут…" },
    { "start_ms": 4300, "end_ms": 7200, "role": "Client", "text": "Да, слушаю вас." }
  ]
}

Роли обязательны: без них непонятно, чью долю речи считать и чью работу оценивать. Тайм-коды необязательны — без них разговор разберётся, но метрики, завязанные на время (доля речи, перебивания, темп), посчитаны не будут и в карточке останутся прочерком, а не нулём.

Архивом

ZIP с записями удобен, когда выгрузка приходит из телефонии. Метаданные берутся из имени файла:

<id>_<in|out>_<телефон>_<ГГГГ_ММ_ДД-ЧЧ_ММ_СС>_<хвост>.mp3

Например 883140777409555_out_79251154445_2026_09_10-14_42_50_akww.mp3 — исходящий звонок на номер 79251154445 от 10 сентября 2026, 14:42:50.

Сначала проверка

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

Повторная загрузка того же файла не создаёт дубль: записи сверяются по содержимому. Служебные файлы macOS — папка __MACOSX, теневые ._имя и .DS_Store — пропускаются: это не записи, а ресурс-форки, и разговорами они не становятся.

Загрузка как единица

Каждая загрузка запоминается целиком: название, вид (файлы или архив), кто и когда её сделал, сколько записей принято и сколько отклонено. По ней потом фильтруют звонки — «покажи то, что я залил во вторник», — и строят отчёты: загрузка доступна и как фильтр, и как разрез, так что две выгрузки можно сравнить между собой. Проверочный прогон архива ничего не создаёт, поэтому и записи о нём не остаётся.

Дата разговора

Дата в списке и в отчётах — это когда звонок состоялся, а не когда его загрузили. Берётся она из первого источника, который её знает:

  1. дата, указанная при загрузке, или колонка started_at в манифесте архива;
  2. имя файла, если оно совпадает с шаблоном телефонии выше;
  3. таймстемп записи внутри архива — то, что zip сохранил о самом файле;
  4. ничего не нашлось — даты нет.

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

Время самой загрузки живёт отдельно и всегда честное — это момент, когда файл приехал в систему.

Кто оператор, а кто клиент

Диаризация отличает голоса, а не людей. Она слышит, что говорили двое, и подписывает их ролями по косвенным признакам — а ошибается молча: доля речи «оператора» оказывается долей клиента, этапы скрипта оцениваются не тому человеку, и карточка при этом выглядит совершенно нормально.

Поэтому у каждой загруженной записи разбор сначала отдельно спрашивает модель: не перепутаны ли стороны. Модель отвечает «да/нет» и одной фразой объясняет, по чему решила, — обе части хранятся у разговора. Разговоры агентов этот шаг пропускают: там известно, кто говорил.

Дальше запись считается дважды — в исходной разметке и в перевёрнутой. Арифметику для второй платформа считает сама: перевернуть роли — это посмотреть на те же реплики с другой стороны. А вот оценки приходится спрашивать у модели ещё раз: «оператор не отработал возражение», сказанное про другого человека, — это другой вердикт, а не тот же самый с переставленными подписями.

В карточке разговора у заголовка транскрипта стоит Поменять роли местами. Поскольку обе разметки посчитаны заранее, это переключение, а не новый разбор: транскрипт и все оценки меняются сразу. Рядом видно, откуда нынешняя разметка — причина модели или пометка, что роли выбрал человек.

Решение человека не перетирается

Если роли переключили руками, следующий разбор об этом не спорит: он пересчитает оценки, но оставит ту сторону, которую выбрали вы. Модель ошиблась один раз — незачем давать ей ошибиться во второй.

Отчёты, список звонков и значения фильтров всегда берут ту разметку, в которой разговор сейчас показывается. Второй набор лежит рядом и ждёт переключения — сложить их в одно среднее означало бы получить число, которое ничего не измеряет.

Сами реплики при этом не переписываются: транскрипт остаётся тем, что выдал диаризатор, а роли переворачиваются на чтении.

Что измеряется

Дефолтный набор приезжает в каждое пространство и делится на две группы.

Считаемые метрики

Вычисляет бэкенд по тайм-кодам, модель не участвует.

МетрикаНормаПочему так
Доля речи операторадо 43%Продажа — это вопросы, а не монолог
Доля речи клиентаот 57%Обратная сторона той же нормы
Перебивания—Сколько раз оператор начал говорить поверх клиента
Доля пересечений—Какая часть разговора прошла в одновременной речи
Темп речи оператора—Слов в минуту
Доля тишины—Паузы между репликами
Длительность разговора, мин—От начала до конца сессии, у загруженной записи — по длине файла

Оценочные характеристики

Их ставит языковая модель. Каждая оценка приходит с обоснованием и ссылкой на реплику, из которой она следует — в карточке ссылка кликается и перематывает запись на это место.

Сюда входят этапы скрипта (открытие, квалификация, выявление потребности, презентация, работа с возражениями, бюджет, ЛПР, закрытие), тон разговора, вежливость, сленг и мат, тип звонка и фиксация следующего шага.

Соблюдение скрипта — взвешенная сумма этапов, приведённая к 0–100. Общий балл считается так же, но берёт всё, чему назначен вес, а не только этапы. Веса видны и меняются в каталоге характеристик; пока вес стоит только у этапов, оба числа совпадают.

«Не измерено» — не ноль

Если характеристику посчитать не удалось, в карточке стоит прочерк и причина. Ноль в доле речи читается как «оператор молчал» и тянет вниз средние по отделу — поэтому неизмеренное в агрегаты не попадает вовсе.

Свой набор характеристик

Раздел Analytics → Характеристики. Слева папки, справа метрики.

Создайте папку под свой набор — например «Возражения» или «Онбординг». Папка Default есть всегда и удалить её нельзя.

Добавьте характеристику. Ключ — латиницей, по нему метрику находят отчёты; после создания он не меняется. Напишите инструкцию модели: что именно оценивать и по какому признаку. Просите обоснование и цитату — без них оценка нечитаема.

Задайте норму. Она красит отклонения в карточке и отчётах, а если характеристика участвует в общем балле — служит и мерой выполнения.

Считаемые метрики руками не заводятся: их значение вычисляет код, и «добавить такую» означало бы написать формулу, которой нет. Их же нельзя удалить — только выключить: пайплайн продолжает считать по ключу. У встроенных оценочных характеристик правится всё, включая инструкцию модели: это просто текст, уходящий в промпт, и уточнить формулировку под свой продукт — нормальное желание.

Удаление характеристики убирает её из каталога и конструктора отчётов совсем. Уже посчитанные значения остаются при разговорах и видны в карточке с пометкой «удалена»: их посчитали, пока характеристика была. В отчётах такая характеристика не участвует, сохранённое представление просто теряет колонку.

Что будет с историей

Правка метрики не переписывает уже посчитанные значения: у каждого сохранена версия метрики на момент расчёта. Отчёт за прошлый месяц не изменится задним числом от того, что вы поменяли вес. Чтобы новые правила применились к старым звонкам, разговоры нужно разобрать заново.

Норма, шкала и вес

Диалог характеристики предлагает только то, что для выбранного типа значения что-то значит:

Тип значенияЧто настраивается
Баллмаксимум шкалы, нормы, направление, вес
Процентынормы, направление, вес
Число, Длительностьнормы, направление, вес; нормы длительности задаются в миллисекундах
Да / нет«хорошо, когда да» или «когда нет», вес
Категорияничего из этого

Максимум шкалы есть только у балла: это и потолок, выше которого модель не ответит, и знаменатель при подсчёте общего балла.

Вес — это участие в общем балле, а не приоритет в списке. Общий балл — взвешенная доля выполнения: сумма (доля × вес), делённая на сумму весов. Долю каждый тип даёт по-своему: балл делится на максимум шкалы; «да/нет» даёт единицу или ноль, и какой ответ хороший, говорит направление; число, длительность и проценты делятся на свою норму — «больше — лучше» делит на нижнюю границу, «меньше — лучше» даёт полный вес внутри верхней и падает по мере превышения. Поэтому у числа без нормы вес ни на что не влияет: делить не на что, и характеристика в итог просто не войдёт.

Соблюдение скрипта и Общий балл — разные числа: первое считает только этапы скрипта, второе — всё, чему назначен вес. Пока вес стоит только у этапов, они совпадают.

Язык названий

Языков здесь два

Язык интерфейса — ваш личный: на нём подписаны характеристики, папки и колонки отчётов. Язык разбора — общий для пространства: на нём модель пишет обоснования оценок. Первый переключается в шапке и меняет картинку сразу; второй живёт в настройках аналитики и применяется к следующему разбору.

Названия и описания встроенных характеристик, папок и представлений хранятся в базе по-английски, а переводы — отдельными строками. Интерфейс сообщает выбранный язык заголовком x-lang — тем, что стоит в переключателе, а не тем, что настроено в браузере, — и в ответ приезжает текст на нём. Для прямых обращений к API запасным остаётся Accept-Language; для языка, которого нет в переводах, остаётся английский — это честнее пустого названия.

Переводятся только тексты, которые поставляет продукт. Названия, которые ввели вы — своя характеристика, своя папка, своё представление, — остаются ровно такими, как их набрали: переводить их означало бы угадывать, что вы имели в виду на языке, на котором не писали.

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

Инструкция для модели не переводится. Это промпт, а не надпись в интерфейсе: две языковые версии означали бы два разных разбора одного разговора.

Отчёты и представления

Раздел Analytics → Представления. Конструктор сверху, готовые представления слева.

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

Измерений может быть несколько, и добавляются они строками, как меры: строка отчёта тогда это сочетание значений — «сотрудник × неделя × тип звонка». Разрезы: сотрудник, дата (с выбором дня, недели или месяца), компания, клиент, источник, загрузка, причина завершения звонка и значение любой характеристики. Одно и то же поле дважды не добавить — кроме даты и характеристики, где повтор осмыслен: месяцы внутри дней, разные характеристики подряд.

Числовую характеристику режут диапазонами: у разреза появляются строки «от–до» с необязательной подписью. Без них каждое значение стало бы отдельной строкой — получился бы список, а не отчёт. Границы полуоткрытые: значение попадает ровно в один диапазон, а не угодившее ни в один собирается в отдельную строку.

Кроме характеристик мерой можно взять количество разговоров — это просто число строк в группе.

Фильтры

Разрез отвечает «в каком виде показать», фильтр — «что вообще брать». Фильтры добавляются строками там же, в конструкторе, и сужают выборку по тем же полям, что и разрезы: сотрудник, клиент, компания, источник, загрузка, тип звонка (агент или загруженная запись), причина завершения и любая характеристика.

Исполнитель в фильтре — и человек, и голосовой агент: разговоры тех и других лежат в одной таблице и меряются одними метриками, поэтому список исполнителей один, но разделён на группы «Сотрудники» и «Голосовые агенты». Тот же фильтр — над списком звонков: там он тоже принимает нескольких исполнителей сразу.

Условие зависит от того, что фильтруют: у полей и текстовых характеристик это «одно из» и «ни одно из» с выбором из значений, которые в данных пространства действительно встречались; у числовой характеристики — «не меньше», «больше», «не больше», «меньше» и число; у любой характеристики — ещё «измерено» и «не измерено». Список значений берётся из самих разговоров, а не из справочника: у загруженной записи клиент и компания могут остаться текстом с импорта, и такую строку отчёта иначе нечем было бы отфильтровать.

Недозаполненная строка фильтра ничего не сужает: фильтр собирают по одному контролу, и «выбрал поле — отчёт опустел» читалось бы как поломка. Фильтр по удалённой характеристике перестаёт применяться вместе с ней — так же, как теряется её колонка.

Фильтры сохраняются вместе с представлением. Период — нет: одно и то же представление смотрят и за неделю, и за месяц, и переключение периода не меняет сохранённый отчёт.

Сохранение

Собранный отчёт сохраняется как представление — для всего пространства или только для себя. Сохранить пишет изменения в открытое представление, Сохранить как заводит новое. Встроенные представления правятся только через копию: они одинаковые у всех, и правка «под свой отдел» сломала бы их остальным, — у них кнопка сохранения выключена.

Звёздочка рядом с представлением выносит его на дашборд. Закрепление личное: у каждого свой дашборд, состав представлений — общий.

Дашборд

Analytics → Дашборд показывает закреплённые представления плитками. Каждая грузится независимо: дашборд из шести отчётов не ждёт самый медленный, чтобы показать хоть что-то.

Встроенных представлений четыре: «Обзор отдела» (ключевые числа), «Сравнение менеджеров» (строка на сотрудника), «Звонки» (журнал) и «Динамика по неделям».

Кнопка Редактировать включает режим правки: плитки перетаскиваются мышью, у каждой появляется крестик, а Сохранить запоминает порядок. Вне этого режима дашборд только читается — случайным кликом плитку не снести.

Массовый разбор

Когда записей много, разбор запускается пачкой: Analytics → Звонки, отметить разговоры и создать прогон. Прогон показывает, сколько разобрано, сколько упало и на чём, его можно остановить и продолжить с того же места. Повторный запуск только для упавших не трогает уже разобранное.

Модель для разбора выбирается в Analytics → Настройки и переопределяется для конкретного прогона — дешёвой моделью можно прогнать весь архив, дорогой перепроверить спорные звонки. Пока модель не выбрана, оценочные характеристики не считаются: разбор дойдёт до метрик по тайм-кодам и остановится. Рядом с выбором модели настраиваются её параметры — температура, top-p, потолок ответа: разбор должен быть воспроизводимым, и температура для него уместна другая, чем для разговора агента.

Язык разбора

Там же выбирается язык разбора: на нём модель читает характеристики и пишет обоснования оценок.

Это настройка пространства, а не читателя. Обоснование пишется один раз и остаётся при разговоре, а читает его вся команда — если бы язык брался из заголовка запроса, один и тот же звонок объяснялся бы по-разному в зависимости от того, кто открыл карточку, и переспросить «почему здесь 2 из 5» было бы не у кого.

Язык, на котором шёл сам разговор, тут ни при чём: русский звонок можно разбирать по-английски, и наоборот. Модель читает транскрипт как есть — переводить его никто не просит.

У каждого разговора сохраняется язык, на котором его разобрали. Через месяц это единственный способ ответить, почему обоснования написаны именно так: настройку с тех пор могли переключить. Переключение применяется к следующему разбору — уже посчитанные оценки не переписываются, для этого разговоры нужно разобрать заново.

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

Справочник участников

Там же живёт справочник участников — две стороны разговора в одном списке.

Сотрудники — те, чью работу оценивают. Идентификаторы из телефонии, указанные в карточке, позволяют загруженной записи находить своего менеджера самой: без них у звонка не будет исполнителя, и сравнивать в отчётах будет некого.

Клиенты — вторая сторона. У клиента есть компания, и именно она делает разрез «по компании» осмысленным: пять звонков разным людям одной организации складываются в одну строку отчёта. Заводить клиента можно и здесь, и прямо там, где его назначают разговору.

В карточке звонка выбираются оба участника и номер конкретного звонка; правки уезжают на сервер по кнопке Сохранить. Рядом — Обновить (разбор идёт фоном, результат приезжает не сразу) и Разобрать заново, который переспрашивает: он заменяет прежние оценки.

API

Все действия модуля доступны через REST. Полное описание с примерами — в справочнике API.

ЧтоЗапрос
Зарегистрировать разговорPOST /api/analytics/conversations
Загрузить пачкойPOST /api/analytics/conversations/batch
Импортировать архивPOST /api/analytics/conversations/archive
Список загрузокGET /api/analytics/uploads
Список разговоровPOST /api/analytics/conversations/search
Карточка разговораGET /api/analytics/conversations/{id}
Поправить разговорPUT /api/analytics/conversations/{id}
Запустить разборPOST /api/analytics/conversations/{id}/analyze
Построить отчётPOST /api/analytics/reports/run
Каталог характеристикGET /api/analytics/metrics
Значения для фильтровGET /api/analytics/reports/filter-options
Справочник участниковGET /api/analytics/sales-reps?kind=Manager|Client
Порядок плиток дашбордаPUT /api/analytics/views/pins/order
Расход на разборGET /api/analytics/usage

Почему список — это POST

У списка разговоров те же фильтры, что у отчётов, вместе с периодом и набором значений. Складывать это в query-строку — значит упереться в её длину и в разное экранирование у клиентов.

Содержание