如何使用 Next.js、AWS 和沙箱构建属于你自己的类似 Lovable 的 AI 应用生成器

如何使用 Next.js、AWS 和沙箱构建属于你自己的类似 Lovable 的 AI 应用生成器

💡 原文英文,约5100词,阅读约需19分钟。
📝

内容提要

本文介绍如何从零构建类似Lovable的AI应用生成器:让AI在隔离云沙箱中编写代码,防止未审查代码危害主机;通过内存快照将沙箱启动时间从33秒缩短至4秒;智能体循环可自动写码、自检并修复错误;使用Postgres事件流实时推送进度,网关代理实现热更新预览;采用Git版本管理且令牌不进入沙箱;闲置沙箱自动休眠唤醒,发布时构建静态文件上传至S3。

🔎

延伸解读

沙箱隔离:安全与性能的平衡

文章强调AI生成的代码未经审查,必须在隔离沙箱中运行,避免危害主机。沙箱不仅提供安全边界,还通过内存快照将启动时间从33.4秒缩短至4秒,唤醒仅需2.4秒。这种设计在安全与效率之间取得了平衡,尤其适合需要快速迭代的AI应用生成场景。

智能体自检与修复机制

智能体在完成代码编写后,会运行类型检查、构建和渲染测试,确保应用可运行。若检查失败,错误会反馈给智能体进行修复,最多三轮。这种自检循环减少了人工干预,提高了生成代码的可靠性,但也存在修复失败的可能,此时会向用户报告错误。

实时进度与预览的实现

通过Postgres事件流和SSE,智能体的每一步操作都能实时推送到浏览器,且刷新页面不会丢失进度。预览网关代理沙箱内的Vite开发服务器,支持热更新,让用户即时看到代码修改效果。这种设计提升了交互体验,但依赖稳定的网络和数据库。

版本管理与发布策略

每次成功修改都会通过Git提交版本,用户可回滚到任意版本。发布时,应用被构建为静态文件上传至S3,独立于沙箱运行,确保即使沙箱休眠也能访问。这种策略保证了发布的稳定性和安全性,但发布过程需要额外的构建时间。

❓

Q&A

为什么AI生成的代码必须放在沙箱里运行?

因为整个产品本质上是在运行未经审查的代码:AI写的代码、npm install拉取的包(其安装脚本可能执行任意命令)、以及启动的dev server都会执行这些代码。如果直接在自己的服务器上运行,可能被rm -rf等操作破坏系统。所以每个项目都需要一个隔离的云沙箱(小型VM),即使代码有恶意也无法危害主机。

如何把沙箱启动时间从33秒缩短到4秒?

使用内存快照。先一次性完成创建沙箱、上传模板、npm install、启动dev server等冷路径操作,然后对沙箱做checkpoint,保存文件、内存和运行中的进程。之后每个新项目只需从该快照恢复,dev server已经在运行,无需重新启动。实测冷启动33.4秒,从快照恢复仅4.0秒,唤醒休眠沙箱2.4秒。

智能体循环是如何自动写代码并修复错误的?

智能体循环给LLM提供工具(如读写文件、运行命令、安装包、获取日志等),LLM调用工具后结果反馈给它,循环直到调用finish。当智能体认为完成时,系统会在沙箱内运行三项检查:TypeScript类型检查、Vite构建、以及用happy-dom渲染应用一次。如果检查失败,错误会作为新消息发回给智能体,让它再修复,默认最多3轮。

如何把智能体的实时进度推送到浏览器,并且刷新页面不丢失?

worker将每一步作为一行写入Postgres的run_events表,并发送NOTIFY。Web端通过Next.js路由处理器用Server-Sent Events流式推送给浏览器。浏览器连接时先重放当前run的所有事件,然后持续监听新行。因为事件都持久化在数据库中,刷新页面后浏览器重连并重放,不会丢失进度。

预览网关是如何实现热更新并保证安全的?

网关将<project-id>.preview.localhost:4000代理到沙箱内的Vite dev server(端口5173),并在服务端添加沙箱API密钥。它同时代理WebSocket升级,使Vite的热更新能实时推送文件变更,预览自动更新。网关还删除了请求中的cookie和authorization,且预览运行在不同源(*.preview.localhost),因此生成的app无法读取主应用的cookie或冒充登录用户调用API。

如何用Git做版本管理,同时避免把令牌放进沙箱?

每个成功回合后,worker在沙箱内执行git commit,将变更保存为新版本。为了持久化历史,沙箱不直接push,而是用git bundle create打包整个仓库,worker读取该bundle文件,然后在worker端用短期令牌推送到托管Git仓库。这样令牌从不进入沙箱,即使沙箱被攻破也无法窃取。恢复版本时不会重写历史,而是将文件匹配旧提交后作为新版本提交。

闲置沙箱如何自动休眠和唤醒?

有一个每分钟运行的任务,将10分钟没有智能体运行的沙箱挂起(suspend),挂起会保留内存,dev server状态不变。当有人打开休眠项目的预览时,网关会显示“Waking up your app...”页面并自动刷新,同时在后台恢复沙箱。实测唤醒约3秒,之后应用即可加载。

发布应用时是如何处理的,为什么发布后不依赖沙箱?

发布时会在沙箱内执行vite build生成静态文件,然后将dist目录下的所有文件上传到S3(本地用MinIO),并保存发布站点信息。网关随后从S3提供这些文件,访问地址为<slug>.app.localhost:4000。由于发布的是静态文件,即使沙箱休眠,已发布的站点也能正常工作。实测发布耗时约6秒,沙箱休眠时站点加载仅4毫秒。

🏷️

标签

➡️

继续阅读