Blind pedestrian crossing the road
Blind pedestrian crossing the road

Эта простая задача до сих пор не имеет 100% надёжного решения  - и агенты часто спотыкаются на совсем простых и очевидных вещах.
Так как типичная LLM обучена работать с  текстом, первые попытки были просто давать модели чистый HTML. И как не странно, это даже работало, причём надёжнее, чем ожидалось скептиками. Можно придумать 1000+ доказательств ущербности этого подхода, но это достаточно для 90% задач, когда надо просто прочитать текст, например новости или пост. Сразу же появились различной степени эффективности фильтры, убирающие «лишнее» в этой простыне.  
В случае факапа АИ переключалась на модели, заточенные на распознавание скриншотов.
Я не нашёл ни одной production-ready web-ориентированной системы,  опирающейся исключительно на  скриншоты. Это остаётся уделом  систем для работы с desktiop-приложениями. Спойлер: там тоже не всё хорошо, чемпион сейчас GPT-5.2 cо средней 86% точностью. Но точность на то и средняя, что в кнопки АИшка попадает обычно  первого раза, зато потом долго тупит на date picker‘ах. Расход токенов тоже не радует, а отслеживание изменений на экране открывает портал в ад, настолько там много подводных камней.

Одновременно в параллельной вселенной существовали E2E тесты, которые имитировали живых юзеров, нажимали на кнопки и заполняли поля. И этим тестам тоже как-то надо было отслеживать изменения на экране. Например, чтобы понять, что разработчик Вася переделал форму и не сообщил тестерам. Сравнение скиншотов оказалось крайне не надёжным методом. Тут разработчики Playwright – это известный open source фреймворк для E2E тестов, под крылом Microsoft - вспомнили про  ARIA и экранные читалки.

ARIA – случайный успех

В далёком 2014 W3C опубликовала первый стандарт WAI-ARIA 1.0. В то время все хотели WEB 2.0 но мало кто знал как его делать правильно. В результате интернет наводнили сайты с кастомными реализациями выпадающих меню, панелей и прочего JavaScript - UI. Внутри был винегрет из  <DIV>, что полностью дезориентировало читалки того времени.
ARIA представляла дополнительные свойства которые разработчик добровольно должен был внедрять в свой HTML код:

  • roles (что это за элемент)

  • names (как это называется)

  • states (что происходит с элементом прямо сейчас).

Почти никто, конечно, не собирался немедленно следовать этим рекомендациям. Но тут европейские в первую очередь законодатели привнесли немного бюрократии и обязали государственные сайты быть доступными для всех, в том числе для людей вынужденных использовать читалки. За ними подтянулись штаты с хайпом по инклюзивности и большие корпорации тоже  зашевелились. Google тоже подтянулся и в 2021 наконец сделал нормальную реализацию  accesibility tree  в Crome DevTools.
Казалось, вот оно, готовое решение для AI! Бери и пользуйся! Но, как всегда, вылезли подводные камни:

  1. Кросс браузерная совместимость. Забудьте про Firefox и WebKit.

  2. Ориентация на скрин-ридеры. Требуется сохранить совместимость с существующими ридерами, которые ориентированы на использование людьми. У человеков контекстное окно сильно меньше, у думают они немного по-другому. LLM без проблем выберет нужный элемент среди тысячи по ID, человек сломается на 10. 

  3. Отсюда ограниченная поддержка инкрементальных изменений.

  4. Зависимость от Google, у которого вообще нет причин любить разработчиков Playwright. Последние переметнулись от него в Microsoft в 2020 как раз под предлогом того, что Google  хотела привязать Puppeteer(это предшественник Playwright) к Chrome.

Собственно это было основной причиной, почему  разработчики Playwright сделали свой кросс-браузерный велосипед.  Продукт оказался очень удачным. Он не использует Chrome-зависимый API. Необходимый  Javascript - код инжектируется в браузер с помощью стандартных Playwright-методов, и там внутри творит свою чёрную магию. Он анализирует DOM и в соответствии с правилами, и, с учётом кучи специальных случаев, формирует ARIA – снэпшот.

Что же всё-таки видит LLM

