深度解析塑造未来的技术文章。

JavaScript 框架隐藏的 AI 成本

AI 编程代理对不同 JavaScript 框架的态度差别很大。了解为什么有些技术栈会多烧一倍 token,以及如何衡量你自己的技术栈。

等距插画:两条传送带,一条平稳运送整齐的包裹,另一条堵满超大板条箱
目的地相同,运费却天差地别。你选的框架决定了代理走哪条传送带。

代理花了十一分钟读迁移指南,才写下第一行代码。这不是你的代理,而是同事上周在一个 SvelteKit 项目上用的那个,提示词和你一小时前给 React 应用的一模一样。你的那次大约八分钟、四百万 token 就完成了。他们的那次花了十七分钟,消耗接近一千万 token,而其中很大一部分差距,是模型在耐心地重新学习一个它在训练时从没见过的框架版本。这种差距现在有了一个名字:JavaScript 框架的 AI 成本。而且多亏业内一件难得的事情,有人真的去测量,而不是凭空断言,我们终于拿到了它的真实数据。

Nolan Lawson 多年来一直用实际基准测试取代前端的经验之谈,最近他做了一件大家都懒得做、却显而易见的事。他为一个小但不简单的宝可梦应用定了规格,包括搜索、筛选、详情页,数据来自 PokéAPI,然后让编程代理用十二种方式把它做出来:Astro、Next.js、Nuxt、SvelteKit、React Router、SolidStart、Qwik、Angular、TanStack Start、Hono 加 htmx、Gracile 加 Lit,以及完全不用 UI 框架的纯 Vite。每个框架独立运行五次,使用相同的提示词;每次构建都用一致性测试套件检查,防止代理作弊;结果则从成本、时间、token 和 Lighthouse 指标几个维度打分。这个实验并不完美,Lawson 自己也承认。但这是我见过的第一次认真尝试,给一个大多数团队只凭感觉做的决定标上了价格。

基准测试实际衡量了什么

实验设置刻意保持中立。代理拿到规格,被要求使用给定框架的最新版本,架构(SSR 还是 CSR)随它自己选。凡是框架提供了官方 MCP 服务器、代理技能或插件的,都开放给代理使用,这样就没有哪个框架能抱怨自己在训练数据里被低估。一致性测试基于无障碍访问树而不是原始 DOM 运行,这一点很重要,因为有一个参赛者是通过 Shadow DOM 渲染的。每个框架跑五次,结果报告中位数。不过 Angular 有两次根本没能生成可测试的应用,所以它的部分数据只来自三次运行。

  • 每个应用的构建成本中位数从约 2.67 美元到 4.97 美元不等,最便宜和最贵的框架之间大约相差两倍。
  • Token 消耗讲的是同一个故事,只是更响亮:最便宜的技术栈约 400 万 token,最贵的接近 1000 万。
  • 耗时与成本高度吻合,快的一端约 8 分钟,慢的一端约 17 分钟。
  • SvelteKit、Gracile+Lit 和 Angular 的构建始终最贵;Astro 和 Hono+htmx 的组合则始终最便宜。
  • 令人意外的是,不用框架的纯 Vite 构建竟然逊于好几个真正的框架。哪怕对机器来说,有结构也胜过没有结构。

每次构建两美元听起来不算什么。单次确实不算什么。但代理式开发本质上是迭代的,没人会直接接受第一版输出。把这个差价乘以每个开发者每周几十次代理会话、乘以整个团队、再乘以一整年,你技术栈上的两倍 token 乘数就会变成实实在在的一笔开支。更重要的是,token 数量反映的东西比钱更值得关注:模型要在你的框架里写出正确代码,需要经历多少试错。token 数高通常意味着代理在困惑、反复读文档、不断重试。这是披着成本外衣的质量信号。

为什么有些框架让代理变得昂贵

我多年训练和评估模型的经验告诉我,这些结果并没有看上去那么神秘。三个机制几乎解释了全部差异,而且它们跟传统意义上哪个框架更好没有任何关系。

训练数据的密度决定命运

React 在智能体时代最大的优势,不在于它的编程模型,而在于十年间的教程、GitHub 仓库和 Stack Overflow 回答,已经把它的惯用写法压缩进了每个前沿模型的权重里。代理写 React 的时候,大部分是在回忆;而写 Gracile 的时候,代理基本是在摸索。在这次基准测试中,不熟悉某个框架的代理会去克隆框架仓库,或者从 node_modules 里翻编译后的源码。这些 token 是在用户代码出现之前,花在补课上的。这与开发者获取知识的整体变化是同一个动态。我写过随着 Stack Overflow 衰落,开发者知识语料会发生什么,而框架这个角度是一个尖锐的特例:冷门工具不只是缺少社区,它们在模型本身里也缺少存在感。

API 变动是一种持续的 token 税

