如何用 ChatGPT 5.5 把一个手绘 Demo,一路补成了能用的 SaaS
从「输入一句话生成手绘图」到部署上线,踩遍额度、SDK、产品形态的坑,再把假登录、假账单补成真能跑的东西——一个小项目从 Demo 到能用的 SaaS 的完整记录。

从「输入一句话生成手绘图」到部署上线,中间踩了额度、SDK、产品形态一堆坑,最后把假登录、假账单补成真能跑的东西。记录一个小项目从 0 到「像样」的完整过程。
最近做了一个小项目:HandDraw AI。
一开始它只是个很直接的工具:输入一句描述,选一种手绘风格,生成图片。后来部署、域名、Key、模型额度、产品形态这些问题一个个冒出来,它慢慢从一个生成器变成了 SaaS 雏形。再后来我打开代码才发现,那个 SaaS 只是个空壳——登录、账单、历史全是假的,又花了一轮把它补成真能跑的东西。
这篇把整个过程串起来讲。
缘起:先把核心能力跑通
最初的目标很简单:做一个手绘风图片生成器。技术栈选得很轻:
Next.js App Router
TypeScript
Vercel
Gemini Image API
前端负责输入画面内容、选风格、传参考图;后端用 Next.js API Route 调图像模型。项目结构大致是:
src/app/page.tsx 主页面
src/app/api/generate/route.ts 生图接口
src/lib/styles.ts 风格配置
src/lib/prompt.ts Prompt 拼装
public/examples/ 风格示例图
它内置了 13 种手绘风格——儿童涂色页、蜡笔童涂、xkcd 火柴人、水墨写意、复古像素……每种风格背后都是一段打磨过的提示词模板。
最初版本很像一个「开发者工具」:打开就是编辑器,左边填参数,右边看结果。功能能跑,但产品感很弱。
API Key 与环境变量
AI 应用第一个绕不开的问题就是 Key 怎么放。本地用 .env:
GEMINI_API_KEY=xxx
GEMINI_IMAGE_MODEL=gemini-3.1-flash-image
Key 只在服务端 API Route 读取,前端不暴露。同时 .gitignore 一定要忽略:
.env
.env*.local
这点很重要——AI Key 一旦提交到 GitHub,基本就等于公开了。
模型名能用,不代表有额度
开发中反复测了几个模型:
gemini-3-pro-image-preview
gemini-3.1-flash-image
gemini-3.1-flash-lite-image
一开始遇到最多的是 429:
free_tier_requests limit: 0
free_tier_input_token_count limit: 0
这不是代码错,也不是 Key 格式错。是当前 Google 项目对这个模型没有免费额度。换了新 Key 再测就 OK 了:
OK image: data:image/jpeg;base64,...
model: gemini-3.1-flash-image
调试这类应用,最好先把错误分清楚:
500:服务端配置可能有问题
401/403:Key 或权限问题
429:额度或频率限制
200:调用成功
SDK 版本变更
还遇到一个典型问题:Gemini SDK 旧版本的 Interactions API schema 不再支持。
The legacy Interactions API schema is no longer supported.
Please upgrade your @google/genai JS/TS SDK to version >= 2.0.0
解决方式是升级 SDK,并把图片响应解析从旧的 interaction.outputs 改成新结构的 interaction.steps:
npm install @google/genai@latest
这也是 AI 应用开发的现实:模型和 SDK 变化很快,写完不能不管。依赖升级、接口变更、模型下线,都要预留维护空间。
部署到 Vercel
标准 Next.js,部署很顺:
vercel --prod
关键是配好环境变量(GEMINI_API_KEY、GEMINI_IMAGE_MODEL),Production 和 Development 都要配。上线后还处理了几个细节:
这些看起来不像「写代码」,但都是产品上线的一部分。
从「工具」到「SaaS 外壳」
最初页面的问题是:用户一进来就直面编辑器。这适合我自己调试,但普通用户根本看不懂在填什么。于是做了一次重构,把形态改成 SaaS:
首页:产品介绍
登录:账号入口
价格:Free / Pro 套餐
工作台:项目、额度、生成器
用户路径变成:打开首页 → 了解产品 → 登录 → 选套餐 → 进入工作台 → 生成图片。