ARIA снэпшоты которые делает Playwright  - это YAML, оптимизированный для потребления LLM. Выглядит он примерно так

- navigation [ref=e1]:
  - link "Home" [ref=e2]:
    - /url: /
  - link "Settings" [ref=e3] [active]:
    - /url: /settings
- main [ref=e4]:
  - heading "Account Settings" [level=1]
  - group "Profile":
    - textbox "Display name" [ref=e5]: John Doe
    - textbox "Email" [ref=e6]: john@example.com
      - /placeholder: you@example.com
  - group "Preferences":
    - checkbox "Email notifications" [ref=e7] [checked]
    - checkbox "Dark mode" [ref=e8]
  - button "Save Changes" [ref=e9] [cursor=pointer]

Никакого CSS. Никакой разметки. Никакого <div class="very_important_another_class"> . Чистое семантическое дерево. Три базовых понятия:
Роль соответствует возможностям взаимодействия. button можно нажать. textbox можно заполнить. checkbox можно переключить. Модели не нужно догадываться о том, интерактивен элемент или нет — это явно объявлено.

Имя предоставляют человекочитаемый идентификатор, вычисляемый по спецификации. Используется цепочка приоритетов:
сначала Plywright ищет aria-labelledby . Если не находит, смотрит на aria-label, далее <label>, потом содержимое элемента, title и, наконец, placeholder.
Именно поэтому

<button><svg class="icon-save"/></button>

невидим как для большинства экранных читалок или AI-агентов — буквально нечего использовать для вычисления имени. Добавьте aria-label="Save" — и проблема исчезает.

Состояние ([checked], [expanded], [disabled], [selected], [pressed]) фиксирует динамическое состояние UI. Модель понимает, что чекбокс уже отмечен, без необходимости визуально смотреть на маленький квадратик с галочкой. (Если вы когда-нибудь отлаживали агента на основе зрения, который “проваливался” на чекбоксах, вы знаете, о чём речь).

Генерация ссылок

Это уже Playwright-фишка, она появляется только в снимках предназначенных для АИ и в документации её нет.  Каждый элемент получает уникальный ref - идентификатор, который напрямую соответствует элементу DOM. Когда модель хочет выполнить действие, она использует его, а не XPATH, CSS или прочие селекторы.

{
  "name": "browser_click",
  "arguments": { "element": "Save Changes button", "ref": "e9" }
}

Инкрементальные различия: экономим токены

Сложное веб-приложение может содержать тысячи семантических элементов. Отправлять полный снимок после каждого действия агента — расточительно, а при оплате API за токен “расточительно” имеет очень конкретную денежную стоимость.

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

- <changed> main [ref=e4]:
  - ref=e5 [unchanged]
  - textbox "Email" [ref=e6]: john.doe@newdomain.com
  - ref=e7 [unchanged]
  - checkbox "Dark mode" [ref=e8] [checked]
  - ref=e9 [unchanged]

Маркеры [unchanged] говорят модели: «это поддерево идентично тому, что у тебя уже есть в контексте». На практике это даёт сокращение размера передаваемых данных примерно на 94% — с ~5КБ до менее чем 300 байт на страницах с 100+ элементами.

Именно эта функция делает экономически целесообразными многошаговые рабочие процессы агента. Без неё выполнение формы из 20 шагов означало бы постоянное расходование токенов на повторное описание всей страницы. С ней модель поддерживает внутреннюю “ментальную модель” и обрабатывает только дельты.

Под капотом: почему это сложнее, чем кажется

Сериализация инклюзивного семантического дерева кажется простой – пока не столкнёшься с подводными камнями. Реализация в Playwright обрабатывает целый ряд сложных случаев:

  • <template> и <slot>: ARIA-снимок должен показывать итоговый вид а не шаблоны с плэйсхолдерами.

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

  • Содержимое ::before и ::after видно пользователю и экранным читалкам. Оно включается в снимок.

  • Видимость  display: none, visibility: hidden, aria-hidden="true", элементы с нулевыми размерами — всё отфильтровано. Снимок отражает то, что реально видит пользователь.