SvelteKit 表现不佳有一个具体且颇为好笑的原因:代理每次运行都读了 SvelteKit v3 的迁移指南,因为这个版本太新,还没进入模型的训练数据。框架每发布一次破坏性变更,都会让模型已经记住的模式失效,迫使它在推理时从文档里重新推导正确的 API,每次会话、每个用户都要用 token 来买单。框架把大版本的动荡当作营销事件,而对使用代理的人来说,那是一笔持续的附加费。一个三年都没有破坏 API 的无聊框架,按这个指标衡量,就是一项高级功能。

冗余在循环中被放大

Angular 的成本似乎与它庞大的代码量成正比。生成的代码行越多,输出的 token 越多,之后每次编辑时需要重新读取的 token 也越多,代理出错的空间也越大。这个规律可以推广:任何工具输出冗长、构建日志嘈杂或测试命令缓慢的技术栈,都会迫使代理在每次迭代中淌过更多文本,而每一次 lint 或类型检查失败都会触发一轮昂贵的往返。从业者在各处都报告了同样的模式:主导代理开销的是迭代的成本,而不是生成的成本。一个快速、安静、严格的工具链,比一个宽松的工具链更便宜,因为严格的约束能在一轮内抓住代理的错误,而不是五轮。

你的框架每发布一次破坏性变更,都是有人要用 token 来买单的税。而且与人类阅读变更日志不同,模型每次会话都要付这笔税。

代理基准测试中的掷骰子问题

我以前做机器学习评估的习惯在这里发挥作用,因为整个研究中最重要的细节是误差范围。LLM 的输出是一个分布,而不是一个点。React Router 的构建成本中位数比 Hono+htmx 高约一美元,但 React Router 最便宜的那一次运行,却比 Hono 最贵的一次还要低。两者的区间大幅重叠。SvelteKit 的运行结果从约 3.20 美元到 6.80 美元不等。有时代理就是运气差,跑偏了方向,烧掉几百万 token,而原因跟框架毫无关系。

一个小机器人在昏暗的图书馆里,台灯下翻阅堆成高墙的手册
当框架不在训练数据里时,代理只能自己查资料,而你要为每一页买单。

工具使用的数据也说明了同样的问题。各框架都提供了 MCP 服务器和技能文件,而代理使用它们……有时候。Nuxt 的 MCP 服务器在五次运行中从未被调用。TanStack Start 的技能文件在五次中只被发现了两次。React Router 的技能每次都被用上了。同样的提示词、同样的执行环境,行为却天差地别,这正是这类工具的随机性。这意味着,每条宣称“框架 X 对代理好太多了,我把整个应用都重写了”的推文,如果只是基于一个下午的氛围编程,衡量的就只是噪声。一次运行只是一则轶事。如果你要让 AI 成本影响架构决策(我认为你应该这么做),那么在相信任何结论之前,都要求看到多次重复运行的中位数,包括这个基准测试在内。

在输出质量上,一切都趋于不错

最令人惊讶的是没有变化的那部分。Lighthouse 的性能、无障碍和累积布局偏移分数,在全部十二个技术栈中几乎都接近饱和,到处都是 99 和 100。只要有清晰的规格和一致性测试套件,现代代理在几乎任何框架里都能做出称职、无障碍的小型应用。质量底线已经抬高到这样的程度:在内容导向的网站上,框架本身几乎不会造成输出的差异。

唯一有明显差距的质量指标是传输的 JavaScript 体积:类岛屿架构的 Astro 和 Hono+htmx 构建为零 KiB,最重的单页应用输出则高达约 142 KiB。总阻塞时间在各处都微不足道,而 LCP 噪声太大,不宜过度解读。这里有两点诚实的说明。测试应用更接近维基百科而不是 Figma,因此对多页架构有利;而 Lighthouse 本身在结构上就对 SPA 不利。尽管如此,纯 JavaScript 的结果仍值得停下来想想:被要求使用无框架纯 Vite 的代理,得分比好几个真正的框架都差,包括所有构建中最高的布局偏移。框架封装了约定,而代理非常依赖约定。给模型一条走熟了的轨道,它就会待在上面;给它一片空白,它就会即兴发挥,而且未必做得好。

这个基准测试无法告诉你什么

在有人基于宝可梦演示重写生产应用之前,我们先坦诚地看看它的适用范围。这是一个小型、以内容为主的应用,几乎没有跨模块状态、没有本地化、没有复杂表单,也没有一个团队会在未来五年里持续维护它。这是真实的局限,也是我在这个博客里反复提到的同一个陷阱:AI 基准测试系统性地遗漏了真实工作的大部分内容。让框架在全新的玩具项目里对代理友好的特性(熟悉度、简单性、静态结构),并不是一个已经到第十八个月、代码混乱的真实产品所需要的特性。

讨论中的框架怀疑论者还点出了一个更深层的道理。框架的历史价值,很大一部分从来不在于它让你能做什么,而在于它禁止你做什么。Java 在企业开发中的成功,部分就是因为它强迫一万名程序员写出看起来一样的代码。框架是为人类团队设计的约束系统,团队成员会加入、离开,也会互相误解。代理并不需要防止无聊或为简历而写代码的护栏,它需要的是清晰的规格和测试套件。有一位从业者在 htmx 上报告了这种颠倒:代理轻松完成了简单页面,却在复杂的有状态表单上栽了跟头,丢失状态、搞坏切换开关,这些问题 React 本可以一次搞定,直到有足够多的测试让它保持诚实。对代理真正重要的约束不是框架,而是一致性测试套件。

