Браузер для агента: что отдавать в DOM, а что пикселями

Архитектура Kitesurf от Cloudflare: почему браузер для модели это не обычный браузер, и три решения, которые стоит подсмотреть.

· 3 мин чтения

Агент открывает страницу и начинает по ней «кликать». Внутри серия хрупких операций: найти элемент по координатам, кликнуть, дождаться перерисовки, прочитать новый DOM. Каждый шаг — это потеря времени и шанс ошибиться. Та же страница, открытая через инструменты, отданные самим сайтом, решается одним вызовом функции.

В августе Cloudflare представила Kitesurf, браузер, построенный не вокруг интерфейса для человека, а вокруг того, что агенту нужно от веба. С тех пор команда расширила его и опубликовала апдейт; его полезно разобрать как готовый референс: что отдавать модели в DOM, что в скриншот, и как не тащить в оркестратор весь балласт браузера.

Принцип: страница отдаёт инструменты, а не пиксели

Ключевой механизм здесь WebMCP. Сайт публикует список функций вроде searchFlights или set-location, и агент вызывает их напрямую. Это тот же шаблон, что и tool calling у модели, только источник инструментов — сама страница. В Cloudflare пишут, что «кликать пиксели и надеяться на правильный элемент» медленно и хрупко, а вызов функции — быстро и предсказуемо.

Недавно Cloudflare дала владельцам сайтов возможность включить WebMCP одним переключателем: агент может находить и использовать инструменты сайта без правки его клиентского кода.

Что важно внутри движка

Для агента «быстро» — это не «быстро грузится», а «короткий цикл рассуждения». В Kitesurf оптимизировали то, что обычно никто не оптимизирует в браузере: границу между Boa и DOM, чтобы частые чтения вроде getAttribute или parentNode отвечались внутри Wasm-DOM без прыжков в JS-обвязку. Таймеры и загрузка скриптов стали меньше повторять работу. Шрифты тянутся по факту использования: сначала проверка, какие символы реально нужны странице.

Результат: при росте поддержки стандартов (Web Platform Tests проходит уже 730 000+ субтестов, на 500 000 больше, чем на момент запуска) и общее время работы, и потребление CPU остались примерно на уровне стартовых бенчмарков. Идея применима шире: агенту важна не пиковая скорость, а стабильная низкая задержка каждого шага цикла.

Как разнесены безопасность и рендеринг

В Kitesurf PageScript (изолят, который запускает код страницы) жёстко отделён от PageRenderer, который превращает вычисленные объекты в пиксели. Это позволило вынести рендер наружу: на клиент, в отдельный Worker или, например, в терминал. У них получилось собрать версию, которая выводит страницу через Kitty-протокол или чистый ANSI.

Для оркестратора это важно по двум причинам. Во-первых, чувствительный код страницы остаётся в песочнице на периферии сети, а пиксели стримятся наружу, та же модель, что и в Cloudflare Browser Isolation. Во-вторых, рендер можно перенести туда, где он нужен, и не держать его в основном цикле агента.

Как повторить

  1. Разделите оркестратор и рендер. DOM и выполнение скриптов — в песочнице на своей стороне, пиксели стримом отдаются клиенту или отдельному воркеру.

  2. Отдавайте агенту инструменты, а не пиксели. Для своих сервисов публикуйте функции, которые закрывают частые действия. Если пользуетесь чужими, ищите те, что поддерживают WebMCP, или хотя бы дают стабильные селекторы и API.

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

  4. Шрифты и тяжёлые ресурсы по факту использования. Агент редко «видит» страницу глазами; типичные шрифтовые наборы часто избыточны. Проверяйте, какие символы реально нужны, и тяните только их.

  5. Берите стандартные тесты совместимости как метрику качества движка. Web Platform Tests в Kitesurf — это не «галочка», а способ отслеживать прогресс в открытом виде и не ловить регрессии при добавлении фич.

  6. Держите интерфейс доступа универсальным. Kitesurf даёт один движок для CDP, Playwright, Puppeteer и MCP: у каждого свои клиенты, но движок один. Так интеграция в существующую обвязку не требует переписывать конвейер.