Каждый из этих случаев — сложный и запутанный сценарий. Случай с aria-owns сам по себе требует построения виртуального дерева, которое не совпадает с реальной структурой DOM — по сути, вы делаете графовую хирургию “на лету”.

К сожалению, разработчики Playwright иногда придерживаются принципиальной позиции – не Playwright должен подстроиться под «плохие» сайты, а последние должны начать соответствовать стандартам. Поэтому до сих пор, например, поля ввода, полностью перекрытые модальным окном показываются «активными». Да, на них можно сфокусироваться с клавиатуры и даже ввести что-нибудь, но кто так делает в реальной жизни?

Слепые зоны

Что ARAI не показывает:

  • Визуальный дизайн - цвета, отступы, типографика, иконки. Красное сообщение об ошибке и дружелюбное зелёное сообщение об успехе выглядят одинаково в YAML.

  • Пространственные отношения - «кнопка под формой» или «рядом с формой»? Дерево не хранит информацию о расположении. (Некоторые агенты экспериментируют с аннотациями bounding-box, но это пока не стандарт.)

  • Canvas / WebGL - игры, графики, сложные визуализации не видны, если разработчик целенаправленно этим не занимался (спойлер: обычно нет).

  • Неявная визуальная семантика - «выделенная строка» работает только если “highlighted” задано как ARIA-состояние, а не просто через CSS-класс.

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

Сравнение агентов и инструментов

Claude (MCP)

Playwright ARIA-снимки + инкрементальные различия

Cursor

та же конвейерная схема, что у Claude

GitHub Copilot

весной 2026 перешёл на Playwright + ARIA

ChatGPT Browsing

анализ DOM

Anthropic Computer Use

cкриншоты, не специализирован для веб

Stagehand

анализ HTML

LaVague

скриншоты + анализ HTML

Примечание: почти все агенты могут использовать скриншоты как резерв. Общая тенденция: миграция на Playwright – ARIA.

Кумулятивный эффект

Playwright предоставляет ARIA-снимки как канонический формат наблюдений, и каждый агент (Claude, Cursor и растущая экосистема) использует один и тот же семантический язык.

Это создаёт положительный цикл:

Агенты стандартизируются на ARIA-снимках → разработчики улучшают инклюзивность → ARIA-снимки становятся лучше → агенты работают надёжнее → больше агентов принимают стандарт.

Сообщество по инклюзивности потратило 20 лет, убеждая разработчиков писать семантический HTML. Экономика AI может сделать за 2 года то, чего активизм не смог за 20.

Что это значит (часть, где я притворяюсь, что разбираюсь в бизнесе)

Дерево инклюзивности больше не просто галочка для соответствия стандартам. Оно становится де-факто API для программного взаимодействия с вебом. Несколько важных последствий:

Для AI-инженеров: если ваш агент по-прежнему в основном ориентирован на визуальные данные для веб-задач, вы теряете производительность и деньги. Архитектура “семантика в первую очередь + визуальный fallback” побеждает.

Для веб-разработчиков: ваш следующий самый требовательный “пользователь” — робот. Правильно размеченный <button> — это не только хорошая доступность, но и совместимость с AI. Кнопка только с иконкой без aria-label теперь является багом в двух измерениях.

Для индустрии: подход с ARIA-снимками приводит к реальной совместимости. Одна и та же страница одинаково работает для Claude, Copilot, Browser-Use и любых будущих агентов. Такое единство — редкость для индустрии и стало возможным благодаря тому, что базовый стандарт (ARIA) уже давно проверен на практике.

Для тестирования: вместо хрупких проверок CSS-селекторов можно писать семантические тесты, которые переживут редизайн. Например: «На странице должен быть отмеченный чекбокс с меткой ‘Email notifications’» — это и тест, и человекочитаемая спецификация.

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

Немного рекламы: бесплатное OpenSource расширение Playwright Write-and-Run для VSCode запускает Playwright код «на лету» без перезапуска теста. Позволяет пошагово проверить выполнение каждой команды, тут же поправить её если надо и продолжить дальше. Не нужно каждый раз перезапускать браузер и ждать логина/инициализации.