Так уж вышло, что раз в несколько лет мы переписываем сервис, отвечающий за диалоговое взаимодействие в Алисе. В прошлый раз мы распиливали монолит на микросервисы, переходили от концепции интента к концепции сценария и улучшали качество классификации. Этот рефакторинг позволил нам научиться горизонтально масштабироваться, ускорил выпуск фичей и дал возможность существенно улучшить качество работы диалогового движка. На этой инфраструктуре мы жили 5 лет.

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

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

Дальше я расскажу, как мы это собираемся делать.


Что внутри этой статьи:

  • Архитектура Megamind: преклассификация, сценарии, постклассификация, генеративные ответы.

  • Как Алиса выглядит на функциях и что такое Function Calling.

  • Учёт контекста экрана, процесс обучения, зерошот, новая проблема классификации.

  • RAG функций и архитектура, схема преклассификации и фолбека.

Как всё работало раньше

Ядро Алисы состоит из множества сценариев, в которых реализована обработка разных типов задач: музыка, видео, погода и пр. Алиса на YandexGPT — это тоже один из таких сценариев.

Обработка запросов строится по следующей схеме:

  1. Сначала происходит анализ возможных смыслов запросов по его тексту и контексту диалога.

  2. В процессе преклассификации отбираются сценарии, которые могли бы дать ответ на запрос, но нет гарантии, что сделают это. Есть сценарии, которые предлагают свои ответы на любые запросы, например сценарий диалога с YandexGPT

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

  4. Полученные ответы ранжируются, и выбирается самый лучший — его и получит пользователь.

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

  • Сценарии аддитивны, то есть можно легко научиться обрабатывать новый интент, вид запроса, не вызывая регресс остального стека. Такое возможно из‑за отсутствия единого входного классификатора интентов, который бы диспетчеризовал обработку в какой‑то единственный сценарий. Кстати, так была устроена Алиса в самом начале, и это сильно ограничивало скорость внедрений.

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

  • Сценарии можно тестировать независимо, а не поднимать всю Алису целиком, чтобы репрезентативно повторить обработку запроса.

Последние 5 лет такая архитектура позволяла эффективно развивать Алису, учить её понимать все новые запросы. Однако у такого подхода нашлись и существенные недостатки:

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

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

  • На каждый запрос в итоге отвечает только один сценарий, поэтому сложно делать кросс‑сценарные взаимодействия вроде запроса: «Включи трек, который стоит у меня на будильнике». Каждый такой пример требует отдельных ухищрений.

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

Наши пользователи довольно хорошо знают возможности Алисы и научились обращаться с ней, как когда‑то научились задавать запросы в Поиск на «поисковом» языке. Многие годы мы не знали, как решать эти проблемы, но с появлением LLM ситуация изменилась.

Оказалось, что большие языковые модели достаточно умные не только для работы с текстом, но и для того, чтобы разложить сложную задачу на несколько шагов выполнения и генерировать структурированные машиночитаемые ответы. В мире этот подход называют Tool Calling или Function Calling, он лежит в основе концепции агентов, про которую сейчас много говорят.

Полтора года назад мы увидели в этом большой потенциал для Алисы, начали первые эксперименты, а сегодня мы запускаем технологию смарт‑функций в Алисе на ТВ Станциях, которой и посвящена эта статья.

Смарт-функции: как это работает

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

Когда пользователь задаёт запрос, мы даём на вход LLM несколько описаний тулов (от слова Tool), которыми она может воспользоваться, контекст (диалог, описание устройства и происходящего на экране), запрос пользователя и просим сгенерировать обращение к тулу для продвижения по решению задачи пользователя.

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

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

