Alexander Bond • 01.11.2026 • 15 мин чтения generative uia2uiai агенты

Архитектура гибридных агентных интерфейсов (Agentic Generative UI / A2UI): потоковый рендеринг виджетов, интерактивные формы и детерминированный сбор данных без перезагрузки страниц

Инженерное руководство по построению Generative UI / A2UI архитектуры: протоколы Streaming JSON Patches, строгая схема-валидация Zod/Pydantic, изоляция Shadow DOM и динамический сбор данных без перезагрузки страниц

Инженерное руководство по построению Generative UI / A2UI архитектуры: протоколы Streaming JSON Patches, строгая схема-валидация Zod/Pydantic, изоляция Shadow DOM и динамический сбор данных без перезагрузки страниц

1. Кризис текстовых интерфейсов (Chat-only UI) в B2B: почему стена текста убивает конверсию

Платформа First Touch — это ИИ-рассылка в Telegram: бот пишет по вашей базе с ваших аккаунтов, отвечает на вопросы и передаёт менеджеру заинтересованных клиентов. Именно на этом контуре мы поймали самый жёсткий сигнал: чем сложнее B2B-сделка, тем быстрее деградирует отдача от текстового чата. Агент выдаёт безупречно структурированную простыню Markdown на 900 слов — и пользователь закрывает диалог на третьем абзаце. Проблема не в качестве генерации. Проблема в том, что мы заставляем человека выполнять работу парсера: прочитать, вычленить параметры, переформулировать их обратно в текст и надеяться, что модель поймёт без потерь.

Фундаментальные ограничения chat-only архитектуры:

  • **Когнитивная перегрузка.** Markdown-простыня не имеет аффордансов: нет границ ввода, нет валидации на месте, нет визуального различия между вопросом и утверждением. Пользователь не понимает, где заканчивается его зона ответственности.
  • **Ошибки структурированного ввода.** Реквизиты, диапазоны цен, временные слоты, конфигурации серверов (CPU/RAM/диск/регион) в свободной форме вводятся с ошибками в 20–40% случаев. Каждая ошибка — это лишний round-trip и рост стоимости токенов.
  • **Невозможность контекстного редактирования.** Чтобы поменять один параметр (например, `seats: 50 → 120`), классический чат перегенерирует весь ответ целиком. Состояние формы живёт в тексте, а не в структуре, поэтому любая правка = полная регенерация + потеря позиции скролла.
  • **Отсутствие детерминизма.** Один и тот же ответ модели не гарантирует одинаковый набор полей на выходе — CRM получает то 6 атрибутов лида, то 4.
  • Переход к A2UI (Agent-to-User-Interface) меняет роль модели: агент перестаёт быть генератором текста и становится оркестратором интерактивных компонентов. Он не описывает калькулятор словами — он инстанцирует виджет PricingMatrix с типизированными пропсами. Он не спрашивает «когда вам удобно» текстом — он монтирует InteractiveDatePicker с ограничениями по таймзоне и занятости слотов. Внутри First Touch внедрение генеративных UI-виджетов в процесс B2B-лидогенерации дало измеримый результат: конверсия в завершённую анкету выросла в 3.37 раза.

    2. Архитектура протокола A2UI и потоковый рендеринг компонентных деревьев

    Жизненный цикл генеративного виджета. (1) Интент пользователя → (2) LLM выбирает компонент из реестра и формирует Structured Output / Tool Call → (3) серверный schema-gate валидирует пропсы → (4) engine режет пропсы на инкрементальные патчи → (5) клиент монтирует Skeleton UI на первом чанке и гидрирует по мере поступления дельт → (6) клиентские события уходят обратно на сервер и реконсилируются с диалоговым контекстом.

    Спецификация Streaming JSON Patches. Мы адаптировали RFC 6902 под потоковый режим: вместо «применить весь документ» клиент получает монотонный поток операций с обязательным полем seq (порядковый номер) и final (флаг завершения). Ключевые операции:

    {"seq":1,"op":"add","path":"/meta","value":{"widget":"TierSelector","schema_version":"1.0","status":"skeleton"}}
    {"seq":2,"op":"add","path":"/props/tiers","value":[{"id":"start","price":29000}]}
    {"seq":3,"op":"append","path":"/props/tiers","value":{"id":"scale","price":79000}}
    {"seq":4,"op":"replace","path":"/meta/status","value":"ready","final":true}

    Первый чанк — всегда envelope: widget, component_id, schema_version. Этого достаточно, чтобы отрисовать каркас (skeleton, спиннеры, нейтральные плейсхолдеры) за ~40–80 мс и не блокировать UI до окончания генерации. Остальные чанки несут только пропсы. Restrictions: path ограничен корнями /props, /meta, /children — запрет на произвольные пути исключает подмену корневых узлов дерева и атаку на структуру приложения.

    Транспорт. Server-Sent Events выигрывает на нисходящем канале: HTTP/2 мультиплексирует десятки SSE-стримов в одном TCP-соединении, накладные расходы на событие — 5–12 байт заголовков, reconnect и Last-Event-ID поддержаны браузером из коробки, инфраструктура (nginx, Cloudflare) не требует настройки. WebSockets дают full-duplex, но требуют sticky sessions при горизонтальном масштабировании, собственной логики heartbeat, reconnect и backpressure — и это оправдано только при высокочастотном вводе (drag-n-drop в PricingMatrix, live-слайдеры). Продакшен-паттерн: SSE вниз + короткие POST/fetch-keepalive вверх, с апгрейдом до WS для компонентов, генерирующих >10 событий/сек.

    3. Детерминированная валидация схем и безопасность клиентского исполнения (Zod / Pydantic)

    Фронтенд-галлюцинации — это не теоретический риск. Модель регулярно: подставляет enum-значение, которого нет в реестре (tier: "enterprise_plus"), отправляет обработчик события как строку (onClick: "fetch(/api/wipe)"), теряет обязательное поле или меняет тип (seats: "50" вместо 50), добавляет пропсы, которые компонент не умеет читать. Любой такой чанк при наивном рендеринге = белый экран или XSS-вектор.

    Двухуровневый шлюз валидации (Two-Tier Schema Gate):

    1. Сервер (Pydantic + Instructor / Structured Output). LLM физически не может вернуть невалидный Tool Call: constrained decoding ограничивает грамматику JSON-схемой. Дополнительно engine сверяет widget с каноническим реестром и проверяет required.

    2. Клиент (Zod runtime validation). Каждый чанк прогоняется через WidgetSchema.safeParse() до мутации состояния. Невалидный патч отбрасывается целиком, а не частично: seq-монотонность ломается → клиент инициирует resync (запрос полного снапшота) и показывает безопасный fallback — статичную карточку с кнопкой «уточнить у менеджера». Ни одна дельта не попадает в DOM без прохождения схемы.

    Изоляция исполнения. Каждый виджет монтируется как Web Component в Shadow DOM: закрытый (closed mode) корень, собственный CSS-scope, отсутствие протечки стилей и селекторов в хост-приложение. Внутри — никакого eval, new Function или динамических