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 всё-таки обращается к базе знаний, но делает это после того, как прочитал экран, и при любом расхождении прав экран. Если документация говорит, что есть кнопка Добавить участника, а экран — что она неактивна, ответ будет про неактивную кнопку.
– Опирайтесь на отрисованный интерфейс, а не на документацию. «Верно в общем случае» — самый дорогой вид ошибки.
– Отправляйте структуру, а не пиксели и не сырой 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