[AVAILABLE_TOOL]
name: get_last_played_content
description: Получение информации о последних прослушанных аудиотреках, проигранных видео и телеканалах
parameters: {"properties":{"content_type":{"description":"Тип контента, последнее воспроизведение которого хочется получить. Можно не указывать, если фильтрация не нужна.","enum":["audio","video"],"type":"string"}},"type":"object"}
return_parameters: {"properties":{"last_played_items":{"description":"Воспроизводимый ранее контент от недавнего к более старому","items":{"properties":{"audio_content_id":{"description":"Идентификатор аудио контента, который воспроизводился последним","properties":{"content_id":{"description":"ID музыки","type":"string"},"type":{"description":"Тип музыки","enum":["artist","album","playlist","track","recommendations","generative","fm_radio"],"type":"string"}},"type":"object"},"audio_content_meta":{"description":"Метаинформация об аудиоконтенте","properties":{"album_meta":{"description":"Метаинформация об альбоме","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artist_meta":{"description":"Метаинформация об исполнителе","properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"fm_radio_meta":{"description":"Метаинформация о FM-радиостанции","properties":{"id":{"description":"ID FM-радиостанции","type":"string"},"station_name":{"description":"Название FM-радиостанции","type":"string"}},"type":"object"},"generative_meta":{"description":"Метаинформация о Нейромузыке","properties":{"id":{"description":"ID Нейромузыки","type":"string"}},"type":"object"},"playlist_meta":{"description":"Метаинформация о плейлисте","properties":{"id":{"description":"ID плейлиста","type":"string"},"title":{"description":"Название плейлиста","type":"string"}},"type":"object"},"recommendations_meta":{"description":"Метаинформация о потоке рекомендаций","properties":{"id_composite":{"description":"ID составного потока рекомендаций - список ID базовых потоков рекомендаций, разделенных запятой","type":"string"},"seeds":{"description":"Метаинформация о базовых потоках рекомендаций. Порядок записей соответствует порядку ID в поле `id_composite`","items":{"properties":{"id":{"description":"ID базового потока рекомендаций. Может использоваться как отдельный идентификатор аудиоконтента с типом `recommendations`","type":"string"},"seed_name_human_readable":{"description":"Человекочитаемое название базового потока рекомендаций","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"track_meta":{"description":"Метаинформация о треке","properties":{"album":{"description":"Метаинформация об альбоме трека","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artists":{"description":"Метаинформация об исполнителях трека","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"duration":{"description":"Продолжительность трека","format":"duration","type":"string"},"id":{"description":"ID трека","type":"string"},"title":{"description":"Название трека","type":"string"}},"type":"object"}},"type":"object"},"duration_since_last_played":{"description":"Количество времени в формате ISO, прошедшего с момента последнего воспроизведения","format":"duration","type":"string"},"is_paused":{"description":"Признак того что контент на паузе","type":"boolean"},"progress_left":{"description":"Оставшееся время до конца контента","format":"duration","type":"string"},"progress_passed":{"description":"Позиция в контенте, на которой пользователь находится в данный момент","format":"duration","type":"string"},"tv_channel_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"tv_channel_content_meta":{"description":"Метаинформация об телеканале","properties":{"channel_name":{"description":"Название телеканала","type":"string"},"program_name":{"description":"Название идущей сейчас телепередачи","type":"string"}},"type":"object"},"tv_stream_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"video_content_id":{"description":"Идентификатор видео контента, который воспроизводился последним","type":"string"},"video_content_meta":{"description":"Метаинформация об видеоконтенте","properties":{"content_audio":{"description":"Список доступных аудио, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id аудио","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это аудио, заполняется только в получении списка доступных аудио","type":"boolean"},"title":{"description":"Название аудио","type":"string"}},"type":"object"},"type":"array"},"content_qualities":{"description":"Список доступных качеств, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"description":{"description":"Описание качества","type":"string"},"id":{"description":"id качества","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это качество, заполняется только в получении списка доступных качеств","type":"boolean"}},"type":"object"},"type":"array"},"content_subtitles":{"description":"Список доступных субтитров, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id субтитров","type":"string"},"is_active":{"description":"Признак что сейчас выбраны эти субтитры, заполняется только при получении списка доступных субтитров","type":"boolean"},"title":{"description":"Название субтитров","type":"string"}},"type":"object"},"type":"array"},"description":{"description":"Описание сериала или фильма","type":"string"},"directors":{"description":"Режиссеры","items":{"type":"string"},"type":"array"},"duration":{"description":"Длительность серии или фильма","type":"string"},"episode_number":{"description":"Номер серии, который играл, заполняется только для сериала","type":"integer"},"genres":{"description":"Жанры, к которым относится фильм или сериал","items":{"type":"string"},"type":"array"},"release_year":{"description":"Год выпуска фильма или сериала","type":"integer"},"season_number":{"description":"Номер сезона, который играл, заполняется только для сериала","type":"integer"},"title":{"description":"Название фильма или сериала","type":"string"},"title_episode":{"description":"Название серии сериала, заполняется только для сериала","type":"string"},"type":{"description":"Тип видео: фильм, сериал или трейлер","enum":["FILM","SERIES","TRAILER","WEB_VIDEO"],"type":"string"}},"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}
[/AVAILABLE_TOOL]

[AVAILABLE_TOOL]
name: video_play_by_id
description: Включение видео контента по Id, в случае отсутствия лицензии открывается описание или QR-код для оплаты. Для сериала можно указать номер сезона, серии
parameters: {"properties":{"id":{"description":"Id видео контента","type":"string"},"launch_series_options":{"description":"Опции для сериала","properties":{"episode_number":{"description":"Серия, которую нужно включить","type":"integer"},"season_number":{"description":"Сезон, который нужно включить","type":"integer"}},"type":"object"}},"required":["id"],"type":"object"}
return_parameters: {"properties":{"episode":{"description":"Серия которую включили, заполняется только для сериала","type":"integer"},"name":{"description":"Название включённого видео контента","type":"string"},"reason_not_play":{"description":"Причина, по которой не удалось включить контент. NotLicense: Необходимо выбрать источник, где удобнее смотреть, NotPurchased: Контент платный, открывается QR-код на оплату, Continue: Контент уже играет, снимает воспроизведение с паузы если она есть, NotLicenseUser: Это платный контент, открывается описание","enum":["NotLicense","NotPurchased","Continue","NotLicenseUser"],"type":"string"},"season":{"description":"Сезон который включили, заполняется только для сериала","type":"integer"}},"type":"object"}
[/AVAILABLE_TOOL]

[DEVICE]
Текущая дата - 2024-12-09. Текущее время - 12:45:00. День недели - Понедельник
Устройство — Яндекс ТВ Станция с Алисой
На экране отображается: Главный экран
[/DEVICE]

[INST]включи мультфильм который мы вчера смотрели[/INST]

[REPLY]

Ожидаем, что модель, глядя на запрос, сгенерирует следующее:

[TOOL_CALL]get_last_played_content
{"content_type":"video"}
[/REPLY]

То есть сгенерирует токен обращения к функции ([TOOL_CALL]), запросит вызов функции get_last_played_content, передав тип контента «видео», так как речь о мультфильме. В этот момент генерация останавливается и обрабатывается. В результате парсинга становится понятно, какую функцию нужно позвать и какое значение аргумента передать. Все доступные функции Алисы зарегистрированы в специальной библиотеке, и система знает, как к ним нужно обратиться, что и происходит.

В результате вызова функции get_last_played_content возвращается новый объект — JSON‑результат её работы, который добавляется в конец промпта. В LLM отправляется новый запрос:

[AVAILABLE_TOOL]
name: get_last_played_content
description: Получение информации о последних прослушанных аудиотреках, проигранных видео и телеканалах
parameters: {"properties":{"content_type":{"description":"Тип контента, последнее воспроизведение которого хочется получить. Можно не указывать, если фильтрация не нужна.","enum":["audio","video"],"type":"string"}},"type":"object"}
return_parameters: {"properties":{"last_played_items":{"description":"Воспроизводимый ранее контент от недавнего к более старому","items":{"properties":{"audio_content_id":{"description":"Идентификатор аудио контента, который воспроизводился последним","properties":{"content_id":{"description":"ID музыки","type":"string"},"type":{"description":"Тип музыки","enum":["artist","album","playlist","track","recommendations","generative","fm_radio"],"type":"string"}},"type":"object"},"audio_content_meta":{"description":"Метаинформация об аудиоконтенте","properties":{"album_meta":{"description":"Метаинформация об альбоме","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artist_meta":{"description":"Метаинформация об исполнителе","properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"fm_radio_meta":{"description":"Метаинформация о FM-радиостанции","properties":{"id":{"description":"ID FM-радиостанции","type":"string"},"station_name":{"description":"Название FM-радиостанции","type":"string"}},"type":"object"},"generative_meta":{"description":"Метаинформация о Нейромузыке","properties":{"id":{"description":"ID Нейромузыки","type":"string"}},"type":"object"},"playlist_meta":{"description":"Метаинформация о плейлисте","properties":{"id":{"description":"ID плейлиста","type":"string"},"title":{"description":"Название плейлиста","type":"string"}},"type":"object"},"recommendations_meta":{"description":"Метаинформация о потоке рекомендаций","properties":{"id_composite":{"description":"ID составного потока рекомендаций - список ID базовых потоков рекомендаций, разделенных запятой","type":"string"},"seeds":{"description":"Метаинформация о базовых потоках рекомендаций. Порядок записей соответствует порядку ID в поле `id_composite`","items":{"properties":{"id":{"description":"ID базового потока рекомендаций. Может использоваться как отдельный идентификатор аудиоконтента с типом `recommendations`","type":"string"},"seed_name_human_readable":{"description":"Человекочитаемое название базового потока рекомендаций","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"track_meta":{"description":"Метаинформация о треке","properties":{"album":{"description":"Метаинформация об альбоме трека","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artists":{"description":"Метаинформация об исполнителях трека","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"duration":{"description":"Продолжительность трека","format":"duration","type":"string"},"id":{"description":"ID трека","type":"string"},"title":{"description":"Название трека","type":"string"}},"type":"object"}},"type":"object"},"duration_since_last_played":{"description":"Количество времени в формате ISO, прошедшего с момента последнего воспроизведения","format":"duration","type":"string"},"is_paused":{"description":"Признак того что контент на паузе","type":"boolean"},"progress_left":{"description":"Оставшееся время до конца контента","format":"duration","type":"string"},"progress_passed":{"description":"Позиция в контенте, на которой пользователь находится в данный момент","format":"duration","type":"string"},"tv_channel_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"tv_channel_content_meta":{"description":"Метаинформация об телеканале","properties":{"channel_name":{"description":"Название телеканала","type":"string"},"program_name":{"description":"Название идущей сейчас телепередачи","type":"string"}},"type":"object"},"tv_stream_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"video_content_id":{"description":"Идентификатор видео контента, который воспроизводился последним","type":"string"},"video_content_meta":{"description":"Метаинформация об видеоконтенте","properties":{"content_audio":{"description":"Список доступных аудио, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id аудио","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это аудио, заполняется только в получении списка доступных аудио","type":"boolean"},"title":{"description":"Название аудио","type":"string"}},"type":"object"},"type":"array"},"content_qualities":{"description":"Список доступных качеств, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"description":{"description":"Описание качества","type":"string"},"id":{"description":"id качества","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это качество, заполняется только в получении списка доступных качеств","type":"boolean"}},"type":"object"},"type":"array"},"content_subtitles":{"description":"Список доступных субтитров, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id субтитров","type":"string"},"is_active":{"description":"Признак что сейчас выбраны эти субтитры, заполняется только при получении списка доступных субтитров","type":"boolean"},"title":{"description":"Название субтитров","type":"string"}},"type":"object"},"type":"array"},"description":{"description":"Описание сериала или фильма","type":"string"},"directors":{"description":"Режиссеры","items":{"type":"string"},"type":"array"},"duration":{"description":"Длительность серии или фильма","type":"string"},"episode_number":{"description":"Номер серии, который играл, заполняется только для сериала","type":"integer"},"genres":{"description":"Жанры, к которым относится фильм или сериал","items":{"type":"string"},"type":"array"},"release_year":{"description":"Год выпуска фильма или сериала","type":"integer"},"season_number":{"description":"Номер сезона, который играл, заполняется только для сериала","type":"integer"},"title":{"description":"Название фильма или сериала","type":"string"},"title_episode":{"description":"Название серии сериала, заполняется только для сериала","type":"string"},"type":{"description":"Тип видео: фильм, сериал или трейлер","enum":["FILM","SERIES","TRAILER","WEB_VIDEO"],"type":"string"}},"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}
[/AVAILABLE_TOOL]

[AVAILABLE_TOOL]
name: video_play_by_id
description: Включение видео контента по Id, в случае отсутствия лицензии открывается описание или QR-код для оплаты. Для сериала можно указать номер сезона, серии
parameters: {"properties":{"id":{"description":"Id видео контента","type":"string"},"launch_series_options":{"description":"Опции для сериала","properties":{"episode_number":{"description":"Серия, которую нужно включить","type":"integer"},"season_number":{"description":"Сезон, который нужно включить","type":"integer"}},"type":"object"}},"required":["id"],"type":"object"}
return_parameters: {"properties":{"episode":{"description":"Серия которую включили, заполняется только для сериала","type":"integer"},"name":{"description":"Название включённого видео контента","type":"string"},"reason_not_play":{"description":"Причина, по которой не удалось включить контент. NotLicense: Необходимо выбрать источник, где удобнее смотреть, NotPurchased: Контент платный, открывается QR-код на оплату, Continue: Контент уже играет, снимает воспроизведение с паузы если она есть, NotLicenseUser: Это платный контент, открывается описание","enum":["NotLicense","NotPurchased","Continue","NotLicenseUser"],"type":"string"},"season":{"description":"Сезон который включили, заполняется только для сериала","type":"integer"}},"type":"object"}
[/AVAILABLE_TOOL]

[DEVICE]
Текущая дата - 2024-12-09. Текущее время - 12:45:00. День недели - Понедельник
Устройство — Яндекс ТВ Станция с Алисой
На экране отображается: Главный экран
[/DEVICE]

[INST]включи мультфильм который мы вчера смотрели[/INST]

[REPLY][TOOL_CALL]get_last_played_content
{"content_type":"video"}
[/REPLY]

[TOOL_RESULT]get_last_played_content
{"last_played_items":[
{"audio_content_id":{"content_id":"12","type":"playlist"},"audio_content_meta":{"track_meta":{"album":{"artists":[{"id":"10","name":"Robert DeLong"}],"id":"9","title":"In the Cards","tracks_count":11,"year":2015},"artists":[{"id":"10","name":"Robert DeLong"}],"duration":"PT3M54.63S","id":"11","title":"Don't Wait Up"}},"duration_since_last_played":"PT38M43S","progress_left":"PT3M48.967S","progress_passed":"PT5.033S"},
{"video_content_id":"15","duration_since_last_played":"P1DT22H47M59S","video_content_meta":{"title":"Лунтик","genres":["мультфильм"],"duration":"PT5M41S","episode_number":8,"release_year":2006,"season_number":1,"title_episode":"Пиявка"},"progress_left":"PT3M58S","progress_passed":"PT1M43S"}
]}
[/TOOL_RESULT]

[REPLY]

На втором шаге уже и предыдущая генерация и результат работы функции лежат в промпте. Ожидается, что модель сгенерирует следующий вызов video_play_by_id и передаст туда video_content_id мультфильма «Лунтик» из ответа тулы get_last_played_content.

[TOOL_CALL]video_play_by_id
{"id":"15"}
[/REPLY]

Генерация снова останавливается, анализируется ответ, вызывается функция video_play_by_id с переданным аргументом. Результат снова дописывается в промпт, и происходит третий вызов языковой модели.

[AVAILABLE_TOOL]
name: get_last_played_content
description: Получение информации о последних прослушанных аудиотреках, проигранных видео и телеканалах
parameters: {"properties":{"content_type":{"description":"Тип контента, последнее воспроизведение которого хочется получить. Можно не указывать, если фильтрация не нужна.","enum":["audio","video"],"type":"string"}},"type":"object"}
return_parameters: {"properties":{"last_played_items":{"description":"Воспроизводимый ранее контент от недавнего к более старому","items":{"properties":{"audio_content_id":{"description":"Идентификатор аудио контента, который воспроизводился последним","properties":{"content_id":{"description":"ID музыки","type":"string"},"type":{"description":"Тип музыки","enum":["artist","album","playlist","track","recommendations","generative","fm_radio"],"type":"string"}},"type":"object"},"audio_content_meta":{"description":"Метаинформация об аудиоконтенте","properties":{"album_meta":{"description":"Метаинформация об альбоме","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artist_meta":{"description":"Метаинформация об исполнителе","properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"fm_radio_meta":{"description":"Метаинформация о FM-радиостанции","properties":{"id":{"description":"ID FM-радиостанции","type":"string"},"station_name":{"description":"Название FM-радиостанции","type":"string"}},"type":"object"},"generative_meta":{"description":"Метаинформация о Нейромузыке","properties":{"id":{"description":"ID Нейромузыки","type":"string"}},"type":"object"},"playlist_meta":{"description":"Метаинформация о плейлисте","properties":{"id":{"description":"ID плейлиста","type":"string"},"title":{"description":"Название плейлиста","type":"string"}},"type":"object"},"recommendations_meta":{"description":"Метаинформация о потоке рекомендаций","properties":{"id_composite":{"description":"ID составного потока рекомендаций - список ID базовых потоков рекомендаций, разделенных запятой","type":"string"},"seeds":{"description":"Метаинформация о базовых потоках рекомендаций. Порядок записей соответствует порядку ID в поле `id_composite`","items":{"properties":{"id":{"description":"ID базового потока рекомендаций. Может использоваться как отдельный идентификатор аудиоконтента с типом `recommendations`","type":"string"},"seed_name_human_readable":{"description":"Человекочитаемое название базового потока рекомендаций","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"track_meta":{"description":"Метаинформация о треке","properties":{"album":{"description":"Метаинформация об альбоме трека","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artists":{"description":"Метаинформация об исполнителях трека","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"duration":{"description":"Продолжительность трека","format":"duration","type":"string"},"id":{"description":"ID трека","type":"string"},"title":{"description":"Название трека","type":"string"}},"type":"object"}},"type":"object"},"duration_since_last_played":{"description":"Количество времени в формате ISO, прошедшего с момента последнего воспроизведения","format":"duration","type":"string"},"is_paused":{"description":"Признак того что контент на паузе","type":"boolean"},"progress_left":{"description":"Оставшееся время до конца контента","format":"duration","type":"string"},"progress_passed":{"description":"Позиция в контенте, на которой пользователь находится в данный момент","format":"duration","type":"string"},"tv_channel_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"tv_channel_content_meta":{"description":"Метаинформация об телеканале","properties":{"channel_name":{"description":"Название телеканала","type":"string"},"program_name":{"description":"Название идущей сейчас телепередачи","type":"string"}},"type":"object"},"tv_stream_content_id":{"description":"Идентификатор телеканала, который воспроизводился последним","type":"string"},"video_content_id":{"description":"Идентификатор видео контента, который воспроизводился последним","type":"string"},"video_content_meta":{"description":"Метаинформация об видеоконтенте","properties":{"content_audio":{"description":"Список доступных аудио, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id аудио","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это аудио, заполняется только в получении списка доступных аудио","type":"boolean"},"title":{"description":"Название аудио","type":"string"}},"type":"object"},"type":"array"},"content_qualities":{"description":"Список доступных качеств, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"description":{"description":"Описание качества","type":"string"},"id":{"description":"id качества","type":"string"},"is_active":{"description":"Признак что сейчас выбрано это качество, заполняется только в получении списка доступных качеств","type":"boolean"}},"type":"object"},"type":"array"},"content_subtitles":{"description":"Список доступных субтитров, заполняется только для текущего видеоконтента в плеере","items":{"properties":{"id":{"description":"id субтитров","type":"string"},"is_active":{"description":"Признак что сейчас выбраны эти субтитры, заполняется только при получении списка доступных субтитров","type":"boolean"},"title":{"description":"Название субтитров","type":"string"}},"type":"object"},"type":"array"},"description":{"description":"Описание сериала или фильма","type":"string"},"directors":{"description":"Режиссеры","items":{"type":"string"},"type":"array"},"duration":{"description":"Длительность серии или фильма","type":"string"},"episode_number":{"description":"Номер серии, который играл, заполняется только для сериала","type":"integer"},"genres":{"description":"Жанры, к которым относится фильм или сериал","items":{"type":"string"},"type":"array"},"release_year":{"description":"Год выпуска фильма или сериала","type":"integer"},"season_number":{"description":"Номер сезона, который играл, заполняется только для сериала","type":"integer"},"title":{"description":"Название фильма или сериала","type":"string"},"title_episode":{"description":"Название серии сериала, заполняется только для сериала","type":"string"},"type":{"description":"Тип видео: фильм, сериал или трейлер","enum":["FILM","SERIES","TRAILER","WEB_VIDEO"],"type":"string"}},"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}
[/AVAILABLE_TOOL]

[AVAILABLE_TOOL]
name: video_play_by_id
description: Включение видео контента по Id, в случае отсутствия лицензии открывается описание или QR-код для оплаты. Для сериала можно указать номер сезона, серии
parameters: {"properties":{"id":{"description":"Id видео контента","type":"string"},"launch_series_options":{"description":"Опции для сериала","properties":{"episode_number":{"description":"Серия, которую нужно включить","type":"integer"},"season_number":{"description":"Сезон, который нужно включить","type":"integer"}},"type":"object"}},"required":["id"],"type":"object"}
return_parameters: {"properties":{"episode":{"description":"Серия которую включили, заполняется только для сериала","type":"integer"},"name":{"description":"Название включённого видео контента","type":"string"},"reason_not_play":{"description":"Причина, по которой не удалось включить контент. NotLicense: Необходимо выбрать источник, где удобнее смотреть, NotPurchased: Контент платный, открывается QR-код на оплату, Continue: Контент уже играет, снимает воспроизведение с паузы если она есть, NotLicenseUser: Это платный контент, открывается описание","enum":["NotLicense","NotPurchased","Continue","NotLicenseUser"],"type":"string"},"season":{"description":"Сезон который включили, заполняется только для сериала","type":"integer"}},"type":"object"}
[/AVAILABLE_TOOL]

[DEVICE]
Текущая дата - 2024-12-09. Текущее время - 12:45:00. День недели - Понедельник
Устройство — Яндекс ТВ Станция с Алисой
На экране отображается: Главный экран
[/DEVICE]

[INST]включи мультфильм который мы вчера смотрели[/INST]

[REPLY][TOOL_CALL]get_last_played_content
{"content_type":"video"}
[/REPLY]

[TOOL_RESULT]get_last_played_content
{"last_played_items":[
{"audio_content_id":{"content_id":"12","type":"playlist"},"audio_content_meta":{"track_meta":{"album":{"artists":[{"id":"10","name":"Robert DeLong"}],"id":"9","title":"In the Cards","tracks_count":11,"year":2015},"artists":[{"id":"10","name":"Robert DeLong"}],"duration":"PT3M54.63S","id":"11","title":"Don't Wait Up"}},"duration_since_last_played":"PT38M43S","progress_left":"PT3M48.967S","progress_passed":"PT5.033S"},
{"video_content_id":"15","duration_since_last_played":"P1DT22H47M59S","video_content_meta":{"title":"Лунтик","genres":["мультфильм"],"duration":"PT5M41S","episode_number":8,"release_year":2006,"season_number":1,"title_episode":"Пиявка"},"progress_left":"PT3M58S","progress_passed":"PT1M43S"}
]}
[/TOOL_RESULT]

[REPLY][TOOL_CALL]video_play_by_id
{"id":"15"}
[/REPLY]

[TOOL_RESULT]video_play_by_id
{"name":"Лунтик","season":1,"episode":8}
[/TOOL_RESULT]

[REPLY]

На этой стадии задача пользователя решена. Модель просто отвечает:

Включаю мультфильм «Лунтик»[/REPLY]

Схематично это выглядит так:

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

Благодаря использованию LLM Алиса может эффективно учитывать контекст беседы при принятии решения по обработке действий. Так можно включить какую‑то серию сериала, а потом попросить включить следующий сезон. Или засечь таймер, а потом поправить его — модель в истории будет видеть конкретный экземпляр таймера, который нужно исправить, ей не придётся запрашивать все таймеры ещё раз.

Всё это наделяет Алису новым свойством — устойчивостью к пользовательским ошибкам. Раньше было очень важно идеально распознать запрос пользователя и всё уточнить, если информации недостаточно, так как было довольно сложно реализовать обработку исправлений. Цена ошибки, когда Алиса не понимала пользователя, была слишком большой. Новый подход снимает эту преграду: Алиса сможет смелее предугадывать, что нужно сделать, а пользователи легко смогут поправить её, если что‑то пошло не так.

Рассмотрим пример, где модель видит не только историю диалога, но и контекст экрана на момент запроса пользователя. Представим, что пользователь просит: «Алиса, найди комедии». В результате открывается экран поисковой выдачи с перечнем фильмов. Дальше пользователь просит: «Оставь только те, которые с высоким рейтингом».

[AVAILABLE_TOOL]
name: content_search
description: Поиск аудио, радио, телепередач, каналов, видео контента, включая поиск по YouTube и другим стримминговым сервисам. Если пользователь явно указывает в запросе тип контента (видео/музыка/канал/фильм/сериал/песня/альбом/мультфильм/подкаст/аудиокнигу/радио и пр) или провайдера, на котором включить (кинопоиск, ivi, Youtube и пр), то оставляй его в тексте запроса.  Открывает экран поисковой выдачи, если конкретное видео не будет включено или открыто в рамках другой функции
parameters: {"properties":{"query":{"description":"Поисковый запрос. Если пользователь указал, то нужно передать номера серий, сезонов, частей, глав и подобное","type":"string"}},"required":["query"],"type":"object"}
return_parameters: {"properties":{"audio_search_results":{"description":"Список музыкальных документов. Для включения можно использовать функцию `audio_play`","items":{"properties":{"audio_content_meta":{"description":"Метаинформация найденного аудиоконтента","properties":{"album_meta":{"description":"Метаинформация об альбоме","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artist_meta":{"description":"Метаинформация об исполнителе","properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"fm_radio_meta":{"description":"Метаинформация о FM-радиостанции","properties":{"id":{"description":"ID FM-радиостанции","type":"string"},"station_name":{"description":"Название FM-радиостанции","type":"string"}},"type":"object"},"generative_meta":{"description":"Метаинформация о Нейромузыке","properties":{"id":{"description":"ID Нейромузыки","type":"string"}},"type":"object"},"playlist_meta":{"description":"Метаинформация о плейлисте","properties":{"id":{"description":"ID плейлиста","type":"string"},"title":{"description":"Название плейлиста","type":"string"}},"type":"object"},"recommendations_meta":{"description":"Метаинформация о потоке рекомендаций","properties":{"id_composite":{"description":"ID составного потока рекомендаций - список ID базовых потоков рекомендаций, разделенных запятой","type":"string"},"seeds":{"description":"Метаинформация о базовых потоках рекомендаций. Порядок записей соответствует порядку ID в поле `id_composite`","items":{"properties":{"id":{"description":"ID базового потока рекомендаций. Может использоваться как отдельный идентификатор аудиоконтента с типом `recommendations`","type":"string"},"seed_name_human_readable":{"description":"Человекочитаемое название базового потока рекомендаций","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"track_meta":{"description":"Метаинформация о треке","properties":{"album":{"description":"Метаинформация об альбоме трека","properties":{"artists":{"description":"Метаинформация об исполнителях, участвовавших в записи альбома","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"genre_catalog_id":{"description":"Жанр альбома, представленный в виде для внутреннего использования","type":"string"},"id":{"description":"ID альбома","type":"string"},"title":{"description":"Название альбома","type":"string"},"tracks_count":{"description":"Количество треков в альбоме","type":"integer"},"year":{"description":"Год выпуска альбома","type":"integer"}},"type":"object"},"artists":{"description":"Метаинформация об исполнителях трека","items":{"properties":{"id":{"description":"ID исполнителя","type":"string"},"name":{"description":"Имя, псевдоним или название исполнителя","type":"string"}},"type":"object"},"type":"array"},"duration":{"description":"Продолжительность трека","format":"duration","type":"string"},"id":{"description":"ID трека","type":"string"},"title":{"description":"Название трека","type":"string"}},"type":"object"}},"type":"object"},"id":{"description":"ID найденного аудиоконтента","type":"string"},"type":{"description":"Тип найденного аудиоконтента","enum":["artist","album","playlist","track","recommendations","generative","fm_radio"],"type":"string"}},"type":"object"},"type":"array"},"films":{"description":"Список фильмов и сериалов из онлайн кинотеатров. Если список пустой, то фильма по запросу не существует. Если список из одного элемента, то найден конкретный фильм. Для включения можно использовать функцию `video_play_by_id`, для открытия карточки `open_film_by_id","items":{"properties":{"country":{"description":"Страны","items":{"type":"string"},"type":"array"},"film_name":{"description":"Название фильма или сериала","type":"string"},"genres":{"description":"Жанры, к которым относится контент","items":{"type":"string"},"type":"array"},"id":{"description":"Id видео контента","type":"string"},"launch_series_options":{"description":"Опции для сериала","properties":{"episode_number":{"description":"Серия, которую нужно включить","type":"integer"},"season_number":{"description":"Сезон, который нужно включить","type":"integer"}},"type":"object"},"rating":{"description":"Рейтинг контента на кинопоиске","type":"number"},"release_year":{"description":"Год производства","type":"integer"},"type":{"description":"Тип: фильм, сериал, видео, или трейлер","enum":["FILM","SERIES","TRAILER","WEB_VIDEO"],"type":"string"}},"type":"object"},"type":"array"},"programs":{"description":"Список телепередач. Для включения можно использовать функцию `turn_on_tv_channel`","items":{"properties":{"channel_title":{"description":"Название телеканала с заданной передачей","type":"string"},"content_id":{"description":"Идентификатор телеканала с заданной передачей","type":"string"},"is_currently_playing":{"description":"Признак того, идёт ли сейчас телепередача","type":"boolean"},"program_end_time":{"description":"Время окончания телепередачи в формате YYYY:MM:DDThh:mm:ss","format":"date-time","type":"string"},"program_start_time":{"description":"Время начала телепередачи в формате YYYY:MM:DDThh:mm:ss","format":"date-time","type":"string"},"program_title":{"description":"Название телепередачи","type":"string"}},"type":"object"},"type":"array"},"tv_channels":{"description":"Список телеканалов. Для включения можно использовать функцию `turn_on_tv_channel`","items":{"properties":{"categories":{"description":"Список категорий телеканала","items":{"type":"string"},"type":"array"},"content_id":{"description":"Идентификатор телеканала","type":"string"},"current_program":{"description":"Идущая сейчас передача на тв-канале","properties":{"description":{"description":"Описание передачи","type":"string"},"end":{"description":"Дата и время конца передачи в формате YYYY-MM-DDThh:mm","type":"string"},"start":{"description":"Дата и время начала передачи в формате YYYY-MM-DDThh:mm","type":"string"},"title":{"description":"Название передачи","type":"string"}},"type":"object"},"description":{"description":"Описание телеканала","type":"string"},"title":{"description":"Название телеканала","type":"string"}},"type":"object"},"type":"array"},"videos":{"description":"Список видео из интернета. Для включения можно использовать функцию `video_play_by_id`","items":{"properties":{"id":{"description":"Id видео контента","type":"string"},"provider":{"description":"Провайдер видео","type":"string"},"title":{"description":"Заголовок видео","type":"string"}},"type":"object"},"type":"array"}},"type":"object"}
[/AVAILABLE_TOOL]

[INST]найди комедии[/INST]

[REPLY]Вот что удалось найти.[/REPLY]

[DEVICE]
Текущая дата - 2024-12-09. Текущее время - 12:45:00. День недели - Понедельник
Устройство — Яндекс ТВ Станция с Алисой
На экране отображается: Результаты поиска по запросу "Комедии"
Найденный видеоконтент: 
1. Бар `Гадкий койот` (фильм, Id: "1")
2. Евротур (фильм, Id: "2")
3. Терминал (фильм, Id: "3")
4. Мамма Mia! (фильм, Id: "4")
5. Война невест (фильм, Id: "5")
6. Похождения императора (фильм, Id: "6")
7. Знакомство с родителями (фильм, Id: "7")
8. Братья Гримм (фильм, Id: "8")
9. 500 дней лета (фильм, Id: "9")
10. Ты водишь! (фильм, Id: "10")
[/DEVICE]

[INST]оставь только те которые с высоким рейтингом[/INST]

[REPLY][TOOL_CALL]content_search
{"query":"комедии с высоким рейтингом"}
[/REPLY]

[TOOL_RESULT]content_search
{"films":[{"film_name":"Назад в будущее","genres":["фантастика","комедия"],"id":"31","rating":8.65,"release_year":1985,"type":"FILM"},{"film_name":"Карты, деньги, два ствола","genres":["боевик","комедия"],"id":"32","rating":8.56,"release_year":1998,"type":"FILM"},{"film_name":"Десятое королевство","genres":["фэнтези","мелодрама"],"id":"33","rating":8.47,"release_year":2000,"type":"SERIES"},{"film_name":"Шоу Трумана","genres":["драма","комедия"],"id":"34","rating":8.28,"release_year":1998,"type":"FILM"},{"film_name":"Наследники","genres":["комедия","драма"],"id":"35","rating":8.13,"release_year":2018,"type":"SERIES"},{"film_name":"Терминал","genres":["драма","мелодрама"],"id":"3","rating":8.12,"release_year":2004,"type":"FILM"},{"film_name":"Мадагаскар","genres":["мультфильм","комедия"],"id":"36","rating":8,"release_year":2005,"type":"FILM"},{"film_name":"Реальная любовь","genres":["мелодрама","комедия"],"id":"37","rating":7.94,"release_year":2003,"type":"FILM"},{"film_name":"Мальчишник в Вегасе","genres":["комедия"],"id":"38","rating":7.87,"release_year":2009,"type":"FILM"},{"film_name":"История рыцаря","genres":["боевик","мелодрама"],"id":"39","rating":7.82,"release_year":2001,"type":"FILM"},{"film_name":"10 причин моей ненависти","genres":["драма","мелодрама"],"id":"40","rating":7.82,"release_year":1999,"type":"FILM"},{"film_name":"С любовью, Рози","genres":["мелодрама","комедия"],"id":"41","rating":7.73,"release_year":2014,"type":"FILM"},{"film_name":"Синдбад: Легенда семи морей","genres":["мультфильм","фэнтези"],"id":"42","rating":7.72,"release_year":2003,"type":"FILM"},{"film_name":"Идеальные незнакомцы","genres":["драма","комедия"],"id":"43","rating":7.7,"release_year":2016,"type":"FILM"},{"film_name":"Грязь","genres":["комедия"],"id":"44","rating":7.65,"release_year":2013,"type":"FILM"},{"film_name":"500 дней лета","genres":["мелодрама","комедия"],"id":"9","rating":7.64,"release_year":2009,"type":"FILM"},{"film_name":"Евротур","genres":["комедия"],"id":"2","rating":7.59,"release_year":2004,"type":"FILM"},{"film_name":"Знакомство с родителями","genres":["мелодрама","комедия"],"id":"7","rating":7.54,"release_year":2000,"type":"FILM"},{"film_name":"Реальные упыри","genres":["комедия","ужасы"],"id":"45","rating":7.45,"release_year":2014,"type":"FILM"},{"film_name":"Аэроплан","genres":["комедия"],"id":"46","rating":7.44,"release_year":1980,"type":"FILM"},{"film_name":"Игра на понижение","genres":["драма","комедия"],"id":"47","rating":7.37,"release_year":2015,"type":"FILM"},{"film_name":"Как отделаться от парня за 10 дней","genres":["мелодрама","комедия"],"id":"48","rating":7.33,"release_year":2003,"type":"FILM"},{"film_name":"Притворись моей женой","genres":["мелодрама","комедия"],"id":"49","rating":7.27,"release_year":2011,"type":"FILM"},{"film_name":"100 вещей и ничего лишнего","genres":["комедия","драма"],"id":"50","rating":7.27,"release_year":2018,"type":"FILM"},{"film_name":"Ослеплённый желаниями","genres":["фэнтези","комедия"],"id":"51","rating":7.24,"release_year":2000,"type":"FILM"},{"film_name":"Давайте потанцуем","genres":["драма","мелодрама"],"id":"52","rating":7.2,"release_year":2004,"type":"FILM"},{"film_name":"Знакомство с Факерами","genres":["мелодрама","комедия"],"id":"53","rating":7.11,"release_year":2004,"type":"FILM"},{"film_name":"Мисс Конгениальность","genres":["боевик","комедия"],"id":"54","rating":7.09,"release_year":2000,"type":"FILM"},{"film_name":"Ночь в музее","genres":["фэнтези","комедия"],"id":"55","rating":7.04,"release_year":2006,"type":"FILM"},{"film_name":"Братья Гримм","genres":["фэнтези","боевик"],"id":"8","rating":7.01,"release_year":2005,"type":"FILM"}],"videos":[{"id":"11","provider":"rutube","title":"Фильм: Рассмеши меня 2023 Фильм со смыслом!  Жанр: Комедия Рейтинг (8.7) #кино #фильмы"},{"id":"12","provider":"ok","title":"Летняя Комедия С Дмитрием Нагиевым!  Девушки бывают разные.  Лучшие комедии, российские комедии"},{"id":"13","provider":"mailru_new","title":"Тузики Веселые Русские Комедии Семейные комедии Молодежные комедии קומדיה רוסית Новинки кино фильмы – смотреть видео онлайн в Моем Мире | Борис Karlchorst"},{"id":"14","provider":"rutube","title":"10 Лучших Американских Комедий за Последние 20 Лет !"},{"id":"15","provider":"vk","title":"Вид со скалы/View from the cliff 2024 / мелодрама, комедия, музыка"},{"id":"16","provider":"mailru_new","title":"Шикарная Комедия HD 2015  \"Запах вереска\" (Русские фильмы, комедии 2015)"},{"id":"17","provider":"mailru_new","title":"Комедия!  \"Хочу замуж\" | Новые русские комедии в HD"},{"id":"18","provider":"rutube","title":"Доброе кино для всей семьи!  \"Любовь С Доставкой НА ДОМ\" (добрая романтическая комедия)"},{"id":"19","provider":"vk","title":"Притчи 2 /комедия, семейный"},{"id":"20","provider":"rutube","title":"Русские комедии с высоким рейтингом I очень смешные комедии I веселые русские комедии"},{"id":"21","provider":"rutube","title":"ТОП-10 Лучших Комедий (2023)"},{"id":"22","provider":"ok","title":"Видео Ржачная Комедия 2020 [[Упакованные ]] Русские Комедии 2020 КИНО Новинки HD ¦ НАШИ Новые Фильмы | OK.RU"},{"id":"23","provider":"rutube","title":"Бесподобная Комедия!  ВАМ Понравится!  - Здравствуйте, мы ваша крыша!  Русские комедии"},{"id":"24","provider":"mailru_new","title":"Смешная Комедия ДАМ, НО НЕ ВАМ 2016, новые комедии и русские фильмы – смотреть видео онлайн в Моем Мире | Евгений ХрамоV"},{"id":"25","provider":"rutube","title":"Комедии с высоким рейтингом I самые смешные комедии l кинокомедии l топ смешных комедий"},{"id":"26","provider":"rutube","title":"Лучшие комедии (2022-2023) | топ новых и старых комедий | смешные фильмы | новинки"},{"id":"27","provider":"rutube","title":"Комедии с высоким рейтингом I самые смешные комедии l кинокомедии l топ смешных комедий"},{"id":"28","provider":"mailru_new","title":"Шикарная русская комедия!!!  С 8 марта мужчины!  Русские комедий, комедии онлайн, лучшие комедии – смотреть видео онлайн в Моем Мире | Таня Яровая"},{"id":"29","provider":"mailru_new","title":"Отличный Фильм, Хорошая Легкая Комедия - \"Крепкий брак\" (Русское кино, Русские комедии) – смотреть видео онлайн в Моем Мире | Павел Никитин"},{"id":"30","provider":"rutube","title":"Топ-15 лучших комедий 1-й половины 2023 года"}]}
[/TOOL_RESULT]

[REPLY]

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

Для LLM нет ограничений, что можно делать только одно действие за раз. Она может вызвать несколько тулов одновременно, поставить лайк нескольким фильмам за раз и включить какой‑то другой. А ещё сразу выставить громкость.

От идеи до реальной работы

Выше изложена принципиальная схема работы LLM, но в таком виде внедрить её в Алису было невозможно:

  • Во‑первых, как мы узнали, какие тулы нужно показать в подводке модели? В примере выше их всего два и оба нужные.

  • Во‑вторых, три похода в LLM — слишком долгое мероприятие, а замедляться никак нельзя.

  • В‑третьих, нужно обеспечить обратную совместимость со старой архитектурой, чтобы не пытаться написать ассистента с нуля.

Попытка описать существующую Алису в ТВ Станциях в виде набора тулов сразу привела к необходимости реализовать несколько сотен функций. Чтобы научить модель пользоваться ими, нам пришлось создать специальную среду для тренировки: AI‑тренеры брали запросы, заданные поверх различных состояний устройств, времени и места, и решали их так же, как это сделает модель.

  1. Делали настоящие вызовы тулов.

  2. Анализировали и обрабатывали результаты их работы.

  3. Делали дальнейшие вызовы.

  4. Писали финальные ответы, как их должна давать Алиса.

  5. Писали обработку ошибок.

На рисунке выше пример интерфейса, в котором работает AI‑тренер. Здесь для обработки запроса он позвал три функции на первом этапе, чтобы создать запись в списке дел и напоминание, а также он узнаёт настроенные будильники, чтобы на втором этапе удалить нужный. В каждом вызове он в специальной форме заполняет аргументы обращения к функции и выполняет вызов, в котором работает весь стек Алисы. То есть ровно те же действия, которые происходят в рантайме при вызове этой же функции в самой модели.

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

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

Думай быстро, решай быстро

Одна из эффективных техник по ускорению инференса моделей на типовых задачах — переиспользование KV Cache между запросами. Её часто используют, когда нужно выполнить генерацию для множества инстрактов, обладающих общим префиксом. Тогда можно один раз посчитать матрицы для всех токенов общего префикса, держать их в памяти GPU и в каждый следующий раз рассчитывать веса только для меняющихся частей инстракта. Мы решили воспользоваться этим подходом.

Мы структурировали промпт таким образом, чтобы по мере продвижения в его решении он только дописывался. Сначала идёт набор релевантных тулов, который константен внутри одного текста запроса и часто может переиспользоваться между запросами разных пользователей. Дальше идут данные, которые характерны для конкретного запроса (дата, время, состояние устройства) — они тоже остаются постоянными внутри одного запроса.

Сетевая архитектура Алисы позволяет гибко управлять маршрутизацией сетевого трафика, за счёт чего мы смогли добиться того, что все запросы к LLM внутри одного запроса попадали на один физический хост с GPU. За счёт этого KV Cache начинает эффективно работать внутри запроса, этап расчёта весов для префикса делается один раз в самом начале, и дальше обработка состоит из небольших генераций вызовов функций.

Бдительный читатель мог заметить, что в промпте все идентификаторы необычные: 1, 2 и т. д. Дело в том, что самое долгое для модели — генерация токенов. Оказалось, что существенную их часть составляли идентификаторы. UUID и другие случайные величины плохо токенизируются и модели приходится использовать много шагов генерации, чтобы их воссоздать. На это неэффективно расходуются вычислительные ресурсы и тратится время. Мы решили прятать от модели исходные идентификаторы и заменяем реальные идентификаторы простейшими в рантайме, а при обучении — на разные случайные величины, чтобы модель не обращала на них внимания. Это позволяет ускорить генерацию одного ID в десятки раз.

В итоге самая большая генерация — это формирование финального ответа пользователю. Важное свойство финального ответа в том, что мы знаем, что он финальный и дальнейшей обработки запроса не будет. Вместо того, чтобы дожидаться его генерации для возврата пользователю, можно стримить его, то есть отдавать пользователю и озвучивать синтезом речи прямо по мере генерации. Тогда пользователь получает ответ в момент начала генерации, а не тогда, когда она закончится. Этот приём эффективно используется в Алисе уже год, с появления в ней YandexGPT.

Что делать с накопленным багажом

Появление новой архитектуры — это большое событие для Алисы. Но что делать с 7 годами опыта, сценариев и умений, которые уже давно есть в ней и хорошо себя показывают? Максимально переиспользовать их! Мы смогли изменить наши фреймворки написания сценариев так, чтобы для обработки запросов в тулы и обычные сценарии было максимум общего кода.

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

Для обработки этого случая мы придумали специальную функцию.

[AVAILABLE_TOOL]
name: assistant_help
description: Используется в случае, если невозможно решить запрос с использованием остальных доступных функций.
parameters: {"properties":{"query":{"description":"Запрос пользователя, перефразированный так, чтобы для его понимания не требовалась предыдущая история общения с пользователем.","minLength":1,"type":"string"}},"required":["query"],"type":"object"}
return_parameters: {"properties":{},"type":"object"}
[/AVAILABLE_TOOL]

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


Появление смарт‑функций и большой языковой модели знаменует собой переход к третьей версии архитектуры Алисы, когда она становится полноценным LLM‑агентом. Новый подход открывает возможность вывести универсальность и возможности Алисы на следующий уровень, научить её выполнять более сложные запросы. А ещё стать естественнее и человечнее не только в диалоге, но и в решении повседневных пользовательских задач.

Комментарии (6)


  1. konst90
    12.12.2024 08:13

    Теперь нейросеть сама разложит запрос на два действия — посмотрит, сколько осталось до конца, и поставит таймер выключения на это время.

    А судья назначает дополнительное время, и телевизор выключается на самом интересном месте.


  1. LesnoyChelovek
    12.12.2024 08:13

    Дальше я расскажу, как мы это собираемся делать.

    А можно вы потом расскажите, как у вас в итоге получилось?

    Потому что сейчас статья выглядит маркетинговый материал, который унесли начальству, чтобы оно дало денег


  1. greenlittlefrog
    12.12.2024 08:13

    В какой момент ваших маркетологов что-то ужалит чуть пониже спины и они начнут использовать данные с LLM (в какое время человек ложится спать, что смотрит, есть ли акцент и т.д) для показа "ненавязчивой" рекламы? Вы за последний год добавили рекламу в:

    Яндекс Go теперь на 30% экрана завешан рекламой
    Кинопоиск теперь с левой рекламой даже у платных пользователей
    Яндекс Музыка теперь с левой рекламой даже у платных пользователей
    Умный дом - всплывающая реклама на весь экран
    Постоянно какой-то дебильный Плюс Дейли всплывает

    Признавайтесь, сколько кода было написано для составление рекламного портрета пользователя?


  1. almirus
    12.12.2024 08:13

    Не знаю куда все это внедряется и используется, дома Станция Мини new, Яндекс Лайт, говоришь "Алиса включи подсветку", ожидая что включатся в комнате, где она услышала, устройства с именами "подсветка панно", "подсветка под телевизором", звук "успешности" есть, включения нет. Нужно говорить или точные названия или "включи светодиодную ленту" (у них такой тип). "Какой уровень CO2 в квартире?" - "Вы хотите узнать уровень углекислого газа в квартире?" - "Да", зачем уточняющий вопрос?

    Есть сценарий с запуском по ключевым словам "Жду курьера", иногда Алиса начинает отвечать, шутить на эту фразу, а не исполнять сценарий.

    Спрашиваешь "Когда закат", Алиса зачем то, добавляет в конце "...это с сайта yandex.ru если что".

    Месяц назад сервис озвучивания (из умного дома HA) стал рандомно возвращать статус 403

    https://iot.quasar.yandex.ru/m/user/scenarios/dХХХХХХХ-cХХХ-4ХХХХХХХХХХХ5 return 403 status


    1. Lizdroz
      12.12.2024 08:13

      Недоработки мб и есть, но они фиксятся, обновляют постоянно, прокачивают и тд, не все же сразу) Но даже щас объективно говоря умнее Алисы голосовых помощников нет, и это не предел


  1. evgs89
    12.12.2024 08:13

    Ещё момент - колонка стоит в спальне. Прошу: "включи свет". Звук есть, света нет. Надо уточнять комнату - неужели нельзя по умолчанию включать приборы в комнате, где стоит колонка, если не указано иначе?
    Если у устройства не уникальное имя - то же самое. Если не уточняешь комнату - не срабатывает ни одно.
    Ну и Спальня Маши и Машина Спальня - для Алисы не одно и то же, и нет возможности записать синонимы, а это было бы удобно.