arka triymfalnaya

kitesurf - браузер для агентов, работающий в v8‑изолятах на cloudflare workers [перевод]

Вольный перевод статьи Jakob Kummerow "Introducing Kitesurf: The agent-first browser that runs in V8 isolates on Cloudflare Workers"


в cloudflare несколько лет время от времени возникал один и тот же вопрос: а не собрать ли нам собственный браузер?

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

потом сошлись сразу несколько обстоятельств. wasm в workers стал достаточно зрелым, появились dynamic workers, rpc между workers, sqlite-based durable objects, улучшилась совместимость с node.js и выросли лимиты платформы.

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

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

- количество токенов;
- размер контекстного окна;
- стоимость;
- масштабирование;
- структурированный html;
- доступ к dom и сетевым запросам.

поэтому двенадцать недель назад в cloudflare снова задали тот же вопрос. на этот раз ответ был коротким: да.

так появился kitesurf — браузер, который целиком работает поверх cloudflare workers и рассчитан прежде всего на ai-агентов. пока он доступен бесплатно в beta-режиме через browser run.

с чего всё началось

первой отправной точкой стал obscura — headless-движок на rust для ai-автоматизации. у него не было chrome, node.js и длинного списка зависимостей.

команда попробовала перенести его в workers с помощью ai-агента. сначала ничего особенно не получилось. но когда агенту дали подробный план, понятные критерии успеха и возможность самостоятельно задавать вопросы, прототип всё-таки заработал.

работал он, правда, едва-едва. но этого оказалось достаточно, чтобы команда решила продолжить.

основные решения

тестов должно быть много

перенести прототип в полноценный браузер — это не один большой рывок, а большое количество маленьких итераций. ai помогал писать код, но сам по себе код ещё не гарантирует, что браузер правильно работает.

поэтому основой стали web platform tests. это большая коллекция тестов на соответствие стандартам w3c. агенты получали конкретные задачи и могли самостоятельно проверять, насколько хорошо они их выполнили.

но одних wpt недостаточно. они проверяют стандарты, а не то, как браузер ведёт себя на настоящем интернете.

для этого cloudflare добавила:

- интеграционные тесты;
- визуальное регрессионное тестирование;
- многошаговые тесты puppeteer;
- параллельное сравнение chromium и kitesurf.

проверялось не только итоговое утверждение теста, но и изображение страницы после каждого шага.

rust, если это возможно

workers хорошо работают с wasm, поэтому код можно писать на rust, c++ или c и затем компилировать в wasm.

команда выбрала rust и wasm-bindgen. от emscripten отказались, потому что его дополнительные слои эмуляции увеличивают размер и стоимость выполнения бинарника.

короче говоря, хотелось быть как можно ближе к железу. насколько это вообще возможно, когда всё происходит внутри v8 isolate.

ошибка не должна убивать сессию

интернет — ненадёжная и местами довольно враждебная среда. браузер должен уметь переживать плохой html, странный javascript и неожиданные ошибки.

поэтому у kitesurf есть простое правило: ошибка должна привести к пустому фрейму или отсутствующему элементу, но не к смерти всей сессии.

каждая граница между компонентами ловит ошибки, подставляет безопасное пустое значение и пишет достаточно логов для последующей диагностики.

изоляция

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

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

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

как можно меньше состояния

состояние делает сбои дорогими. если компонент хранит много данных, после падения его приходится восстанавливать.

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

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

как устроен kitesurf

в системе есть три главных компонента:

- engine;
- pagescript;
- pagerenderer.

sandboxoutbound

браузеру приходится загружать изображения, стили, шрифты, javascript и wasm с произвольных сайтов. это одна из самых опасных операций.

в kitesurf сеть контролирует отдельный worker — sandboxoutbound. остальные компоненты не могут обращаться к интернету напрямую.

он отвечает за:

- cors;
- заголовки, похожие на браузерные;
- фильтрацию ответов;
- отдельное cookie-хранилище для каждой страницы;
- блокировку запросов, которые не проходят политику безопасности.

если запрос запрещён, компонент получает 403.

engine

engine — единственный публичный компонент. он принимает подключения по websocket и http, обрабатывает chrome devtools protocol и хранит состояние сессии.

остальные части системы stateless.

использование cdp даёт совместимость с уже существующими инструментами. к kitesurf можно подключить puppeteer, playwright, chrome-remote-interface и интерфейс chrome devtools.

для клиента это означает, что почти ничего менять не нужно. браузер выглядит как ещё один cdp endpoint.

pagescript

pagescript запускается в отдельном dynamic worker для каждой страницы и каждого out-of-process iframe.

внутри isolate находятся:

- чистый `globalThis`;
- объект dom;
- javascript страницы;
- wasm-код страницы;
- состояние текущей сессии.

html и css разбираются с помощью компонентов blitz и stylo — css-парсера firefox. оба проекта написаны на rust.

