22 августа 2026 г.

Почему Barkan читает экран, а не документацию

Документация описывает продукт в целом. DOM описывает его для конкретного пользователя — прямо сейчас. Заглядываем внутрь: как Barkan превращает живую страницу в то, с чем может работать модель.

Трое коллег вместе работают за одним ноутбуком

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


Сбой, который изменил архитектуру

Версию, обученную на документации, сломал самый обыденный вопрос. Тестировщик спросил: «Как добавить второе рабочее место?» — и получил аккуратный ответ из шести шагов, взятый прямиком из базы знаний. Четвёртый шаг предлагал нажать Добавить участника. На экране тестировщика эта кнопка была серой, а всплывающая подсказка объясняла, что тариф Launch ограничен одним рабочим местом.

Ответ не был галлюцинацией. Он был верным — в общем случае — и бесполезным в частном. Модель понятия не имела, что кнопка неактивна: ничто в документации не могло сказать ей, как прямо сейчас выглядит экран этого аккаунта.

В этом главное ограничение любого ассистента, чьи знания взяты из текстов о продукте: он знает продукт таким, каким его задумали, а не таким, каким он отрисован для этого пользователя. И пользователи застревают как раз в разрыве между ними.

Если ответ зависит от того, что видит пользователь, модель тоже должна это видеть. Документации позволено объяснять зачем; говорить где вправе только живой интерфейс.


Что значит «читать экран»

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

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

Слой · Что в нём · Зачем это нужно

Интерактивные элементы · Кнопки, ссылки, поля ввода со стабильным идентификатором и доступной подписью · Чтобы модель могла указать на конкретный элемент управления и выполнить с ним действие

Связи · Какая подпись относится к какому полю, какая кнопка — к какой форме · Превращают «поле e-mail» в конкретный элемент

Факты интерфейса · Неактивные состояния, выбранные вкладки, бейджи, счётчики, ошибки валидации · Та самая информация «кнопка серая на тарифе Launch», которой никогда не было в документации

Блоки контента · Видимые заголовки и текст, без дублей и с обрезкой · Достаточно контекста, чтобы понять страницу, но не вся страница

Сводки по формам · Что заполнено, что пусто, что заполнено неверно · Позволяют модели продолжить наполовину выполненный сценарий

Активные поверхности и прокрутка · Открытые модальные окна, выдвижные панели, текущая видимая область · Отличают «нет на экране» от «не существует»

Метаданные страницы · Маршрут, заголовок, data-атрибуты из разрешённого списка · Дешёвый и надёжный способ сориентироваться

Весь снимок устроен так, чтобы быть компактным, стабильным и честным. Компактным — чтобы укладываться в бюджет контекста и оставлять модели место подумать. Стабильным — чтобы один и тот же элемент получал один и тот же идентификатор от реплики к реплике: только так возможны указание на элементы и многошаговые действия. Честным — чтобы модель никогда не видела элемент управления, которого не видит пользователь.


Три инженерные проблемы, которые это создаёт

Опора на DOM решает проблему «неправильно для пользователя» и тут же создаёт три новые. Они того стоят, но они вполне реальны.


1. Интерфейс движется

Индекс документации меняется, когда кто-то правит статью. DOM меняется, когда происходит что угодно: открывается выпадающее меню, всплывает уведомление, догружается список. Снимок, сделанный на секунду раньше, описывает страницу, которой уже нет.

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


Человек работает на ноутбуке, сидя на диване

2. Стабильные идентификаторы в нестабильном дереве

Сказать модели «нажми третью кнопку» — ненадёжно. Сказать «нажми элемент с id b17» можно, только если b17 будет означать то же самое и на следующей реплике. Современные фреймворки агрессивно перерисовывают страницу, поэтому полагаться на идентичность узлов DOM мы не можем.

Наши идентификаторы строятся из того, по чему элемент узнал бы человек: его роли, подписи, положения среди соседних элементов, ориентира (landmark), внутри которого он находится, — а соответствие между идентификатором и живым узлом мы храним в недолговечной карте. Когда карта устаревает, действие явно завершается ошибкой, и модель перечитывает страницу, а не нажимает не туда. Заметная неудача куда лучше, чем успешное действие не с тем элементом.


3. Что не отправлять

Обогащённый снимок реального продукта содержит реальные данные: имена клиентов в таблице, сумму счёта, e-mail в поле формы. Отправлять всё это модели по умолчанию недопустимо, и «это нужно для контекста» — недостаточно веская причина.

Снимок минимизируется на клиенте, прежде чем покинет страницу. Видимый текст обрезается и очищается от дублей, значения полей не копируются, а сводятся к заполнено / пусто / неверно, и передаются только data-атрибуты из разрешённого списка. Цель в том, чтобы модель знала, что на странице есть таблица клиентов на 48 строк и поле поиска над ней, а не кто эти клиенты.

Иногда минимизация стоит нам ответа. Если пользователь спрашивает: «Почему в этом счёте неправильная сумма?», модель не видит числа. Мы считаем, что это правильное поведение по умолчанию: модель может указать пользователю на поле и объяснить, как считается сумма, а сама цифра так и не покинет страницу.


Показывать, а не рассказывать

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

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

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

Barkan ведёт пользователя по сценарию внутри живого интерфейса
Курсор движется к настоящему элементу на настоящей странице: ничего не описывается, если на это нельзя показать


Где документация по-прежнему важна

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

Поэтому Barkan всё-таки обращается к базе знаний, но делает это после того, как прочитал экран, и при любом расхождении прав экран. Если документация говорит, что есть кнопка Добавить участника, а экран — что она неактивна, ответ будет про неактивную кнопку.

– Опирайтесь на отрисованный интерфейс, а не на документацию. «Верно в общем случае» — самый дорогой вид ошибки.

– Отправляйте структуру, а не пиксели и не сырой HTML: интерактивные элементы, связи, факты интерфейса, сжатый контент.

– Делайте снимок, когда страница успокоится, и повторяйте его после каждого действия: DOM — движущаяся мишень.

– Минимизируйте на клиенте. Модель должна знать форму данных, а не сами данные.

– Показывайте, а не описывайте. Если вы видите элемент, вы можете на него указать.


Установка — по-прежнему одна строка

Резонно опасаться, что «читает отрисованный интерфейс» подразумевает глубокую интеграцию. Это не так. Виджет — это один тег script в шаблоне страниц, который вы уже отрисовываете; он монтирует собственный корень в shadow DOM, наблюдает за страницей изнутри браузера и не требует ни аннотаций маршрутов, ни обёрток для компонентов.

<script async src="https://trybarkan.com/widget.js" data-barkan-site="site_your_key"></script>

Всё описанное выше происходит в этом скрипте. Продукту, в который он установлен, не нужно даже знать о существовании Barkan.

Установите сниппет, откройте своё приложение и спросите у него то, на что не отвечает ваша документация. $25 на балансе для начала, без привязки карты.

«Большинству пользователей не нужен ещё один ответ. Они хотят, чтобы им показали путь или чтобы всё сделали за них. В этом весь продукт.» 

Gabriel Lancelot

Сооснователь Barkan

Gabriel Lancelot, сооснователь Barkan