当然,最便宜的构建并不等于最便宜的代码库。为了一个你的团队深入理解、并能维护多年的技术栈,每次代理会话多花两美元,显然是正确的选择。但注意,这种论证需要数字。衡量 AI 成本的全部意义,不是为了评出一个赢家,而是用可以权衡的数字,取代“这个框架对代理更好”这样的说法,让你能把它和招聘池、生态成熟度以及包体积放在一起比较。开发者体验的争论里,感觉已经输了;在代理时代的争论中,它也不应该默认获胜。

如何衡量你自己技术栈的 AI 成本

不要把别人的基准测试(包括这个在内)直接套用到你的代码库上。你的仓库、你的规格和你选的模型,会产生属于它们自己的分布。好消息是,衡量 AI 成本其实相当容易,因为编程代理本身已经报告了你需要的一切。如果你想在动手插桩之前先弄清循环、上下文和权限是如何相互作用的,我们那篇智能编程 CLI 到底是怎么工作的是很好的基础。然后按下面的步骤做:

  1. 选一个能代表你真实工作的纵向切片,比如涉及数据层、状态管理和 UI 的功能,而不是一个落地页。
  2. 先写一致性测试。测试既是质量关卡,也是防作弊的手段;没有测试的代理会过早宣布胜利。
  3. 每个候选技术栈或配置至少运行五次相同的提示词。报告中位数和区间,绝不只报告单次结果。
  4. 记录总 token(区分缓存读取、输入和输出)、实际耗时、成本,以及工具调用次数和重试循环次数。
  5. 统计有多少 token 花在阅读文档上,例如迁移指南、变更日志,以及在 node_modules 里的翻找。这就是你的训练数据缺口税,直接量化了。
  6. 在大版本升级之后重新运行基准测试。随着 API 变动和训练截止日期推移,AI 成本会发生漂移。

这套测试框架本身花一个下午写脚本就够了。下面是我用过的骨架。具体的 CLI 参数取决于你使用的代理,但整体结构是通用的:

import json
import statistics
import subprocess
FRAMEWORKS = ["astro", "react-router", "sveltekit"]
RUNS = 5
SPEC = open("spec.md").read()
def build_once(framework: str) -> dict:
"""One full agent session: build the app, return usage stats."""
result = subprocess.run(
[
"agent-cli", "run",
"--prompt", SPEC,
"--context", f"Build this with the latest {framework}.",
"--output-format", "json",
],
capture_output=True,
text=True,
check=True,
)
return json.loads(result.stdout)
for framework in FRAMEWORKS:
runs = [build_once(framework) for _ in range(RUNS)]
costs = [r["cost_usd"] for r in runs]
tokens = [r["tokens_total"] for r in runs]
print(
f"{framework}: "
f"median ${statistics.median(costs):.2f} "
f"(range ${min(costs):.2f}-${max(costs):.2f}), "
f"median {statistics.median(tokens) / 1e6:.1f}M tokens"
)

重试次数和 token 总数一样值得密切关注。根据我的经验,“每个通过的测试消耗多少 token”是最诚实的指标:它把成本、困惑度和正确性压缩成一个数字,并且会惩罚真正伤人的失败模式,也就是代理在五轮编译错误循环中挣扎,才勉强写出能通过的代码。一个代理第一次或第二次尝试就能干净通过的框架,每次都会胜过一个名义上更便宜、却需要不断纠错的框架。

一台黄铜天平,一端是金币,另一端是发光的半透明方块,置于木桌上
Token 正在成为一种架构成本单位,值得与决策中的其他因素放在一起权衡。

务实的结论

那么,你应该因为代理觉得 Astro 更便宜,就把你的 Angular 应用重写成 Astro 吗?不应该。两者的成本差很小,方差却很大,测试应用只是个玩具,而且你的迁移本身消耗的代理 token,可能比十年里省下的还多。任何以“为了代理”来推销框架迁移的人,都是在用行业一贯的凭感觉推理,只是额外加了一个新理由。

但 AI 成本理应在决策桌上占据一席之地,与招聘池、生态深度和包体积并列。对于全新项目,证据指向一个一致的方向:选择训练数据覆盖深、API 变动慢、工具链严格而安静、并且模型已经见过上万次的约定俗成的技术栈。无聊的技术一直是务实的选择,代理只是让“无聊”变得可以衡量。锁定你的框架版本,因为在模型追上来之前,每次升级都意味着推理时的一笔税。无论你选哪个框架,都要投入一致性测试。它们是唯一能让每个代理都变得更便宜的资产,能在代理陷入困境时保持它诚实,并且在你今天用的模型过时很久之后依然有价值。框架会不断更迭,而测试和测量的习惯,才是能留下来的东西。