Главная / Статьи / Голосовые агенты и исправления: почему мало правильно расслышать номер заказа

Голосовые агенты и исправления: почему мало правильно расслышать номер заказа

Голосовой агент повторил исправленный номер заказа, но изменил не тот заказ. Разбираем, как устаревшие вызовы инструментов переживают перебивание и как их ловят конечные автоматы и трассировки.

1121 слов

Подтверждение, которое звучало правильно

Клиент просит голосового агента перенести доставку заказа 4821 на пятницу. Не дав агенту договорить, клиент вставляет поправку: номер 4281, а не 4821. Агент останавливается на полуслове, соглашается и обещает обновить заказ 4281.

Звонок заканчивается на хорошей ноте. Но система изменила заказ 4821, а заказ 4281 так никто и не тронул.

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

Почему транскрипт — это не состояние

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

Conversation history   →  4821, then a correction to 4281
Active intent          →  the order the customer currently means
Pending action         →  the order ID already loaded into the tool call
Backend state          →  the order that was actually written

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

Запись о том, что было сказано, оказалась точной. Сломался переход состояния.

Как выжило устаревшее значение

Чтобы так вышло, достаточно трёх обычных проектных решений, и в большинстве голосовых стеков есть все три.

История, которая только растёт

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

Инструменты, подготовленные слишком рано

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

Несколько копий одного факта

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

Что показывает трассировка

Ни транскрипт, ни финальный голосовой ответ ничего этого не раскрывают. Это видно только в трассировке выполнения с метками времени:

10:03:12.100  Customer mentions order 4821
10:03:12.420  Active state set: order_id = 4821
10:03:13.000  Update tool prepared: order_id = 4821
10:03:13.250  Customer interrupts: "Sorry, I meant 4281."
10:03:13.510  Conversation state updated:  order_id = 4281
10:03:13.700  Previously prepared tool executes: order_id = 4821
10:03:14.100  Agent says: "I've updated order 4281."

Исправление пришло в 13.510, а вызов инструмента был зафиксирован ещё в 13.000. Всё после этой фиксации, включая голосовое подтверждение, отражает значение, которое больше не совпадает с желанием клиента. Оценка, проверяющая, уловил ли транскрипт исправление или назвал ли ответ правильный заказ, этот звонок пропустила бы. Расхождение выдаёт только трассировка.

Исправление должно отменять незавершённую работу

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

→ Intent detected
→ Parameters collected
→ Parameters validated
→ Customer confirmation
→ Action committed
→ Backend result verified

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

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

Как это тестировать

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

Каждый прогон оценивается по семи вопросам:

  1. Было ли уловлено исправление?
  2. Обновилось ли активное состояние?
  3. Было ли аннулировано старое значение?
  4. Получил ли инструмент правильные аргументы?
  5. Была ли попытка дублирующего или устаревшего действия?
  6. Было ли итоговое состояние бэкенда правильным?
  7. Совпало ли голосовое подтверждение с бэкендом?

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

Услышать — не значит применить

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

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