javascript и wasm для страницы запускаются в одном isolate.

а что делать с eval

с eval всё сложнее. workers пока не разрешает использовать его нативно по соображениям безопасности. запустить отдельный isolate тоже нельзя: у него не будет доступа к текущему globalThis.

поэтому kitesurf использует boa js — javascript-движок на rust, который запускается поверх workers.

получается runtime внутри runtime. звучит не очень оптимально, потому что так оно и есть. но для редких вызовов eval этого пока достаточно.

pagerenderer

pagerenderer превращает вычисленное состояние страницы в изображение.

когда engine нужен новый кадр, pagerenderer:

1. получает описание страницы от pagescript;
2. загружает нужные изображения и шрифты;
3. растеризует содержимое;
4. возвращает изображение в engine;
5. отдаёт клиенту png, jpeg или pdf.

за отрисовку отвечают компоненты blitz-paint и parley. parley занимается формированием глифов, выбором шрифтов и разбиением текста на строки.

renderer не хранит состояние страницы. поэтому engine может спокойно завершить зависший worker и поднять новый, если rpc-вызов завершился ошибкой.

тесты и производительность

kitesurf уже проходит больше 215 тысяч web platform tests, причём команда каждую неделю добавляет новые.

лучше всего пока покрыты функции, важные для агентов:

- css;
- dom;
- html;
- выделение;
- svg;
- xhr;
- streams.

cloudflare сравнила kitesurf и chromium на 14-URL наборе. использовались медианные значения пяти запусков browser run.

показатель kitesurf chromium результат
cpu, скриншот 380 ms 1 173 ms в 3,1 раза меньше
cpu, извлечение html 229 ms 877 ms в 3,8 раза меньше
память, скриншот 57,8 mib 271,0 mib в 4,7 раза меньше
память, извлечение html 39,4 mib 273,7 mib в 7 раз меньше
полное время, скриншот 1 148 ms 637 ms в 1,8 раза медленнее
полное время, извлечение html 820 ms 472 ms в 1,7 раза медленнее

chromium быстрее по времени выполнения. это ожидаемо: у него есть jit и уже прогретый браузерный процесс.

зато kitesurf заметно дешевле по cpu и памяти. а именно эти показатели в конечном счёте сильнее всего влияют на стоимость запуска большого количества сессий.

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

doom тоже запускается

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

у kitesurf doom запускается.

этого, конечно, недостаточно для серьёзной проверки. но всё равно приятно.

как попробовать

kitesurf уже доступен в browser run и пока работает бесплатно в beta-режиме, с ограничениями на аккаунт.

существующий cdp endpoint теперь принимает параметр:

browser=kitesurf

это значит, что можно использовать текущие клиенты puppeteer, playwright, chrome-remote-interface, а также ai-агентов, которые работают через mcp или cdp.

для быстрого скриншота достаточно добавить параметр к endpoint:

curl -X POST \
  'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-run/screenshot?browser=kitesurf' \
  -H 'Authorization: Bearer <apiToken>' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com"
  }' \
  --output "screenshot.png"

есть и публичный playground. туда можно ввести любой url и посмотреть, как kitesurf его отображает.

в интерфейс playground встроен chrome devtools. можно смотреть dom, сообщения консоли, сетевые запросы и потребление памяти wasm.

когда kitesurf имеет смысл

сейчас он корректно работает с такими страницами, как:

- todomvc на vanilla javascript;
- react;
- vue;
- angular;
- preact;
- wikipedia;
- hacker news;
- cloudflare blog;
- значительная часть dashboard cloudflare.

kitesurf хорошо подходит агентам, которым нужно:

- извлечь содержимое страницы;
- получить структуру html;
- сделать скриншот;
- сгенерировать pdf;
- выполнить короткую автоматизацию;
- быстро обработать много страниц.

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

чего он пока не умеет

kitesurf пока не лучший выбор, если нужны:

- видео;
- webgl;
- сложные bot challenge;
- настоящие tls fingerprints;
- долгие авторизованные сессии;
- сохранение состояния между запусками;
- полная pixel-perfect совместимость с chromium.

для таких задач cloudflare рекомендует использовать обычный browser run на базе chromium. если неизвестно, поддерживает ли kitesurf конкретный сайт, проще всего открыть его в playground и проверить.

что будет дальше

kitesurf существует всего около двенадцати недель. первый commit появился в мае, так что проект ещё довольно молодой.

команда работает над несколькими направлениями:

- расширяет поддержку cdp;
- улучшает точность отрисовки скриншотов и pdf;
- добавляет новые web api;
- увеличивает покрытие wpt;
- оптимизирует cpu, память и полное время выполнения.

в будущем cloudflare собирается открыть kitesurf исходный код. цель — дать пользователям возможность запускать собственную версию браузера в своих аккаунтах.

а пока предлагается просто открыть playground, попробовать несколько сайтов и посмотреть, что получится.

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