桃子桃子快讯
返回首页
工具

把 LLM 塞进视图层:一次「每点一次都重新生成」的 Web 实验

开发者用 LLM 直接充当 Web 应用的视图层,每次点击都触发模型生成新 HTML,并实测了多款模型的生成耗时与单页成…

2026.07.02 · 周四5 分钟阅读

JD Trask 在「Prompt Poets Society」六月聚会上抛出一个想法:Web 服务器本质上是「文本进、文本出」,而 LLM 也是「文本进、文本出」。顺着这条思路,他做了一个名为 🔥 token burner 🔥 的实验性 Web 应用——LLM 直接充当整个应用的视图层,每一次点击都不是在调用已经写好的前端组件,而是触发模型重新生成一整张页面。

作者坦言这是一个「显而易见很糟糕的主意」:每次点击都要花钱、要等几秒钟、且返回结果每次都略有不同。但他依然把它实现了出来,因为在交互范式上,它和传统的 vibe coding 工具有本质区别——生成的 HTML 不是最终产物,而是对话本身的一个回合。

一次点击如何变成一张新页面

应用的机制并不复杂。不是所有交互都会回到模型;很多页面会保留普通的客户端 JS 来处理动画或本地 UI 状态。但只要模型想让某个元素触发新一轮对话,就会给该元素挂上一个 data-prompt 属性(表单则用 data-prompt-template),由一段注入的脚本把点击和提交转换成对 /c/:convoId/:turnId/act 的 POST 请求,body 就是下一条消息。生成的按钮本质上就是「待发送的下一条对话」。

服务端收到请求后做三件事:

  • 加载历史:通过一条递归 SQL 查询沿着 parent_turn_id 向上回溯对话树,避免兄弟分支的回合混入上下文。
  • 强制调用工具:把新提示追加进历史后调用模型,toolChoice 锁定到唯一的 render_page({ body_html, summary, style_hints }) 工具,模型只能返回结构化 HTML。
  • 渲染并返回:把 body_html 填入共享模板(预加载 Tailwind、D3、Chart.js、Three.js、Tone.js),再作为 GET /c/:convoId/:turnId 的真实响应返回。

一个关键设计是:模型永远看不到自己上一回合生成过的原始 HTML,每次回放给它的只有它自己写的 summary 字符串。这让输入上下文保持精简,模型在输出 token 上「挥霍」,在输入侧却相当克制。

工程上必须解决的细节

要把单次好玩变成可用的原型,还需要补上几块工程拼图:

  • 生成是异步的:回合先以 status: "pending" 写入数据库,LLM 调用后台执行,前端每秒轮询一次 /status,完成前显示 spinner。
  • 分支与去重:回合是一棵以 parent_turn_id 为键的树,从同一个父节点触发相同提示时,会复用已有页面而不是重新生成。
  • 系统提示要划清边界:作者显式禁止模型在前端伪造「后端功能」,任何需要真实逻辑的交互都必须再走一轮对话。
  • 浏览器负责导航:模型被禁止渲染返回按钮,因为生成的「返回」无法真正回到任何地方,只会再烧一轮去模仿之前的页面。真正的浏览器后退键已经够用,沿树走回去再开新分支才是这套交互的意义所在。

不同模型的生成耗时与成本

作者提供了一个模型选择器,让用户在「更聪明」和「更快更便宜」之间自行权衡。下面的数据来自他在不同模型下生成页面的实测(默认模型 claude-sonnet-4.6 的样本量远大于其他模型,其余为更小、噪声更大的样本):

平均页面生成耗时:

  • claude-sonnet-4.6:76.1 秒
  • claude-opus-4.7:64.7 秒
  • gemini-3.5-flash:57.0 秒
  • gpt-5.4-nano:47.7 秒
  • claude-haiku-4.5:11.6 秒
  • gemini-3.1-flash-lite:4.0 秒

平均单页成本:

  • claude-opus-4.7:$0.1493
  • gemini-3.5-flash:$0.1063
  • claude-sonnet-4.6:$0.0904
  • claude-haiku-4.5:$0.0098
  • gpt-5.4-nano:$0.0079
  • gemini-3.1-flash-lite:$0.0016

作者的评价是「比它应得的可用得多」。前沿模型下每一页都能感受到生成延迟,spinner 久到让人烦躁;用 gemini-3.1-flash-lite 这种小而快的模型时,体感已经接近普通页面加载的水平。他同时提醒,因为对话链接是可分享的,打开别人分享的分支相当于执行对方提示词诱导模型写出的 JS——这是一个玩具,请按玩具对待。

信源