很多 AI Demo 的能力其实够用,卡住它们的是没有产品外壳——用户不知道它是什么、适合谁、怎么收费、为什么要注册。
把「空壳」补成真能用的产品
SaaS 外壳搭起来后,打开代码会发现——流程几乎全是演示用的空壳:
- 登录是假的,账号密码是只读占位符;
- 账单是假的,选套餐不真开通、刷新就没;
- 项目列表是硬编码的常量;
- 生成完就丢,刷新即消失,没有任何历史;
- 移动端菜单按钮是个死键。
全是摆设。于是有了这一章:整体优化页面 + 把功能真正补活。

原来一个文件塞下所有视图、状态、逻辑。这次拆成职责清晰的结构:
src/lib/data.ts 套餐/示例数据、类型、工具函数
src/lib/history.ts 本地持久化 + 生成历史(新增)
src/components/* Topbar / HomeView / AuthView / BillingView
StudioSidebar / StudioView / Footer
src/app/page.tsx 只负责状态编排
page.tsx 从「什么都干」变成「只做编排」,可维护性直接上一个台阶。

- 状态持久化:用
localStorage存登录态和套餐,刷新不掉线。关键是避开 SSR 的 hydration 报错——初始用默认值,挂载后在useEffect里再读本地存储。 - 真实的生成历史:每次生成自动存一条(缩略图、风格、时间、prompt),侧边栏支持点击恢复、删除、下载;首页 dashboard 联动展示真实最近项目。
- 能用的配额系统:按套餐算额度(Starter 20 / Pro 800),进度条真实反映用量,用完自动禁用并提示。
- 修复订阅流程:未登录选套餐先引导登录、再自动激活,「当前套餐」正确高亮。
- 补齐交互:带校验的登录框、真正能展开的移动端导航、重新生成、新建、toast 提示、加载态与空状态。
- 页面优化:新增风格画廊(点任意风格直达工作台并预选)、页脚,收敛整体视觉。
验证与交付
功能写完不等于做完,三道关卡逐一过:
npm run lint → 0 错误 0 警告
npm run build → 类型检查 + 静态生成通过
dev server → 首页 200、SSR 内容正确、无 hydration 报错
工程化:一份 AGENTS.md
项目还加了 AGENTS.md 作为贡献者指南,记录项目结构、开发命令、代码风格、提交规范、环境变量注意事项。提交信息保持简短祈使式:
Refactor app into SaaS workspace
Update Gemini SDK image response handling
Add persistence, history, and UI polish to workspace
这些小规范,哪怕一个人开发也有用——项目一旦持续迭代,没有基本约定很快就会乱。
从 Demo 到产品差的是什么
这个项目不大,但完整走了一遍 AI 产品的关键环节:核心能力验证 → Prompt 与风格配置 → Key 安全 → 额度调试 → SDK 适配 → Vercel 部署 → 域名与访问控制 → SaaS 重构 → 账号与付费路径预留 → 持久化与历史。
几个具体的感受:
模型调用真的只是第一步。真正要上线,后面还压着一长串:谁来用、怎么进入、怎么付费、怎么限额、怎么隐藏底层复杂度、怎么稳定部署、怎么处理错误。
而「看起来能用」和「真能用」之间,差的往往不是新功能,是状态管理。登录会不会掉、刷新会不会丢、额度用完怎么办——这些边界情况才是分水岭。
还有一点:交付要留痕、能验证。我在收尾时说清了哪些验证过、哪些没跑(依赖真实 Key 的 Gemini 生成没实调,避免消耗额度)。诚实的交付比漂亮的结论有用。
HandDraw AI 现在还是早期版本,但基础搭起来了。生成历史已经有了(本地版),下一步优先补两件事:真实账号系统和真实支付订阅,再把历史从 localStorage 换成后端数据库。