Речевая аналитика в контакт-центре, или в отделе продаж — это ключевой инструмент для оценки качества обслуживания и соблюдения стандартов общения. С развитием больших языковых моделей (LLM), таких как YandexGPT, подход к анализу диалогов кардинально изменился. Теперь вместо поиска словосочетаний и настройки сложных шаблонов — достаточно передать весь диалог модели и задать ей понятные вопросы
Раньше аналитика работала по линейному сценарию: голосовые записи звонков из телефонии транскрибировались в текст, после чего специальный модуль искал в этом тексте заранее заданные ключевые слова и фразы. На основе наличия или отсутствия этих фраз делались выводы: был ли использован нужный скрипт, было ли приветствие, озвучено ли имя клиента и пр.

Теперь достаточно интегрировать аналитику с YandexGPT. Рассмотрим чуть более сложную аналитику, чем оценка «было ли приветствие». Оценим эмоциональность диалога (положительно, нейтрально, негативно), и пытался ли менеджер решить основную задач. Например, для автосалон, основная задача менеджера — пригласить клиента посетить автосалон. Еще желательно вылавливать случаи «Нет в наличии», когда клиент искал автомашину, которой нет в наличии.
Шаг 1. Собрать системный промпт
В запросе на API Яндекс есть два промпта, system и user. В системном промпте описываем общее задание для GPT, и добавляем описание, как результаты обработки разложить в JSON.
const mainPrompt = "Твоя компания продает автомашины. Ты аналитик, ты оцениваешь работу менеджеров отдела продаж. Оцени разговор менеджера с клиентом. Основной задачей менеджера является убедить клиента посетить автосалон.";
const jsonPrompt =
'Дай следующие результаты анализа:\n' +
'1. Тема разговора (результат в поле topic);\n' +
'2. Суммаризируй разговор (результат в поле summary);\n' +
'3. Подведи итоги разговора (результат в поле result);\n' +
'4. Поставь оценку менеджеру (от 0 до 5), пытался ли менеджер выполнить свою основную задачу (результат в поле rate);\n' +
'5. Сообщал ли менеджер клиенту, что какого-то товара нет в наличии: да (out), нет (nope) - (результат в поле stock);\n' +
'6. Оцени эмоции в разговоре: негативно (negative), нейтрально (neutral), позитивно (positive) - (результат в поле emotional);';
Соединяем через точку оба промпта, получаем системный промпт:
const systemPrompt = mainPrompt + '. ' + jsonPrompt;

Шаг 2. Собрать данные по диалогу
Во второй промпт, который user, собираем простынь переписки. Автор реплики, и через двоеточие сама реплика. Следующая реплика через новую строку. Так как в системном промпте используются «Менеджер» и «Клиент», то соответственно в переписке тоже используем «Менеджер» и «Клиент», а не «сотрудник», «покупатель», или как то еще.
const userPrompt =
'Клиент: здравствуйте, меня интересует автомашина;\n' +
'Менеджер: да, есть автомашины, но в наличии осталось мало. Не хотите ли приехать в автосалон?;\n' + ...
Шаг 3. Отправляем запрос в YandexGPT
У YandexGPT в API есть несколько методов для работы с LLM, самый дешевый это асинхронный. Цены зависят от токенов. Если не в токенах, а в понятных единицах измерения, то оценка одного диалога (примерно 2-3 минуты разговор) будет стоить около 4-5 тенге за диалог, это порядка 1 руб за диалог. Может чуть больше, не считал эти токены.
Запрос отправляем на «штатную» LLM. Есть еще вариант дообучить модель, и работать со «своей» LLM, но для общей оценки диалога, достаточно «штатной» LLM.
Соответственно url для асинхронного запроса:
const urlYandex = 'https://llm.api.cloud.yandex.net/foundationModels/v1/completionAsync';
Для запроса на API еще нужен folderId, это ID папки в консоли Яндекс. Так же в папке должен быть сервисный экаунт с ролью ai.languageModels.user, и для этого экаунта создать API-ключ.
Тело запроса:
const requestBody = {
"modelUri": "gpt://" + folderId + "/yandexgpt/latest", // "Это если испольуем общую LLM
// "modelUri": "ds://" + modelId, // Это если используем дообученную "свою" LLM
"completionOptions": {
"stream": false,
"temperature": 0.3,
// "maxTokens": "20"
},
"messages": [
{
"role": "system",
"text": systemPrompt,
},
{
"role": "user",
"text": userPrompt
}
],
"jsonObject": true,
"jsonSchema": {
"schema": {
"type": "object",
"properties": {
"topic": {
"type": "string"
},
"summary": {
"type": "string"
},
"result": {
"type": "string"
},
"rate": {
"type": "number",
"minimum": 0,
"maximum": 5,
},
"stock": {
"type": "string",
"enum": [ "out", "nope" ]
},
"emotional": {
"type": "string",
"enum": [ "negative", "neutral", "positive" ]
}
},
"required": [ "topic", "summary", "result", "rate", "stock", "emotional" ] // Если не указать required, то LLM может игнорировать поля
}
}
}
Выше, в системном промпте описано, как результаты оценки разложить в JSON. Соответственно в запрос вкладываем эту же самую JSON схему, и указываем, что поля обязательные (required). Если не указать required, то LLM может игнорировать поля.
При отправке запроса заголовок x-client-request-id можно не присваивать, он не влияет ни на что. Пустой заголовок x-data-logging-enabled означает, что я не хочу, чтобы Яндекс использовал мои данные для обучения своих моделей, то есть я не хочу, чтобы Яндекс хранил у себя мои данные.
По результатам запроса API должен вернуть resuestId, если тело корректное. Если некорректное, то в ответе не будет data.id.
let result = {
success: false,
state: 'dummy',
requestId: 'no',
}
axios.defaults.headers.common['Authorization'] = 'Api-Key ' + gptKeyAPI;
axios.defaults.headers.common['x-client-request-id'] = 'snt_' + UtilRandomNum( 10000000, 90000000 );
axios.defaults.headers.common['x-data-logging-enabled'] = '';
try {
const res = await axios.post(urlYandex, requestBody);
result.requestId = res.data.id;
result.state = 'gpt';
result.success = true;
return result;
} catch (e: any) {
result.success = true;
result.state = 'bad';
return result;
}
Полученный requestId сохраняем.
Шаг 4. Получаем результаты YandexGPT
Далее через пару минут запрашиваем результаты, с url:
axios.defaults.headers.common['Authorization'] = 'Api-Key ' + gptKeyAPI;
const url = 'https://operation.api.cloud.yandex.net/operations/' + requestId;
Если в ответе есть поле done, и в нем значение true, то результаты готовы. Если не результаты не готовы, то через минуту повторяем запрос на результаты.
Парсим результаты:
const responseString = response.data.response.alternatives[ 0 ].message.text;
const responseData: any = JSON.parse( responseString );
В responseData будет JSON схема с ответом от YandexGPT.
Далее сохраняем, и показываем результаты довольным пользователям в карточке звонка на вкладке «GPT суммаризация».

В целом оценка работает хорошо. Пишите звоните, переходите на Демо стенд.