Вопрос, который здесь разбирается, звучит провокационно: можно ли перевести килобайты JavaScript-бандла в деньги, которые агент тратит на сборку приложения на этом фреймворке. Ответ оказывается неожиданным: прямой формулы «килобайт в токены» не существует, а сама метрика стоимости устроена иначе, чем подсказывает заголовок. Разберём, что именно измерялось, как считались токены и почему размер бандла и расход агента — две отдельные величины, которые не связываются коэффициентом.
Что такое «AI cost» и в чём он измеряется
«AI cost» в этом бенчмарке — денежная стоимость одного прогона сборки приложения агентом, в долларах США. Для каждого фреймворка берётся медиана 3–5 прогонов: например, Hono+htmx — $2.67, Angular — $4.97. Рядом приводятся токены в миллионах и время в минутах, причём токены и время, по наблюдению автора, «track pretty closely with the cost» — то есть тесно следуют за стоимостью.
Цена в долларах получается не пересчётом токенов по собственной формуле автора: токены сообщает Claude Code, а цены цитируются из API Claude Code — то есть денежное значение берётся из того же отчёта, что и токены, а не вычисляется отдельно. Поэтому «AI cost» — это денежный эквивалент сборки, а не токены и тем более не килобайты.
Важная оговорка о природе цифр: цены цитируются из API Claude Code и не отражают реально потраченные деньги — автор работает на плане Max.
Как устроен эксперимент
Приложение-«holotype»
Единым сценарием служило небольшое, но нетривиальное приложение-«Покедекс» на PokéAPI: список покемонов с типами, приёмами и данными из разных игр, с поиском и фильтрацией. Автор называет его «holotype» — единственным образцом типа сайта — и прямо оговаривает границы: это преимущественно контентный сайт с малой интерактивностью, ближе к Википедии, чем к Figma или GMail. Приложение выбрано потому, что его легко понять на высоком уровне и относительно просто описать спецификацией и протестировать.
Участники и версии
В сравнении участвовали Nuxt, Qwik, React Router, SolidStart, SvelteKit, TanStack Start, Vanilla и другие, для каждого зафиксированы точные версии пакетов:
- Nuxt — nuxt 4.6.2 и vue 3.5.44;
- Qwik — @builder.io/qwik-city и @builder.io/qwik 1.20.2 в первой итерации и 1.20.3 в итерациях 2–5;
- React Router — react-router 8.5.0 и react 19.3.1;
- SolidStart — @solidjs/start 2.1.0 и solid-js 1.9.17;
- SvelteKit — @sveltejs/kit 3.1.0 и svelte 5.57.2;
- TanStack Start — @tanstack/react-start 1.169.4 и react 19.3.1;
- Vanilla — vite 8.3.5.
Для Vanilla агент был проинструктирован использовать «vanilla JavaScript or TypeScript with Vite, without a UI framework». Vite выбран потому, что лежит в основе многих фреймворков и представляет достаточно стандартную и агностичную инфраструктуру JavaScript.
Агент и окружение
Спецификация передавалась модели Opus 5.5 с высоким уровнем усилий, с указанием использовать последнюю версию соответствующего фреймворка. Каждый агент работал в песочнице и не знал, что приложение будут проверять в Lighthouse на производительность и доступность, хотя получал набор тестов на соответствие. Для каждого фреймворка агент должен был использовать официальные MCPпротокол подключения внешних инструментов к модели или skillsпоставляемые фреймворком файлы-инструкции для агента этого инструмента. Прогоны повторялись, потому что результаты LLM стохастичны: «running multiple iterations did help».
Как считались медианы и интервалы
На каждый фреймворк выполнялось от 3 до 5 прогонов. Для метрик Lighthouse схема двухступенчатая: сначала медиана 5 запусков на приложение, затем медиана по 3–5 приложениям. Запись вида «3.85 M (3.16–8.18)−0.69+4.33» у Nuxt читается так: 3.85 M — медиана токенов, в скобках диапазон, а −0.69 и +4.33 — асимметричные отклонения вниз и вверх от медианы. Токены сообщал Claude Code, длительность — общее время по настенным часам.
Как агент «потребляет» фреймворк
Токены описываются как сумма чтений из кэшачасть ввода, которую модель берёт из ранее сохранённого контекста и которая тарифицируется отдельно от нового ввода, некэшированного ввода и вывода, и приводятся по фреймворкам без разбивки по шагам — например, у Angular медиана 9.76 M.
Зато фиксируется, какие инструменты агент реально задействовал, и разброс здесь большой. Для SvelteKit MCP использовался во всех 5 прогонах. Для React Router skill-инструмент и skill-файлы — в 5 из 5. Для Next.js агенты читали skill-файл лишь в 1 из 5 прогонов, а AGENTS.md — в 2 из 5; это файл с инструкциями для агента, который он читает, чтобы узнать правила работы с проектом. Для TanStack Start агент находил свои skill-файлы только в 2 из 5 прогонов, причём они поставляются в node_modules проекта. Для Nuxt MCP агентами не использовался вовсе. Прямой связи между чтением skill-файлов или AGENTS.md и расходом токенов материал не устанавливает; широкий разброс автор объясняет стохастической природой LLM.
Рисунок. Из чего складывается прогон: от спецификации до замеров токенов и Lighthouse.
Как сравнивали и что получилось
Стенд: модель Opus 5.5 с высоким уровнем усилий, песочница без знания о Lighthouse, официальные MCP или skills для каждого фреймворка, от 3 до 5 прогонов на фреймворк, для Lighthouse — медиана 5 запусков на приложение с симулированным мобильным троттлингом, затем медиана по 3–5 приложениям. Повторить можно, взяв тот же «Покедекс» на PokéAPI и те же версии пакетов.
Медианные токены на прогон, отсортированные по возрастанию:
| Фреймворк | Токены, M |
|---|---|
| Nuxt | 3.85 |
| Astro | 4.13 |
| Hono+htmx | 4.26 |
| Next.js | 4.99 |
| Vanilla | 5.00 |
| Qwik | 5.64 |
| TanStack Start | 7.07 |
| SolidStart | 7.13 |
| React Router | 7.58 |
| SvelteKit | 8.53 |
| Gracile+Lit | 9.04 |
| Angular | 9.76 |
Рисунок. Медианные токены на прогон по фреймворкам, миллионы токенов.
У Angular медиана взята по 3 итерациям: дважды не удалось создать рабочее приложение.
По стоимости наибольший разброс у Angular — $4.97 (3.19–6.82)−1.78+1.85, тогда как у Hono+htmx $2.67 (2.23–3.19)−0.44+0.52. По времени тоже Angular: 17.2 min (9.8–23.7)−7.4+6.5, у Nuxt 9.0 min (8.0–17.6)−1.0+8.6. По токенам снова Angular: 9.76 M (4.92–14.94)−4.84+5.18, у Nuxt 3.85 M (3.16–8.18)−0.69+4.33. По JavaScript-байтам лидирует Angular: 93 KiB (81–102)−12+9, у Gracile+Lit 8 KiB (1–13)−7+5. По TBTTotal Blocking Time — суммарное время, на которое главный поток блокируется длинными задачами наибольший разброс у Next.js: 71 ms (66–121)−5+50, у Nuxt 40 ms (14–54)−26+14. По LCPLargest Contentful Paint — момент, когда отрисован крупнейший видимый элемент страницы — снова Next.js: 2090 ms (1028–2187)−1062+97, у Vanilla 1667 ms (764–1676)−903+9. Итог: по большинству метрик (стоимость, время, токены, JS-байты) наибольшая вариативность у Angular, по TBT и LCP — у Next.js.
Связь с размером бандла
Токены и JavaScript-байты — две отдельные метрики бенчмарка: токены складываются из cache readsчтений из кэша — повторно переданного контекста, который не оплачивается как новый ввод, uncached inputнекэшированного ввода — нового текста, отправленного модели, и outputвывода — сгенерированного моделью текста, медиана по 3–5 прогонам; JavaScript-байты отчитывает Lighthouse, медиана по 3–5 приложениям. Для Next.js, например, JS-байты составляют 142 KiB (136–143), а токены — 4.99 M (3.54–8.82), и сопоставлять их напрямую не с чем.
Что действительно утверждается: размер кода влияет на число токенов, в том числе при будущих правках, а значит — на реальную стоимость поддержки кода во времени. Дороговизна Angular объясняется общим размером кода. Сама метрика JavaScript-байтов в основном отражает размер клиентского фреймворка. А токены тесно связаны со стоимостью и временем, но не с размером бандла.
Что цифры не показывают
Автор прямо называет эксперимент несовершенным. Приложение — единственный «holotype», контентный сайт с малой интерактивностью, поэтому результаты не переносятся на сложные приложения. Архитектуру (SSRserver-side rendering — рендеринг страницы на сервере vs CSRclient-side rendering — рендеринг страницы в браузере) и уровень производительности не задавали, а фреймворки различались тем, насколько они смещены в клиент или сервер и используют ли вообще клиентский фреймворк; агент Gracile в двух прогонах даже не использовал Lit. LLM стохастичны: иногда агент уходит в сторону и тратит токены не по вине фреймворка. Lighthouse сам даёт нестабильные результаты — LCP может выбрать одно изображение «крупнейшим» элементом, а на следующем прогоне другое. В двух прогонах Angular агент построил SSR-приложение, отклонявшее не-localhost, что автор счёл нарушением спецификации и не перезапускал.
Почему сделано именно так
Автор оговаривает, что не пытается выставить какой-либо фреймворк в дурном свете, и до запуска не знал, кто победит. Результат зависит от приложения и метрик: можно было бы сделать бенчмарк в пользу SPAодностраничное приложение, которое отрисовывает интерфейс в браузере и подгружает данные без полной перезагрузки страницы, выбрав сложный дашборд, видеоигру или продуктивное приложение, или мерить интерактивность внутри приложения вместо Core Web Vitalsнабора метрик Google о скорости загрузки, отзывчивости и визуальной стабильности страницы, которые жёстки к SPA. Чтобы уравнять условия, каждый фреймворк использовал официальные MCP или skills, а архитектуру и производительность не навязывали.
Для maintainability автор выбрал простой и проверенный показатель — общее число строк кода, отказавшись от навороченных метрик вроде цикломатической сложности. Смысл в том, что цель фреймворка — сократить объём кода, который нужно поддерживать, а размер кода влияет на число токенов и на реальную стоимость поддержки во времени.
Улучшить бенчмарк можно было бы, обязав агента использовать Service Workersфоновые скрипты браузера, которые перехватывают сетевые запросы страницы и могут отдавать закэшированные ресурсы для офлайн-кэширования, оптимизировав изображения покемонов, применив lazy-loading, fetchpriority, Speculation Rules APIбраузерный механизм, который заранее подгружает или отрисовывает страницу по правилам, заданным в разметке. Автор намеренно не направлял агентов к этим приёмам, потому что типичный вайб-кодер так не поступает. Другой вариант — предгенерировать все HTML-файлы как статические ресурсы — прямо запрещён инструкциями и проверяется тестовым стендом: это обход сути бенчмарка, цель которого — имитировать большой объём возможно динамических данных. Можно было бы прогнать больше итераций, взять других кодирующих агентов, другие уровни усилий, другие фреймворки и версии, варианты с MCP/skills и без, больше браузеров помимо Chromium, другие типы приложений — этого автор не делал в основном ради экономии времени.
Что из этого следует на практике
- Метрика «AI cost» — это деньги за прогон сборки, а не токены и не килобайты. Планируя бюджет на агентскую разработку, ориентируйтесь на стоимость прогона, а токены и время используйте как её спутники: они идут за стоимостью тесно.
- Размер бандла и расход агента — независимые метрики: пересчитать килобайты в токены нельзя, связь между ними утверждается только качественно — размер кода влияет на число токенов при будущих правках, то есть на стоимость поддержки.
- Разброс внутри одного фреймворка сопоставим с разницей между фреймворками. Медианы токенов лежат в диапазоне от 3.85 M до 9.76 M, но интервалы широкие, а у Angular и Next.js особенно. Одиночный прогон не показателен — нужны итерации и медиана.
- Использование инструментов фреймворка агентом нестабильно: MCP у Nuxt не использовался вовсе, skill-файлы Next.js читались в 1 из 5 прогонов, а TanStack Start находил свои файлы в
node_modulesтолько в 2 из 5. Если инструменты фреймворка важны для качества, рассчитывать на их автоматическое применение не приходится. - Результаты получены на одном контентном приложении с малой интерактивностью и без заданной архитектуры. Для сложных интерактивных приложений цифры не переносятся, а сравнение фреймворков с разным уклоном в клиент или сервер не полностью эквивалентно.