# Взаимодействие: расширение пространства наблюдений и пространства действий В главе 1 был выдвинут тезис: когда базовая модель зафиксирована, главным системно-инженерным рычагом повышения качества работы агента обычно оказывается переопределение или расширение его **пространства наблюдений** и **пространства действий**. Главы со второй по пятую всё это время выполняли обещанное: инженерия контекста решает, что попадает в наблюдение, память и базы знаний растягивают наблюдение за пределы одной сессии, инструменты определяют, что агент умеет делать, а генерация кода позволяет ему создавать новые действия самому. Но все эти расширения происходили при одной и той же предпосылке: **агент и мир говорят по очереди**. Пользователь договорил фразу, агент подумал, вызвал несколько инструментов и ответил; пока он думает, мир по умолчанию считается неподвижным. Предпосылка настолько естественна, что её почти никогда не выписывают как допущение. Именно это допущение и снимает настоящая глава. ## Две оси: модальность и момент Если развернуть пространство наблюдений и пространство действий, у каждого обнаружится по два направления расширения. - **Модальность** задаёт **форму** наблюдения и действия: читает ли агент только текст или ещё и слышит звук, видит экран, ощущает момент силы; выдаёт ли он только токены или ещё и говорит, кликает, приводит в движение суставы. - **Момент** задаёт **ритм** наблюдения и действия: агент сам идёт за наблюдением или мир проталкивает его; действие обязано завершиться внутри одного хода или может растянуться на несколько, быть прерванным на середине и вытесненным более срочным. Предыдущие главы расширяли **содержание** этих двух пространств; эта глава расширяет их **модальность** и **момент**: | | Расширение пространства наблюдений | Расширение пространства действий | |---|---|---| | **Содержание** (главы 2–5) | Инженерия контекста, память и базы знаний | Инструменты, генерация кода | | **Модальность** (эта глава) | Голос, экран, физические датчики | Речь, клики, движение суставов | | **Момент** (эта глава) | Мир проталкивает, непрерывные потоки | Через ходы, прерываемо, вытесняемо | Основной тезис главы сжимается в одну фразу: **пошаговость — это допущение, оставленное обучением, а не свойство среды.** Корпус обучения модели почти целиком построен по принципу очередности: за вопросом следует ответ, за вызовом инструмента — результат, один собеседник заканчивает, прежде чем начинает другой. Поэтому политика, которую усваивает модель, предполагает, что мир будет её ждать. Реальная среда не ждёт реакции модели: письмо приходит, пока она думает, пользователь перебивает на середине фразы, страница уже изменилась между двумя скриншотами, а чашка опрокидывается, пока манипулятор тянется к ней. | Масштаб | Сценарий | Изменение со стороны наблюдения | Изменение со стороны действия | |---|---|---|---| | Секунды — сутки | Асинхронность и событийность | Мир сам будит агента (письма, таймеры, обратные вызовы) | Действие растянуто на ходы: сначала запуск, потом завершение по событию | | 10 мс — 1 с | Голос | Слушать во время речи, не дожидаясь конца фразы | Думать во время речи, прерываемо, с правкой на середине | | Доли секунды — секунды | Computer Use | Экран меняется между кадрами | После действия надо заново подтвердить, соответствует ли реальность плану | | Миллисекунды | Робототехника | Датчики возвращают данные непрерывно | Действие разбивается на куски: планируется по чуть-чуть, вытесняемо | Все четыре раздела делят один набор примитивов — **пробуждение, безопасная точка, отмена, вытеснение и разделение быстрого и медленного**, — различаясь лишь параметрами и характером отказов. «Проверить сигнал отмены в безопасной точке» в событийной асинхронности и «при аномалии отбросить оставшиеся действия и наблюдать заново» в разбиении действий робота — это один и тот же механизм, реализованный дважды на масштабах, отличающихся на пять порядков. Увидеть этот изоморфизм важнее, чем запомнить технические детали любого отдельного сценария. **В порядке чтения есть один намеренный ход: голосу в этой главе отведено заметно больше места, чем двум последующим сценариям.** На эволюционной линии интерактивности реального времени голос прошёл дальше всех и лучше всего годится в качестве системы отсчёта: от проблемы «у последовательного конвейера слишком большая задержка», через сквозные модели, полный дуплекс и речь во время размышления, вплоть до относительно сложившегося сегодняшнего итога — весь путь «проблема → решение → итог» уже пройден. Поэтому мы разбираем его подробно, и последующие Computer Use и робототехнику можно читать в сопоставлении с этой линией: до какого её участка дошёл каждый и где застрял. ## Асинхронность и событийность: когда мир приходит сам Инструменты восприятия, исполнения и совместной работы из главы 4 агент вызывает сам. Но как ему реагировать на внешние события, способные прийти в любой момент? Для этого нужна событийно-управляемая асинхронная архитектура. На неё опираются и два оставшихся класса инструментов из главы 1—триггеры событий и средства общения с пользователем,—поэтому они также рассматриваются здесь. ### Зачем нужна асинхронность Сначала поясним необходимость асинхронности на аналогии. Синхронность (Synchronous) означает «одно дело нужно закончить, прежде чем начать следующее», асинхронность (Asynchronous) означает «несколько дел могут выполняться одновременно». Традиционная синхронная архитектура агента похожа на стойку, где умеют только принимать в очередь — обслуживается только один клиент за раз, и только после завершения можно вызвать следующего; настоящий же умный помощник больше похож на гибкого секретаря — на столе лежит несколько дел, ожидающих обработки (письма, звонки, посетители), и секретарь решает, что обработать первым, исходя из срочности, а на середине дела может приостановиться и переключиться, если появится что-то более срочное. В синхронном режиме агенту приходится либо ждать завершения фоновой задачи, прежде чем разговаривать с пользователем, либо ждать окончания диалога, прежде чем обрабатывать новое событие, — что не позволяет реализовать несколько ключевых возможностей, необходимых для реальных сценариев ассистента: - **Асинхронное выполнение — это норма** — многие задачи требуют длительного времени выполнения и не должны блокировать взаимодействие с пользователем. - **Динамическая оценка приоритета событий** — не все события одинаково важны, агенту нужно интеллектуально выбирать стратегию обработки: отменить текущую операцию (срочно), поставить в очередь (обычно) или обработать параллельно (независимый лёгкий запрос). - **Плавность прерывания и восстановления** — прерванный диалог или задача должны иметь возможность естественным образом возобновиться. Фундаментальное противоречие, возникающее при попытке реализовать асинхронную парадигму на текущих LLM, состоит в следующем: парадигма обучения LLM предполагает синхронность — после вызова инструмента следующим сообщением обязательно должен идти результат вызова этого инструмента; но реальное развёртывание требует асинхронности — пользователь может прервать в любой момент, несколько задач могут продвигаться параллельно, внешние события могут поступить ещё до того, как вернётся результат инструмента. Это противоречие «синхронное обучение / асинхронное развёртывание» пронизывает все инженерные компромиссы, обсуждаемые далее в этом разделе. Для этого нам нужна **событийно-управляемая асинхронная архитектура агента**. Технически это означает, что система больше не активно и повторно проверяет «есть ли новое сообщение» (это называется поллингом, что неэффективно), а автоматически запускает логику обработки при поступлении нового сообщения. Все входы, выходы, процессы размышления и внешние взаимодействия единообразно моделируются как поток событий — записи событий, расположенные последовательно на временной шкале. На рис. 6-1 показана общая архитектура событийно-управляемого асинхронного агента, демонстрирующая взаимосвязь между источниками событий, очередью событий и процессом обработки агента. ![Рис. 6-1 Архитектура событийно-управляемого асинхронного агента](images/fig6-1.svg) ### Реализация событийных механизмов в OpenClaw Open-source фреймворк OpenClaw (подробнее его архитектура рассматривается в главе 5) получает сообщения из множества каналов через плоскость управления Gateway и маршрутизирует их в среду выполнения агента. Он предоставляет три встроенных механизма автоматизации: - **Hooks (событийные хуки)**: реагируют на события жизненного цикла агента, такие как создание сессии, сброс и т.д., по аналогии с триггерами событий в GitHub Actions - **Cron (планировщик по расписанию)**: выполняет периодические задачи по cron-выражениям (широко используемый в Unix-системах синтаксис планирования задач, например, `0 9 * * 5` означает «каждую пятницу в 9 утра»), например, генерирует еженедельный отчёт каждую пятницу, сводит данные в начале каждого месяца - **Heartbeat (демон сердцебиения)**: пробуждает агента каждые N минут, проверяет наличие вопросов, требующих внимания, полагаясь на суждение агента, чтобы избежать усталости от оповещений Эти три механизма придают OpenClaw-агенту видимость «автономности» — даже когда пользователь не в сети, агент может по расписанию генерировать отчёты, проверять состояние системы, обрабатывать рутинные дела. Но при внимательном рассмотрении выявляется фундаментальное ограничение. Сначала нужно прояснить один момент: для встроенных каналов Gateway (таких как IM, веб-интерфейс) сообщения сами по себе доставляются в **push-режиме** — сообщение сразу маршрутизируется агенту при поступлении; среди трёх механизмов автоматизации только Cron и Heartbeat действительно заставляют агента «действовать самостоятельно» при отсутствии сообщений от пользователя, и оба они являются **времяуправляемыми** — Heartbeat проверяет с фиксированным интервалом, Cron срабатывает в заданное время, а Hooks лишь пассивно реагируют на внутренние события жизненного цикла фреймворка и не способны привнести новые изменения из внешнего мира. Настоящий недостаток заключается в следующем: для любого произвольного источника событий третьей стороны, помимо встроенных каналов, — новое письмо, обратный вызов внешнего API, срочное уведомление, требующее немедленной обработки, — у OpenClaw нет канала для мгновенного подключения, агент не может отреагировать в момент возникновения события, а может обнаружить его лишь при следующем цикле Cron/Heartbeat. Такая задержка во многих сценариях недопустима. Возьмём для примера **PineClaw** (плагин OpenClaw для Pine AI): Pine AI — это ИИ-помощник, который совершает реальные телефонные звонки от лица пользователя, типичные сценарии включают согласование счетов, отмену подписок и обработку страховых претензий. Когда пользователь через OpenClaw-агента запускает задачу телефонного звонка Pine, голосовой ИИ Pine совершает звонок от имени пользователя, но в процессе разговора в любой момент может понадобиться вмешательство пользователя: - **Проверка личности в реальном времени**: служба поддержки требует подтверждения личности владельца аккаунта, Pine нужно, чтобы пользователь немедленно предоставил код безопасности или одноразовый пароль (OTP) - **Подтверждение трёхстороннего звонка**: служба поддержки требует прямого разговора с владельцем аккаунта, Pine нужно, чтобы пользователь принял звонок в течение нескольких секунд - **Синхронизация прогресса и подтверждение решения**: переговоры достигли ключевого момента (например, собеседник предложил скидку), Pine нужно подтверждение пользователя о согласии Если полагаться на периодический опрос через Heartbeat — предположим, интервал сердцебиения составляет 5 минут — пользователь может долго не получать уведомление, пока служба поддержки ждёт код подтверждения, что приведёт к тому, что служба поддержки повесит трубку, и звонок сорвётся. А сокращение интервала опроса до секунд создаст множество бесполезных запросов и растрату ресурсов. Решение PineClaw заключается во введении **механизма Channel** — построении канала событий реального времени между Gateway OpenClaw и API Pine. Когда происходят ключевые события — звонок принят, требуется ввод от пользователя, звонок завершён — сообщение мгновенно отправляется OpenClaw-агенту, агент немедленно обрабатывает его и уведомляет пользователя, задержка отклика снижается с минут до секунд. Этот пример раскрывает основную ценность событийно-управляемой архитектуры для фреймворка агентов: **настоящее «проактивное обслуживание» требует не только, чтобы агент мог периодически проверять мир, но и чтобы мир мог активно уведомлять агента**. Единообразное моделирование всех входов — сообщений пользователя, результатов инструментов, внешних обратных вызовов, срабатываний по расписанию — как потока событий, управление мышлением и действиями агента через цикл событий — это архитектурная основа для достижения данной цели. В рамках этой архитектуры ниже сначала будут представлены два класса инструментов, непосредственно связанных с событиями, а также виртуальная личность и изолированная среда выполнения, поддерживающие независимые действия агента, а затем будет обсуждён конкретный дизайн механизма обработки событий. ### Инструмент срабатывания события Инструмент срабатывания события — это точка входа, через которую внешние события запускают действия агента. Без инструмента срабатывания события агент может только непрерывно циклически размышлять, вызывать инструменты, и наконец выдать результат, после чего ждать следующего ввода пользователя. Чтобы преобразовать изменения в мире в события, которые агент может обработать, существует три распространённых типа инструментов срабатывания события. **Таймер** (set_timer) обрабатывает события, зависящие от физического времени. Например, если было отправлено письмо, но собеседник не ответил, спустя некоторое время нужно отправить ещё одно письмо с вопросом о прогрессе; если был совершён звонок, но собеседника не было на рабочем месте, нужно попробовать позвонить снова в следующее рабочее время. Для этого такие инструменты, как OpenClaw и Claude Code, поддерживают инструмент таймера, пробуждающий себя в заданное физическое время. **Одноразовый таймер** используется для задач с чётко определённым моментом времени: например, пользователь просит «позвонить в DMV», сейчас суббота, и агент устанавливает «позвонить в DMV в понедельник в 10:00 утра», после срабатывания таймера звонок совершается автоматически. **Циклический таймер** используется для периодических задач: например, проверка состояния сервера раз в час, отправка отчёта о прогрессе каждую пятницу. Кроме того, некоторые внешние сервисы не поддерживают активную отправку данных о прогрессе, только активный запрос прогресса, и в этом случае нужно использовать циклический таймер для периодического повторного запроса — Heartbeat в OpenClaw, о котором говорилось в предыдущем разделе, как раз является систематизацией такого механизма и источником способности OpenClaw к «проактивному обслуживанию». **Мониторинг фоновой задачи** (monitor_shell) обрабатывает события от асинхронно выполняемых инструментов или задач командной строки. Некоторым задачам командной строки нужно долго выполняться в фоне, и агенту нужно отслеживать прогресс выполнения. Если заставить агента постоянно «смотреть» за командной строкой, то есть постоянно вызывать инструмент для проверки текущего прогресса, это приведёт к трате слишком большого количества токенов; если же дать задаче командной строки полностью завершиться, прежде чем агент начнёт размышлять и действовать, то агент не сможет своевременно обнаружить серьёзные проблемы в процессе выполнения и даже не сможет вмешаться в случае зависания командной строки, что приведёт к зависанию всей задачи. Решение Claude Code для этой проблемы — введение инструмента monitor (мониторинг), позволяющего агенту отслеживать новый вывод командной строки или вывод, содержащий определённые ключевые слова. **Канал внешних событий** (connect_channel) отправляет агенту в реальном времени внешние события, такие как поступление нового письма, обратный вызов API, сообщение IM. Механизм Channel в PineClaw из предыдущего раздела — типичная реализация этого. На уровне проектирования инструмент срабатывания события должен определять чёткие условия срабатывания и правила фильтрации, чтобы избежать пробуждения агента нерелевантными событиями и растраты вычислительных ресурсов; полезная нагрузка события (payload) должна содержать достаточно контекстной информации, чтобы уменьшить количество дополнительных запросов, которые агенту придётся сделать после пробуждения. ### Инструмент коммуникации с пользователем Сессии OpenClaw прозрачны для пользователя: пользователь и агент могут в любой момент обмениваться сообщениями через специальные инструменты с изображениями, файлами, push-уведомлениями, мультимодальным содержимым и Generative UI. Инструмент коммуникации с пользователем возник в условиях всё большего разнообразия каналов общения между агентом и пользователем. Многие агенты (такие как Claude Code, Manus, Genspark) используют нативный цикл ReAct, при котором всё, что «говорит» агент (то есть сообщения assistant), напрямую отправляется пользователю, а пользователь должен открыть указанную сессию в приложении, чтобы общаться с агентом. OpenClaw — один из самых влиятельных представителей универсальных агентов, ломающих эту парадигму человеко-машинного общения: его сессия прозрачна для пользователя — пользователю не нужно осознавать существование сессии, а также не нужно вникать в детали вызова инструментов агентом; пользователь и агент могут в любой момент отправить сообщение друг другу, а не так, что пользователь отправляет одно сообщение — агент отвечает одним. Поэтому многие оценивают OpenClaw как обладающий «живым ощущением», словно секретарь, общающийся с пользователем асинхронно через текстовые сообщения. При этом такие текстовые сообщения не являются просто прямым выводом сообщения assistant модели пользователю, а отправляются с помощью специального инструмента, эти сообщения могут также содержать вложения изображений и файлов, а также push-уведомления в зависимости от степени срочности. Помимо текстового общения с пользователем, всё больше агентов обладают способностью к мультимодальному общению, например, отправка структурированных карточных сообщений, отправка писем-напоминаний. Некоторые агенты уже начинают пробовать генеративный UI, то есть генерацию интерактивных интерфейсов с помощью HTML и подобных средств, чтобы более дружелюбным образом показывать информацию пользователю. На уровне проектирования инструмент коммуникации с пользователем должен поддерживать асинхронный режим сообщений (пользователь не обязательно в сети), предоставлять отслеживание статуса прочитано/непрочитано и сохранять согласованность сообщений в многоканальных сценариях. **Многоканальное общение с пользователем и возврат внимания.** Здесь нужно прояснить границу категорий, которую легко перепутать: одинаковая «отправка уведомления» относится к инструменту сотрудничества, если получатель — это администратор-утверждающий или сотрудничающий агент (например, запрос одобрения от администратора, отчёт о прогрессе сотрудничающему агенту); а если получатель — сам конечный пользователь, это относится к инструменту коммуникации с пользователем. Различие не в канале, а в том, «кого уведомляют и зачем». **Отклик агента не должен ограничиваться одним каналом, механизм уведомлений одновременно служит и механизмом возврата внимания пользователя**. Отправка сообщений расширяется на такие каналы, как мгновенные сообщения, SMS, электронная почта, телефонный звонок, push-уведомления и другие. Агент комплексно выбирает канал, исходя из степени срочности, статуса пользователя, характера содержания и предпочтений пользователя, гарантируя, что важные сообщения не будут пропущены, но избегая при этом повторяющегося беспокойства. Для длительно выполняющихся задач агенту нужно активно уведомить пользователя по завершении, вернув внимание пользователя. Для периодических задач (например, ежедневных сводок, еженедельных отчётов) уведомления помогают пользователю сформировать устойчивую привычку взаимодействия. Инструмент коммуникации с пользователем решает задачу «как достучаться до пользователя». Но в каком качестве агент появляется в этих каналах и в какой среде он выполняет действия от имени пользователя — для этого нужен ещё один слой инфраструктуры идентичности и среды, что и является темой следующего раздела. ### Виртуальная идентичность и изолированная среда исполнения Виртуальный компьютер работает круглосуточно, ограничивает доступ агента к локальным файлам, а ошибка затрагивает максимум виртуальную среду. Данные передаются через общую файловую систему и ссылки-пути. Прежде всего нужно пояснить назначение этого раздела: виртуальная идентичность и изолированная среда исполнения по сути представляют собой инфраструктуру среды исполнения, продолжающую логику песочницы, которую мы обсуждали в разделе про инструмент выполнения; она вынесена в раздел про асинхронную архитектуру потому, что именно агенту, работающему самостоятельно, постоянно активному и в любой момент готовому действовать от имени пользователя, это нужнее всего. В начале главы упоминалось, что Саманта из «Она» обладала собственной идентичностью и рабочей средой. Чтобы реализовать подобного универсального помощника, приходится сразу решать ключевой архитектурный вопрос: должен ли агент напрямую управлять личными аккаунтами пользователя или ему нужна собственная виртуальная идентичность? Прямое управление кажется удобным, но если агент допустит ошибку или будет взломан, вся цифровая идентичность пользователя окажется под угрозой. Более надёжное решение — наделить агента отдельным набором виртуальной идентичности, как у секретаря есть свой рабочий телефон и почта. Такая виртуальная идентичность включает выделенные аккаунты для связи, хранилище и вычислительную среду, позволяя агенту действовать от имени пользователя прозрачным образом. Чёткость идентичности не только не подрывает доверие, но и укрепляет достоверность коммуникации. Виртуальную идентичность нужно разместить в изолированной среде исполнения. **Виртуальный компьютер** (VM/контейнер) и **виртуальный телефон** (эмулятор Android) дают агенту изоляцию на уровне операционной системы и полноценные возможности управления рабочим столом/мобильным устройством: у агента там есть собственная учётная запись, домашний каталог и учётные данные для входа, все действия отслеживаемы и проверяемы; даже ошибочное действие не затронет хостовую систему и реальное устройство пользователя. Это распространение идеи песочницы из раздела про инструмент выполнения на измерение «цифровой идентичности» — если песочница изолирует выполнение кода, то виртуальный компьютер и виртуальный телефон изолируют всю цифровую идентичность целиком. Отдельная идентичность несёт с собой и две реальные проблемы. Первая — **механизмы противодействия автоматизации**: многие сайты блокируют автоматический доступ с помощью CAPTCHA и проверки репутации IP-адреса; виртуальные среды с IP дата-центров легко распознаются, поэтому на практике часто требуется настраивать резидентную прокси-сеть (с использованием реальных домашних IP), чтобы получить нормальный доступ. Вторая — **сценарии доступа к настоящим аккаунтам пользователя**: когда задачу нужно выполнить под учётной записью самого пользователя, следует использовать аутентификацию Human-in-the-Loop — через удалённый рабочий стол VNC/RDP пользователь лично выполняет вход в визуальной среде, видя весь интерфейс, с которым работает агент, и понимая, зачем нужна аутентификация; после этого токен сессии переиспользуется в течение срока действия, чтобы не отвлекать пользователя слишком часто, что даёт баланс между автономностью и безопасностью. Обмен данными между главным агентом и виртуальными средами происходит через **общую файловую систему**: с помощью монтирования тома (например, `/workspace/shared`) соединяются главный агент, виртуальный компьютер и виртуальный телефон, а данные передаются как ссылки на путь к файлу, а не как копии содержимого, чтобы не занимать окно контекста. Возьмём для примера задачу анализа данных: пользователь загружает CSV-файл в общую директорию, агент в виртуальном компьютере читает файл, выполняет анализ, генерирует график и сохраняет его обратно в общую директорию, а главному агенту достаточно вернуть пользователю только путь к файлу с графиком — между сторонами всегда передаётся лишь лёгкая строка с путём. Инструмент срабатывания события позволяет миру будить агента, инструмент коммуникации с пользователем позволяет агенту достигать пользователя, а виртуальная идентичность и изолированная среда исполнения позволяют агенту действовать самостоятельно и подотчётно. Остаётся вопрос: как поступать, когда на один и тот же экземпляр агента одновременно обрушивается несколько событий? ### Механизм обработки событий Один экземпляр агента может одновременно сталкиваться с несколькими событиями: новое сообщение пользователя, результат, возвращённый инструментом, срабатывание таймера, запрос на взаимодействие от другого агента. От того, насколько эффективно и корректно обрабатываются эти события, напрямую зависит производительность и пользовательский опыт. Каркасом этого механизма служит **цикл событий** (event loop) из области конкурентного программирования. Асинхронного агента можно рассматривать как долго работающий цикл: на каждой итерации он извлекает из входной очереди несколько событий, добавляет их в траекторию, делает один вызов LLM, выполняет решённые им вызовы инструментов и возвращается в начало цикла, чтобы дождаться следующей партии событий — это та же структура, что и у goroutine в Go, которая читает сообщения из channel и обрабатывает их итерация за итерацией в `for { select { ... } }`. У этой модели есть ключевое свойство: **события потребляются только на границах итераций цикла**. Пока LLM рассуждает, а инструмент выполняется, вновь поступившее событие не вклинивается ниоткуда и не ломает текущий шаг, а сначала ждёт в очереди, пока на этой итерации не будет достигнута **безопасная точка** (завершение отрезка рассуждения, возврат из вызова инструмента), — и лишь тогда обрабатывается вместе с остальными. Отмена подчиняется той же дисциплине: она не обрывает работу насильно в произвольный момент, а на безопасной точке проверяет, «не поступил ли запрос остановиться» — именно эту роль в Go играет `ctx.Done()` (в главе 10 та же концепция context используется для обсуждения каскадной отмены дочерних агентов родительским агентом). Если это понять, то различие между тремя описанными ниже стратегиями обработки сводится лишь к тому, как они относятся к безопасной точке: дать событию дождаться следующей естественной безопасной точки (через очередь), самому заблаговременно создать безопасную точку (через отмену) либо вообще запустить отдельный цикл, не дожидаясь безопасной точки основного цикла (параллельно). **Структурированное моделирование событий.** Предпосылка обработки — понимание. Универсальный агент сталкивается со входными данными не только от одного пользователя — сообщение, присланное третьей стороной, это не сообщение пользователя агенту, но агенту всё равно нужно его понять, оценить важность и решить, как вмешаться. Это требует моделировать каждый вход как **структурированное событие**, содержащее богатую семантику: - **Источник (кто)**: сам пользователь, контакт, незнакомец, системное уведомление - **Канал (каким образом)**: телефонный звонок, SMS, мгновенное сообщение, письмо, социальная сеть, срабатывание таймера, результат асинхронного вызова инструмента, обновление статуса из мониторинга командной строки - **Содержание (что)**: текст сообщения, эмоциональная окраска, срочность, требуется ли ответ - **Контекст (фон)**: является ли это ответом на предыдущий диалог или новым обращением, связь с текущей задачей Возьмём для примера письмо клиента с запросом на возврат средств; конкретная форма структурированного события выглядит так: ```json { "source": {"type": "email", "sender": "client@example.com"}, "channel": "gmail_webhook", "content": {"subject": "Запрос на возврат", "body": "Заказ #12345, хотел бы вернуть..."}, "context": {"priority": "high", "customer_tier": "vip", "related_orders": ["#12345"]} } ``` Только когда все эти измерения чётко смоделированы как структурированные события, агент способен сохранять ясное восприятие в многосторонней коммуникации, не путая ввод пользователя с результатом инструмента и не принимая результат инструмента со скрытыми инструкциями за команду пользователя, что приводит к инъекции промпта. Сложность управления многопоточным контекстом также требует, чтобы агент понимал связи между несколькими ветками диалога — как сообщение от третьей стороны влияет на настроение пользователя, как меняется роль пользователя в разных диалогах, когда нужно свести воедино информацию из разных веток, чтобы дать совет. По экосистеме триггеров таких платформ рабочих процессов, как n8n, видно: Webhook, таймер, почта, изменение в базе данных, отслеживание файлов — каждый триггер является одним из «органов чувств», которыми агент воспринимает мир. Когда все эти разнородные события единообразно моделируются в структурированном формате, агент способен последовательно обрабатывать стимулы из разных источников, и описанные ниже определение срочности и стратегии обработки строятся именно на этом едином моделировании. **Динамическая стратегия обработки на основе срочности.** Люди, справляясь с несколькими задачами одновременно, применяют разные стратегии в зависимости от степени срочности. Столкнувшись с внезапной срочной ситуацией, немедленно бросают текущую работу; столкнувшись с рутинным пунктом дел, добавляют его в список задач на потом. Обработка событий агентом должна отражать такую же интеллектуальность. ![Рис. 6-2 Три стратегии асинхронной обработки событий](images/fig6-2.svg) **Обработка на основе отмены (Cancellation-Based)** применяется для срочных событий, и её суть — **заблаговременно создать безопасную точку** для срочного события: принудительно прервать текущий шаг, превратив этот момент в границу, на которой можно потребить новое событие. Когда приходит срочное событие (например, пользователь нажимает «стоп» или система надзора присылает команду с высоким приоритетом): (1) текущая операция останавливается — если LLM в процессе рассуждения, поток немедленно отменяется; если выполняется синхронный инструмент, отправляется сигнал отмены; (2) очередь ожидающих событий очищается, все события из неё извлекаются; (3) события из очереди вместе со срочным событием добавляются в конец траектории; (4) LLM немедленно вызывается заново, получая на вход полную обновлённую траекторию для оценки ситуации. Например, когда пользователь вводит «Стоп! Я неправильно сказал» в момент, пока агент выполняет потенциально ошибочное действие, агент сразу же увидит этот новый ввод, заново поймёт истинное намерение и тем самым избежит выполнения ошибочного действия. **Обработка через очередь (Queued)** применяется для рутинных событий. Когда приходит несрочное событие (например, асинхронный инструмент вернул результат или пользователь прислал дополнительную информацию): (1) событие помещается в конец очереди, не прерывая текущую операцию; (2) система дожидается завершения текущей операции — даёт LLM закончить рассуждение, позволяет синхронному инструменту доработать; (3) когда завершается любой вызов инструмента и возвращает `tool.result`, проверяется очередь, и если она не пуста, все события сразу добавляются в траекторию; (4) LLM обрабатывает обновлённую траекторию целиком. Так реализуется пакетная обработка, повышающая эффективность — например, после того как агент вызывает инструмент поиска, пока ожидается результат, пользователь добавляет уточнение «смотри только результаты за последний месяц»; это уточнение попадает в очередь, и когда приходят результаты поиска, оба события представляются LLM вместе, избавляя от лишних обращений. **Параллельная обработка (Parallel)** применяется для независимых лёгких запросов. Например, пока агент анализирует большой объём данных, пользователь вдруг спрашивает: «Какая сегодня погода?» Такие запросы обладают тремя признаками: не связаны с основной задачей, требуют быстрого ответа, дёшевы в исполнении. Здесь не подходит ни обработка через отмену (прервёт важную основную задачу), ни обработка через очередь (заставит пользователя слишком долго ждать). Система сначала оценивает независимость и сложность запроса, затем выполняет его самостоятельно в параллельной сессии рассуждения, вызывая необходимые инструменты и немедленно возвращая ответ. Запрос и ответ добавляются в траекторию основной задачи с явной пометкой «выполнено параллельно с основной задачей», чтобы избежать путаницы у LLM. **Определение срочности.** Срочные события: прерывание пользователем (`user.interrupt`), команда надзора (`supervisor.instruction`), прерывание от другого агента (`agent.interrupt`), внешний триггер, помеченный как срочный (например, системное предупреждение, сбой платежа). Несрочные события: обычный ввод пользователя (`user.input`), ввод от агента (`agent.input`), результат инструмента (`tool.result`), срабатывание таймера (`timer.trigger`), обычный внешний триггер. У жёстко закодированных правил есть свои ограничения — то, как обрабатывать событие, определяется его семантикой: «немедленно остановись» требует отмены, «какая сегодня погода» — параллельной обработки, «отчёт нужно отправить мне на китайском» — обработки через очередь. **Рекомендуется использовать лёгкую классифицирующую LLM в роли маршрутизатора событий**, чтобы быстро определять подходящую стратегию по мере поступления событий. Далее на примере эксперимента с событийно-ориентированным агентом обработки писем разберём, как реализовать описанные выше стратегии обработки событий на практике. > **Эксперимент 6-1 ★★★: событийно-ориентированный агент обработки писем** > > > ![Рис. 6-3 Эксперимент 6-1. Архитектура событийно-ориентированного агента](images/fig6-3.svg) > > > В этом эксперименте строится простейший событийно-ориентированный агент: **автоматический помощник обработки почты**. Агент отслеживает почтовый ящик и при каждом получении нового письма автоматически запускает процесс обработки — классификацию, резюмирование, составление черновика ответа, а при необходимости — уведомление пользователя. Это самый наглядный вводный сценарий для событийно-ориентированного агента: одно внешнее событие (поступление нового письма) запускает один полный цикл размышления агента. > > **Цель эксперимента** — понять ключевую идею событийно-ориентированной работы: агент больше не просто пассивно ждёт ввода от пользователя, а способен реагировать на внешние события и действовать проактивно. Через этот эксперимент читатель освоит регистрацию источников событий, очередь событий и базовый замкнутый цикл «событие поступило → агент обработал → результат выведен». > > **Источники событий и очередь событий.** > > Система поддерживает единообразное подключение различных источников событий: > > - **Почтовые события** (`on_email_received`): срабатывают при регулярной проверке почтового ящика или при получении push-уведомления о новом письме > - **Сообщения IM/SMS** (`on_im_message`, `on_sms_message`): срабатывают на сообщения мгновенных мессенджеров > - **События GitHub** (`on_github_pr_update`, `on_github_issue_update`): замечания при ревью PR, изменения статуса > - **Срабатывание таймера** (`on_timer_expire`): периодические задачи (например, ежедневное резюме, генерация еженедельного отчёта) > - **Webhook** (`on_webhook_received`): универсальный обратный вызов от внешних систем > - **Системные события** (`on_user_inactive`, `on_process_timeout`, `on_resource_alert`): изменения внутреннего состояния > > Все события поступают в единую **очередь событий** и обрабатываются последовательно в порядке поступления. Каждое событие запускает отдельный цикл размышления агента: агент читает содержание события, вызывает нужные инструменты (например, запрос к базе знаний, чтение вложения, поиск в истории писем по теме), формирует результат обработки (метку категории, резюме, черновик ответа) и в конце с помощью инструмента уведомления информирует пользователя или напрямую выполняет действие. > > **Сценарий проверки**: настройте агента на отслеживание тестового почтового ящика. Смоделируйте получение трёх писем — приглашение на встречу, жалоба клиента, рекламная рассылка. Агент обрабатывает их по очереди: для приглашения на встречу автоматически проверяет конфликты в календаре и составляет черновик ответа с принятием/отклонением; для жалобы клиента извлекает ключевую информацию, помечает как высокоприоритетную и уведомляет пользователя о необходимости обработки; рекламную рассылку автоматически архивирует. Весь процесс проходит без участия пользователя. Эксперимент 6-1 продемонстрировал простейшую событийно-ориентированную модель — события поступают в очередь, агент обрабатывает их по очереди. Но когда агенту нужно реагировать на прерывания во время длительного выполнения инструмента или одновременно управлять несколькими параллельными задачами, простой очереди событий уже недостаточно. Далее рассмотрим более глубокие инженерные проблемы. ### Инженерная реализация: как заставить синхронную модель поддерживать асинхронное прерывание Эксперимент 6-1 обрабатывал только последовательные события — они поступали в очередь по порядку, и агент обрабатывал их одно за другим. Теперь вернёмся к противоречию «синхронное обучение / асинхронное развёртывание», обозначенному в начале раздела: как втиснуть в синхронный формат ситуацию, когда пользователь неожиданно прерывает работу, пока инструмент ещё не вернул результат? В этом разделе описано текущее промышленное инженерное решение. Сначала поясним это противоречие на конкретном примере. Допустим, агент помогает пользователю составить письмо (вызов инструмента: поиск контактной информации); пока поиск ещё не вернул результат, пользователь вдруг говорит: «Подожди, сначала посмотри погоду на завтра». В синхронном цикле ReAct агент обязан дождаться результата поиска, прежде чем сможет обработать следующее сообщение — потому что API требует, чтобы «сразу после вызова инструмента следующим сообщением обязательно шёл результат инструмента». Но в асинхронном реальном мире событие может прервать выполняемую задачу в любой момент. Как выразить семантику «асинхронного прерывания» в рамках ограничений «синхронного формата» — именно на этот вопрос и отвечает описанное ниже инженерное решение. **Инженерный компромисс: асинхронная реализация, симулирующая синхронность.** Ключевая идея: **в обычном режиме, когда прерываний не происходит, LLM видит стандартную синхронную траекторию, и только при прерывании вставляется заполнитель, чтобы восстановить формат**. Вот пять ключевых правил: **Правило 1**: как только LLM выдаёт ответ, сообщение assistant (включая thinking, content и вызов инструмента) сразу же записывается. **Правило 2**: результат инструмента (tool result) записывается только по завершении выполнения инструмента. Во время выполнения траектория находится в состоянии «частично завершена». **Правило 3**: прерывание во время выполнения инструмента требует заполнителя. Для незавершённого инструмента генерируется заполняющий ответ (например, «инструмент выполняется в фоновом режиме, приоритет — обработать новое событие»), затем добавляется событие прерывания, и LLM вызывается заново. С точки зрения LLM assistant message по-прежнему имеет парный tool result. **Правило 4**: прерывание во время размышления LLM приводит к прямому отбрасыванию текущего размышления. Оно не записывается в траекторию, новое событие сразу добавляется, и запускается новый цикл размышления. **Правило 5**: непрерывающие события поступают в очередь и ожидают пакетной обработки. Они добавляются все разом только после завершения текущего цикла. Возьмём для примера ситуацию, когда агент составляет письмо, а пользователь прерывает его вопросом о погоде — вот как работают эти пять правил: 1. Агент вызывает `search_contacts` для поиска контактной информации, сообщение assistant сразу записывается в траекторию (правило 1). 2. Пока результат поиска ещё не получен, пользователь присылает «сначала посмотри погоду на завтра». Поскольку это прерывание пользователем, система генерирует заполняющий tool result для незавершённого `search_contacts` («инструмент выполняется в фоновом режиме, приоритет — обработать новое событие», правило 3), затем добавляет запрос пользователя о погоде в траекторию и вызывает LLM заново. В этот момент формат траектории, который видит LLM, полностью корректен — assistant message и tool result идеально спарены. 3. После того как запрос о погоде выполнен и ответ отправлен пользователю, приходит исходный результат `search_contacts`, добавляясь в траекторию как новое событие (правило 2), и агент, прочитав контактную информацию, продолжает составлять письмо. Ключевое преимущество этого решения: **в обычном режиме LLM видит идеальную синхронную траекторию** — assistant message и tool result строго спарены, хронологический порядок ясен, никаких заполнителей или аномальных состояний. Это наиболее дружественно для LLM, обученной по действующей синхронной парадигме, и максимально сохраняет качество рассуждения. Только когда прерывание действительно необходимо, вводится заполнитель — как «необходимый компромисс». Однако сохраняется риск усиления галлюцинаций. В этом сценарии, хотя заполнитель явно указывает, что инструмент «ещё не завершён», система всё же может в последующем размышлении «выдумать» результат инструмента, ошибочно посчитав, что инструмент уже вернул действительные данные, и на основе этого вымышленного результата принять неверное решение. Это происходит потому, что в подавляющем большинстве траекторий, которые модель видела при обучении, сразу после вызова инструмента следовал реальный результат — она никогда не училась обрабатывать ситуацию «результат ещё не пришёл». Поэтому на практике прерывание следует применять только в действительно срочных случаях (явный запрос пользователя остановиться), а несрочные события помещать в очередь для пакетной обработки. **Асинхронный интерфейс инструментов, подходящий для существующих моделей.** Раз синхронное допущение модели трудно преодолеть, более фундаментальная стратегия — **встроить асинхронную семантику уже на уровне проектирования интерфейса инструмента**. Традиционное проектирование инструментов подразумевает семантику «вызов означает завершение». Например, название `phone_call` подразумевает, что «вызов совершит звонок и дождётся завершения разговора, вернув запись звонка». В асинхронной парадигме «запуск» и «завершение» следует разделить: - `initiate_phone_call`: запускает телефонный звонок, немедленно возвращая идентификатор задачи и начальный статус (например, «звонок инициирован, идёт набор номера») - о ходе звонка сообщается через события (`phone_call_connected`, `phone_call_ended`) Ключевое здесь — само название и описание инструмента должны передавать асинхронную семантику. Когда модель видит `initiate_phone_call`, её способность понимать язык естественным образом подсказывает, что это «инициирование», а не «завершение». Описание инструмента должно дополнительно это подчёркивать: «Этот инструмент запускает задачу телефонного звонка, обрабатываемую субагентом. После успешного инициирования задача сразу возвращает идентификатор задачи, и вы можете продолжать заниматься другими делами. По завершении звонка вы получите отдельное уведомляющее событие». **Проблема рассеивания внимания при пакетной обработке в очереди.** При пакетной обработке событий модель зачастую обращает внимание только на последнее событие. Причина в том, что **модель обучена реагировать на самый новый ввод, а пакетная обработка событий нарушает это допущение**. Вмешаться можно на двух уровнях: **Уровень промпта**: сообщить модели, что «при получении нескольких последовательных событий убедитесь, что учитываете всю информацию целиком». **Пометка в строке состояния агента**: перед каждым событием добавляется явная метка: ```text [Необработанное событие 1/4] Tool result from database_query: ... [Необработанное событие 2/4] Дополнение от User: смотри только данные по Пекину [Необработанное событие 3/4] Системное напоминание: до дедлайна отчёта осталось 30 минут [Необработанное событие 4/4] Вопрос от User: как продвигается работа? ``` В конце добавляется сводка: «Выше находятся 4 необработанных события, включая 1 результат инструмента, 2 сообщения пользователя, 1 системное напоминание. Убедитесь, что ваш ответ охватывает всю информацию». ### Глубинное противоречие и направления развития ![Рис. 6-4 Парадигма синхронного обучения и реальность асинхронного развёртывания](images/fig6-4.svg) В конечном счёте, заглушки, асинхронные интерфейсы инструментов и метки строки состояния, обсуждавшиеся в предыдущих разделах, — всё это способы залатать с помощью инженерии промптов одно и то же противоречие «синхронное обучение / асинхронное развёртывание» (рис. 6-4). Причины этого противоречия подробно разобраны в начале раздела, здесь мы их не повторяем и сосредоточимся только на его фундаментальном решении. **В ожидании эволюции модели: от синхронности к асинхронности.** Описанные выше инженерные приёмы по сути представляют собой **компенсацию недостатков обучения модели средствами инженерии промптов** — это временная мера переходного периода. Настоящее решение требует смены парадигмы на уровне обучения самой модели. В области робототехники модели VLA (Vision-Language-Action, «зрение-язык-действие», подробнее в главе 6) уже столкнулись со схожим вызовом: между восприятием и действием неизбежно возникает задержка. Успех VLA указывает направление эволюции для моделей-агентов. Следующему поколению моделей нужно приобрести три ключевые способности через обучение с подкреплением в асинхронной среде: 1. **Понимание асинхронного чередования событий в траектории**: это самый существенный пробел в текущих способностях. Современные модели ожидают строго синхронной последовательности, но в реальной асинхронной среде после вызова инструмента может следовать не результат его выполнения, а новое сообщение пользователя; размышление может быть прервано на середине, но промежуточное состояние должно сохраняться в траектории, а после обработки нового сообщения размышление должно продолжаться, а не начинаться заново. Модели нужно сохранять ясное понимание в такой «неупорядоченной» траектории — какие вызовы инструментов ещё ожидают результата, а какие фрагменты размышления не завершены. 2. **Восстановление прерванных задач и размышлений**: после того как модель отвлеклась на срочное событие, она должна по-прежнему помнить о незавершённой задаче. Например, если во время выполнения агентом инструмента анализа данных пользователь вдруг спрашивает о погоде, после ответа агент должен естественным образом продолжить ожидание результата анализа, а не забыть, что инструмент всё ещё работает. Особенно важно избегать галлюцинаций — ложного ощущения, что прерванный вызов инструмента уже завершён. 3. **Комплексная обработка пакета событий**: когда в траекторию пакетно добавляется несколько событий, нельзя обращать внимание только на последнее из них — нужно учитывать всю необработанную информацию в совокупности. Для реализации такого асинхронного обучения с подкреплением нужна новая инфраструктура: симулятор асинхронной среды (генерирующий сценарии задержанного возврата инструментов, случайных прерываний пользователем и т. п.) и специализированное вознаграждение за асинхронные способности (правильное понимание неупорядоченной траектории, успешное восстановление прерванного размышления, отсутствие галлюцинаций, комплексная обработка пакетных событий). Для непрерывного мышления не обязательно ждать следующего поколения моделей. Около двухсот строк оркестрации способны превратить **готовую** текстовую модель рассуждения в агента **непрерывного времени**, связав описанный инженерный компромисс с эволюцией модели. Это развитие правила 4: не отбрасывать прерванную мысль, а строить всё взаимодействие как непрерывный поток. Среда исполнения может принудительно закрыть текущий блок ``, вставить новое наблюдение—результат инструмента, прерывание пользователя или обновление распознавания—как обычное сообщение и продолжить декодирование. Механизм использует ресурс, который часто пропадает зря: модель способна выдавать сотни токенов в секунду, тогда как вызов инструмента или реплика пользователя занимают несколько секунд. Это ожидание можно потратить на размышление. Поэтому агент способен **думать в ожидании**—продолжать с частичной информацией и даже заранее запускать следующий инструмент—и **думать во время действия**—продолжать рассуждение при выводе и исправляться по ходу действия. > **Эксперимент 6-2 ★★★: асинхронный агент с параллельным выполнением и способностью к прерыванию** > > > ![Рис. 6-5 Эксперимент 6-2 Прерывание и восстановление асинхронного агента](images/fig6-5.svg) > > > На основе простой очереди событий из эксперимента 6-1 данный эксперимент погружается глубже в асинхронного агента: **параллельное выполнение инструментов, отмена выполнения и управление состоянием**. Агент теперь не просто обрабатывает события по очереди, а должен одновременно управлять несколькими параллельными задачами, обрабатывать прерывания и восстановление, а также принимать динамические решения на основе состояния в реальном времени. > > **1. Асинхронное выполнение инструментов**: поддержка асинхронного выполнения долгих инструментов (не менее 3–5 секунд), с немедленным возвратом заглушки при запуске. **Сценарий проверки**: агент выполняет длительную терминальную команду, во время которой пользователь спрашивает «который сейчас час?», агент отвечает немедленно, а после этого представляет результат анализа, когда тот возвращается. > > **2. Очередь событий и пакетная обработка**: накопление несрочных событий с пакетным добавлением в траекторию. **Сценарий проверки**: агент выполняет долгую задачу, пользователь подряд отправляет «не забудь ответить на японском» и «оформи в виде веб-страницы», по завершении задачи все события обрабатываются разом, и генерируется веб-страница на японском. > > **3. Механизм прерывания**: команда пользователя «стоп» немедленно прерывает поток выполнения и отменяет асинхронные инструменты. **Сценарий проверки**: агент выполняет долгую задачу, пользователь отправляет «отмена», агент немедленно останавливается, в траектории фиксируются событие прерывания и операция отмены. > > **4. Отмена и запрос состояния параллельных инструментов**: после завершения асинхронного инструмента реальный результат впрыскивается в диалог через новое событие, поддерживается отмена или запрос прогресса по идентификатору задачи. **Сценарий проверки**: пользователь просит «запусти для меня одновременно эти три скрипта, и когда какой-то из них завершится первым, посмотри прогресс остальных, и если он ещё не превысил 50%, отмени его». Три скрипта имитируют процесс анализа, во время выполнения непрерывно выводя прогресс со скоростью 3%, 2% и 1% в секунду соответственно. Агент одновременно запускает три асинхронных терминальных команды; когда скрипт со скоростью 3% в секунду завершается примерно через 33 секунды, агент запрашивает состояние двух оставшихся терминалов, обнаруживает, что один выполнен примерно на 66%, а другой — примерно на 33%, и отменяет тот, что не превысил 50%. После завершения обоих терминалов результаты объединяются в итоговый отчёт. > Асинхронное событийное исполнение позволяет миру разбудить агента в любой момент, но предполагает, что модель успеет закончить мысль до ответа. Следующие три раздела оспаривают это допущение: когда среда меняется не медленнее генерации модели, схема «сначала подумай, потом говори» сама становится недопустимой задержкой. ## Голос: самый естественный интерфейс человека и машины Голос — это не просто текст, превращённый в звук. Человек говорит примерно в четыре раза быстрее, чем печатает, и при этом освобождает руки и глаза. Поэтому голосовой Agent образует непрерывный цикл ввода и вывода, в котором пользователь может перебить его в любой момент. Диктовка превращает речь в текст, а голосовой Agent позволяет сотрудничать с ним напрямую; оба сценария поддерживают описанный ранее whisper coding. Здесь рассматриваются два направления: пользователь говорит с Agent, а Agent говорит с внешним миром от имени пользователя. Голосовая модель определяет, на что Agent способен ответить, а архитектура взаимодействия — насколько хорошо он слышит, быстро отвечает, передаёт очередь и выполняет подтверждения и вызовы инструментов во время разговора. ### Время взаимодействия: от каскада к полному дуплексу Введение OpenAI о GPT-Live описывает три парадигмы голосового взаимодействия: каскадную, поочерёдную и полнодуплексную[^ch6-12]. Это не линейная замена старого новым, а разные компромиссы между задержкой, стоимостью и наблюдаемостью: | Парадигма | Основная структура | Главное преимущество | Главное ограничение | | --- | --- | --- | --- | | Каскад | VAD → ASR → LLM → TTS | Ясные модули, которые легко заменять и отлаживать | Задержка накапливается, а просодические сигналы теряются на границах | | Сквозной Omni | Нативные аудиовход и аудиовыход, поочерёдное взаимодействие | Меньшая задержка, лучше сохраняются тон, эмоции и окружающий звук | Всё ещё требует очереди; обучение и отладка дороже | | Полный дуплекс | Нативные аудиовход и аудиовыход; непрерывно слушает, говорит и принимает решения | Перекрывающаяся речь, естественные перебивания и непрерывный поток | Сложнее обучать, контролировать и оценивать | Общая идея — уйти от предположения, что люди говорят строго по очереди, и от догадки VAD о том, кому принадлежит очередь. Каскад и Omni всё ещё делят разговор на ходы, а полный дуплекс превращает владение очередью в непрерывное решение модели. [^ch6-12]: OpenAI. *Introducing GPT-Live.* 2026-07-08. https://openai.com/index/introducing-gpt-live/ Классификация «каскад / по очереди / полный дуплекс» взята из описания трёх поколений ChatGPT Voice; термин «сквозной мультимодальный (Omni)» соответствует категории «turn-based voice models». ### Парадигма 1 · Каскадный конвейер Большинство коммерческих голосовых помощников по-прежнему используют последовательный конвейер (рис. 6-6): VAD определяет конец реплики, ASR переводит аудио в текст, LLM понимает запрос и генерирует ответ, а TTS озвучивает его. Модульность упрощает независимую оптимизацию, но каждая граница добавляет ожидание. ![Рис. 6-6: Последовательный конвейер голосового Agent](images/fig6-6.svg) | Модуль | Роль | Типичное узкое место | | --- | --- | --- | | VAD | Определить окончание речи | Порог тишины задерживает ответ и ошибочно делит реплики | | ASR | Преобразовать аудио в текст | Задержка распознавания и потеря контекста | | LLM | Понять, рассуждать и сгенерировать ответ | Время до первого токена; reasoning добавляет ожидание | | TTS | Преобразовать текст в речь | Синтез первого пакета и буфер воспроизведения | Для короткого ответа без reasoning ожидание VAD, ASR, LLM и TTS складывается последовательно (рис. 6-7); конкретные значения зависят от длины ввода, модели, оборудования, сети и нагрузки. В производстве очередь дополнительно увеличивает простой (рис. 6-8). ![Рис. 6-7: Каскад задержек последовательного ответа](images/fig6-7.svg) ![Рис. 6-8: Кривая задержки очереди](images/fig6-8.svg) > **Эксперимент 6-3 ★: построение традиционного голосового Agent** > > Соедините через WebSocket микрофон, Silero VAD, локальный Whisper, потоковую LLM и Fish S1 TTS, создав каскадную базовую линию. #### От последовательности к потоковому восприятию Рис. 6-7 описывает полностью последовательный случай VAD + ASR + LLM + TTS. У такой последовательной схемы восприятия три проблемы: 1. **Накопление задержки**: чтобы убедиться, что пользователь договорил, приходится дожидаться паузы тишины. 2. **Потеря информации**: двоичный сигнал «есть звук / нет звука» не способен передать колебания, эмоции, короткие реплики и окружающий звук. 3. **Разрыв контекста**: адреса электронной почты, имена людей и прочие имена собственные могут быть разорваны между сегментами и распознаны с ошибками. Чтобы решить эту проблему, сохранив модульное разделение труда, применяют **потоковое восприятие**: каждый этап как можно раньше выдаёт промежуточный результат. - **ASR расшифровывает по ходу речи**: как только VAD обнаруживает, что пользователь начал говорить, ASR-модель вызывается через определённые промежутки времени и потоково выдаёт предварительную расшифровку; после того как VAD зафиксировал конец реплики, текст подтверждается окончательно. - **Спекулятивное исполнение LLM**: предварительная расшифровка сразу отправляется в LLM; если окончательный текст совпал с ней, LLM повторно не вызывается, иначе предшествующее спекулятивное размышление отменяется и LLM вызывается заново. - **Посегментный вывод LLM**: первый пригодный для произнесения фрагмент сразу передаётся в TTS, не дожидаясь полного ответа. - **Инкрементальный синтез TTS**: аудиоблоки возвращаются непрерывно, поэтому дальнейшие генерация, синтез и воспроизведение перекрываются. Настоящему потоковому ASR нужна поддержка со стороны самой модели. Декодер Whisper авторегрессионный, но его энкодер ожидает полный аудиосегмент, поэтому его нельзя просто считать потоковой моделью. Потоковая аудиомодель на базе LLM может выдавать текст и семантические события из непрерывного звука, объединяя распознавание и часть понимания в одной модели. Она сохраняет контекст от начала разговора до текущего момента и может использовать мировые знания для обработки названий брендов, имён людей и других имён собственных. Кроме слов поток может выдавать маркеры \`speak_start/end\` и \`interrupt\` (границы речи и намерение перебить), \`emotion\` (эмоция и колебание), а также \`laugh\`, \`sigh\` и \`noise\` (паралингвистические и внешние звуки). Так голосовой Agent не сжимает каждое акустическое событие до обычного текста. Если нужно лишь определить, закончил ли пользователь говорить, решение о конце реплики можно встроить непосредственно в потоковый распознаватель. Обучающие метки должны использовать только сведения, доступные в момент решения; иначе информация из будущего создаст вывод, который невозможно воспроизвести онлайн. > **Эксперимент 6-4 ★: моделирование потокового речевого восприятия с помощью Qwen2-Audio** > > Qwen2-Audio сам по себе не является потоковой моделью. Эксперимент имитирует непрерывное восприятие нарастающими аудиопрефиксами и сравнивает его с 600 мс VAD + Whisper. ### Парадигма 2 · Сквозные мультимодальные модели (Omni) Даже с потоковым восприятием каскад передаёт слушание, мышление и речь через дискретные интерфейсы; при превращении аудио в текст теряются эмоция, интонация и окружающий звук. Omni делает всё одной моделью, что уменьшает задержку и сохраняет нетекстовые сигналы, но повышает стоимость обучения, отладки и замены компонентов (рис. 6-9). Самокаскад может исправить ошибку распознавания, когда для задачи достаточно текста; если же ответ зависит от скорости речи, эмоции или среды, текстовый узкий канал необратимо уничтожает доказательство. Omni всё ещё предполагает очередность и использует VAD или семантическое определение конца реплики. Пауза в последовательности чисел может быть принята за конец; потоковое восприятие улучшает решение, но не отменяет ходов разговора. ![Рис. 6-9: Сравнение сквозных мультимодальных речевых моделей](images/fig6-9.svg) > **Эксперимент 6-5 ★★: локальный запуск MiniCPM-o 4.5 — сквозной путь против самокаскада** > > Запустите MiniCPM-o 4.5 локально с отключённым thinking mode и сравните прямой ответ по аудио с самокаскадом, который сначала транскрибирует, а затем отвечает той же моделью. Здесь измеряется сохранение аудиоинформации, **а не** описанное далее «мышление во время речи». ### Парадигма 3 · Интерактивные полнодуплексные модели Omni разделяет «говорит пользователь» и «говорит модель», но синхронный перевод требует перекрытия. Полнодуплексная модель слушает и говорит непрерывно, каждый раз решая, продолжать ли, замолчать, перебить или вызвать инструмент. Moshi от Kyutai был ранним исследовательским примером. Thinking Machines Lab называет такой подход **Interaction Model**[^ch6-14]: взаимодействие зашито в модель, а не собрано вокруг VAD. GPT-Live доводит его до производственного масштаба и делегирует сложную работу фоновой модели, пока передний план поддерживает разговор. [^ch6-14]: Thinking Machines Lab, “Interaction Models: A Scalable Approach to Human-AI Collaboration”, 2026-05. https://thinkingmachines.ai/blog/interaction-models/ ### Когнитивное время: взаимодействие в реальном времени и глубокое мышление Качество взаимодействия и потолок интеллекта — разные измерения. Передний план должен ответить, пока пользователь ещё вовлечён, а фоновая модель может думать дольше. Следующие три решения — компромиссы, а не последовательные ступени. Первые два можно применить поверх каскада или Omni; третье объединяет глубокое мышление и выражение в реальном времени внутри одной модели. #### Решение 1: быстрое мышление для заполнителя, медленное — для ответа Быстрое мышление способно за несколько сотен миллисекунд выдать «заполняющую» реплику, а медленное тем временем доводит в фоне более глубокий вывод. Проблема в том, что простые вопросы обрабатываются дважды, а на сложных возникает противоречие: быстрая модель советует купить, медленная затем обнаруживает, что в тарифе нет ключевой функции, и пользователь за считаные секунды слышит два взаимоисключающих ответа. Коренная причина в том, что каждый экземпляр провёл собственное независимое рассуждение. ![Рис. 6-10: Архитектура быстрого/медленного мышления и сравнение решений](images/fig6-10.svg) #### Решение 2: быстрое мышление для взаимодействия, медленное — для подсказки Во втором решении фоновая модель передаёт подсказки модели переднего плана через строку состояния или отдельный интерфейс, а передний план продолжает вести разговор и решает, как сформулировать ответ. Это устойчивее первого решения, но связь остаётся косвенной: передний план может неверно понять подсказку и не видит промежуточных рассуждений фона; пока фон не закончил, на уточняющий вопрос пользователя передний план отвечает только собственными силами. Он умеет естественно «дождаться результата», но по-настоящему думать во время речи не может. #### Решение 3: сквозное объединение мышления и выражения Третье решение встраивает способность рассуждать прямо в сквозную аудиомодель. Step-Audio R1 решает две задачи двумя взаимодополняющими механизмами: **дистилляция мышления с привязкой к модальности (MGRD)** заставляет модель рассуждать на основе акустических признаков, а **двухмозговая архитектура MPS** распараллеливает замысел и его выражение. Первое обеспечивает «думать правильно», второе решает задачу «говорить вовремя». В идеале модель должна определять эмоцию по высоте тона, ритму и интонации, а не только по расшифрованному тексту. MGRD отбирает те цепочки рассуждений, которые действительно опираются на акустические признаки, обучает на этих данных модель и с помощью обучения с подкреплением не даёт модели пропустить рассуждение и сразу угадать ответ. В MPS мозг замысла непрерывно порождает фрагменты рассуждения, а мозг выражения, получив фрагмент, тут же синтезирует речь, соединяя его с уже произнесённым. Оба работают параллельно, конвейером, поэтому не нужно ждать окончания всего рассуждения, чтобы пользователь услышал первую фразу. #### Компромисс между разделением быстрого/медленного мышления и сквозным рассуждением Единая модель наиболее непосредственно реализует «думать во время речи», но ценой того, что мышление и речь в реальном времени приходится переобучать вместе; в развязанном варианте фоновый «мозг» проще заменить. Это компромисс, а не простая замена одного другим. На фоне стремительного развития передовых моделей рассуждения разделение быстрого и медленного мышления даёт важное инженерное преимущество: система может напрямую использовать прогресс каждого нового поколения медленных моделей. Быстрая модель переднего плана отвечает только за прослушивание, отклик и поддержание разговора с низкой задержкой, а медленная фоновая модель — за рассуждение, планирование и вызовы инструментов. Когда появляется более сильная модель рассуждения, достаточно заменить фоновую модель, не переобучая всю голосовую систему реального времени. Единый подход связывает рассуждение и взаимодействие одним циклом обучения, поэтому при каждом обновлении приходится заново балансировать интеллект, задержку ответа и естественность выражения. Таким образом, разделение быстрого и медленного мышления — не просто уступка задержке, а модульный выбор, позволяющий способности к взаимодействию и потолку интеллекта развиваться независимо. Такое разделение не обязательно ухудшает выполнение задач. По состоянию на август 2026 года голосовой Agent Pine AI с раздельной архитектурой быстрого и медленного мышления занимал первое место в τ³-Voice Leaderboard, опережая Grok Voice, GPT-Realtime-2 и другие системы. Этот результат как минимум показывает, что на задачах, одновременно проверяющих глубокое рассуждение и разговор в реальном времени, развязанная архитектура не уступает сквозным моделям по своей природе.[^ch6-17] [^ch6-17]: Pine AI. “The Most Natural Human-Computer Interface Is Your Voice.” 2026-06-23 (обновлено 2026-08-06). https://www.19pine.ai/blog/pine-ai-the-most-natural-human-computer-interface-is-your-voice Следует уточнить, что выражение «сквозная модель» часто используют в двух значениях. Первое — **сквозной речевой тракт**, описанный в предыдущем разделе: модель непосредственно принимает и генерирует аудио, а не соединяет несколько моделей через дискретный текст. В этом смысле и Omni, и Interaction Model являются сквозными, но Omni обычно работает по очереди, тогда как Interaction Model способен слушать и говорить одновременно; их архитектуры существенно различаются. Второе — **сквозная когнитивная архитектура**, о которой идёт речь в этом разделе: взаимодействие в реальном времени и глубокое мышление либо разделяют состояние и совместно обучаются в одной модели, либо распределяются между быстрой моделью переднего плана и медленной фоновой моделью. Эти две оси независимы. Система может иметь сквозной речевой тракт и при этом сохранять разделение быстрого/медленного мышления в когнитивной архитектуре; делегирование Thinking Machines Lab сложных задач фоновой модели рассуждения — один из примеров такого сочетания. ### Синтез речи, более похожей на человеческую Традиционный TTS может выдать машинную природу слишком гладкой речью и слишком редкими паузами. Паузы, слова-заполнители и редкие повторы в человеческой речи сигнализируют о неуверенности и процессе мышления. Основная LLM может выдавать вместе с текстом управляющие маркеры, такие как **THINKING**, **EMO:happy** и **SPEED:0.8x**; TTS отображает их в паузы, просодию, темп речи, смех, вздохи и другие невербальные аудиосигналы. Реализация может быть основана на TTS, обученном понимать управляющие маркеры, либо на клонировании голоса с референсными клипами для разных эмоций и стилей. > **Эксперимент 6-6 ★★: TTS, управляемый control tokens, с Fish Audio** > > Используйте Fish Audio S1, чтобы построить библиотеку голоса с несколькими референсами, и сравните три конфигурации: без управляющих маркеров, с одним референсным клипом и с несколькими референсными клипами. Исполнительный слой выбирает соответствующие эмоцию, темп речи и стиль по маркерам. ## Computer Use: агент автоматизации GUI Читая до этого момента, вы, возможно, заметили, что в этой главе речи посвящено заметно больше места, чем двум оставшимся сценариям, — и это сделано намеренно. На этой линии эволюции реального времени в мультимодальности речь прошла путь наиболее полно и заслуживает того, чтобы служить системой отсчёта: отталкиваясь от проблемы «слишком высокой задержки последовательного конвейера», через сквозные модели, полный дуплекс, «говорю, пока думаю» и целый ряд других решений, речь дошла до относительно сформировавшегося сегодняшнего итога — весь путь от проблемы через решение к итогу здесь полностью пройден. Поэтому мы разобрали её подробно, а два следующих сценария — Computer Use и роботы — можно рассматривать, сверяясь с этой линией эволюции речи: на какой стадии этого пути находится каждый из них, и на чём он застрял. Эти три сценария кажутся разными, но сталкиваются с одними и теми же базовыми вызовами: восприятие в реальном времени, принятие решений с низкой задержкой, непрерывное взаимодействие. Далее посмотрим, как эти технические темы воспроизводятся в визуальном взаимодействии (Computer Use) и физическом взаимодействии (роботы) — сначала расширим взгляд от слуховой модальности к визуальной: что если агент способен не только понимать речь, но и «видеть» экран и управлять графическим интерфейсом? Computer Use (также называемый агентом автоматизации GUI) позволяет ИИ пользоваться программами так же, как человек, — наблюдая за экраном и управляя мышью и клавиатурой: например, открыть браузер и найти информацию, заполнить данные в таблице или изменить настройки в системных параметрах. В основе лежит цикл **восприятие — мышление — действие** (Рис. 6-11): 1. Агент делает скриншот текущего экрана 2. Мультимодальная модель получает скриншот и указание задачи, выводит рассуждение и конкретное действие 3. Слой исполнения выполняет это действие в реальной среде (двигает мышь, кликает, вводит текст и т. д.) 4. После ожидания реакции интерфейса снова делается скриншот, и цикл переходит к следующему шагу Здесь важно различать **понимание интерфейса** и **выполнение задачи**. Первое ближе к мультимодальному пониманию и измеряется ответами на вопросы по одному скриншоту; второе требует замкнуть понимание и генерацию действий в цикл, способный обрабатывать загрузку страниц, изменения состояния, ошибки и необратимые последствия. Поэтому трудность Computer Use состоит не только в правильном ответе по скриншоту, но и в повторной проверке после каждого шага, что реальность всё ещё соответствует плану. ![Рис. 6-11 Цикл восприятие-мышление-действие Computer Use-агента](images/fig6-11.svg) В этом цикле есть три ключевых измерения проектирования: **пространство действий** (какие операции доступны агенту), **визуальное позиционирование** (как найти целевой элемент на скриншоте) и **архитектура модели** (как сгенерировать правильное действие на основе скриншота). ### Проектирование пространства действий Эталонная реализация Anthropic делит полную способность к взаимодействию на три категории инструментов (Рис. 6-12). Это ясный дизайн пространства действий, но не закрытый протокол, которому обязаны следовать поставщики моделей: если Harness преобразует те же скриншоты, ограничения действий и результаты исполнения в поддерживаемые целевой моделью сообщения и структурированные выходы, один и тот же цикл «восприятие — мышление — действие» смогут вести Claude, модели зрения с открытыми весами и самостоятельно размещённые конечные точки. ![Рис. 6-12 Пространство действий Computer Use](images/fig6-12.svg) **Инструмент GUI-операций** (computer tool): операции мыши включают перемещение (mouse_move), клик левой/правой/средней кнопкой, двойной/тройной клик, перетаскивание (left_click_drag), а также более точные нажатие/отпускание (left_mouse_down/up). Прокрутка (scroll) поддерживает четыре направления и может комбинироваться с клавишами-модификаторами. Клавиатурные операции включают посимвольный ввод (type, интервал между символами 12 мс имитирует реальную печать), сочетания клавиш (key, например Ctrl+C), удержание клавиши (hold_key). Действия восприятия: скриншот (screenshot), получение позиции курсора (cursor_position), ожидание (wait). **Инструмент выполнения команд** (bash tool): предоставляет постоянную сессию bash-терминала с тайм-аутом 120 секунд, определяет завершение выполнения команды по строке-«часовому», сохраняет состояние среды между несколькими вызовами (например, если перейти в директорию через cd, следующий вызов будет уже в ней). **Инструмент редактирования файлов** (str_replace_editor): реализует безопасное редактирование через сопоставление строк, поддерживает просмотр, создание, замену, вставку и отмену операций — это точнее, чем прямая перезапись всего файла, и снижает риск случайного изменения остального содержимого. > **Эксперимент 6-7 ★: запуск Computer Use (эталонный путь Anthropic или путь открытой модели)** > > Путь A использует Anthropic Computer Use Demo. Его контейнер включает полноценную среду рабочего стола Ubuntu, в том числе браузер, терминал и другие распространённые инструменты. Фронтенд получает задачу, а бэкенд отправляет инструкции и скриншоты в Claude, а затем выполняет действия мыши, клавиатуры, терминала или редактирования, возвращённые моделью. > > Путь B использует пример кода из [`chapter6/computer-use-open-model`](../chapter6/computer-use-open-model/). По умолчанию он управляет browser-use через открытую по весам модель Qwen3-VL 32B Instruct через размещённый API OpenRouter или через self-hosted vLLM/SGLang и аналогичные системы. ### Визуальная локализация (Grounding) В каждом раунде цикла модели нужно точно определить положение целевого элемента на скриншоте — «где находится строка поиска?», «каковы координаты кнопки отправки?». Это и есть задача визуальной локализации (Grounding). Сейчас существует **два основных подхода**: первый — превратить локализацию в **вопрос с вариантами ответа**: сначала все элементы интерфейса помечаются номерами, и модели остаётся лишь выбрать один из них; второй — **прямое предсказание координат**: модель, как человек, буквально «смотрит» на скриншот и называет координаты. Причём подход с вариантами ответа реализуется двумя способами: **чисто визуальная разметка** (исходный Set-of-Mark, где сегментационная модель нарезает кандидатные области по пикселям) и **структурированное индексирование элементов** (DOM/Accessibility Tree, когда структура считывается напрямую из самого интерфейса). Общее преимущество подходов с вариантами ответа в том, что открытая задача «найти на скриншоте кнопку и предсказать её координаты» превращается в закрытую задачу «выбрать один элемент из уже размеченных». Точно так же, как на экзамене вопрос с вариантами ответа проще, чем вопрос с открытым ответом: модели достаточно сказать «нажать [123]», а не «нажать на кнопку на экране в точке (350, 464)». Прямое предсказание координат для модели особенно трудно — чтобы делать это точно, требуется большой объём обучения, а на разных разрешениях экрана оно легко даёт сбой. **Set-of-Mark: метод визуальной разметки.** Исходный Set-of-Mark (SoM) был предложен исследовательским подразделением Microsoft в 2023 году, изначально — чтобы раскрыть возможности визуальной локализации GPT-4V. Это **чисто визуальный** метод: сегментационная модель (SAM, SEEM и т. п.) автоматически нарезает на скриншоте кандидатные области, для каждой из них накладывается номерная метка, и модель видит изображение с номерами — ей достаточно назвать номер, а система пересчитает его в координаты центра соответствующей области. Весь процесс не требует DOM и вообще какой-либо внутренней структуры интерфейса, поэтому подход применим и к нативному настольному ПО, и к игровым интерфейсам — лишь бы сегментационная модель могла нарезать кандидатные области. **Структурированное индексирование элементов: структурная реализация идеи SoM для веба.** Когда сам интерфейс может предоставить структурированную информацию, разметку можно сделать точнее. Современные веб-страницы ещё до рендеринга уже определяют полную структуру элементов (дерево DOM) и семантические роли (что является кнопкой, что — полем ввода), а интерфейс специальных возможностей (Accessibility Tree) даёт аналогичную информацию для многих настольных приложений. Именно так поступают веб-агенты на базе проекта browser-use: интерактивные элементы перечисляются из DOM и нумеруются — это можно рассматривать как структурную реализацию идеи SoM для веба (Рис. 6-13). Процесс состоит из четырёх шагов: 1. Через отладочный интерфейс браузера (CDP, Chrome DevTools Protocol) получить структурированное представление страницы (дерево DOM) и информацию о доступности 2. Автоматически определить, какие элементы интерактивны (кнопки, поля ввода, ссылки и т. д.) 3. Присвоить каждому интерактивному элементу уникальный ID и нарисовать вокруг него рамку на скриншоте 4. Одновременно сформировать текстовый список, описывающий, какой элемент соответствует каждому ID ```text Скриншот: [на изображении ключевые элементы помечены ID [1], [2], [3], [4] и т. д.] Элементы: [1] [2]