此页目录
BUILD LOG 02 · WIND

我是怎样一步步和 AI 做出一个台风守护站的

从一句模糊的想法,到视觉方案、真实天气、守护清单和部署上线。
这一期重点讲清楚:每一步我怎样问 AI,又怎样把结果改到真正能用。

CodexImage GenNext.jsOpen-Meteo第 02 期
油画插图:风雨中的创意守护世界

如果只对 AI 说一句「帮我做一个台风网站」,它很快就能生成一个页面。

但一个页面能显示出来,和一个网站真正可用,中间还有很长一段距离。产品要解决什么问题、需要哪些页面、哪些内容用图片生成、哪些部分必须写成代码、天气数据从哪里来、接口失败怎么办、最后怎样部署,这些都需要一轮一轮地和 AI 讲清楚。

「风来有信」就是这样做出来的。

它是一个面向移动端的台风守护网站,可以切换浙江、福建和台湾的 17 个城市,查看当前风力、阵风、降雨、气压和未来 6 小时预报,也包含防台清单、台风科普和守护卡片。

风来有信首页与实时风雨

这篇文章不只展示最后的代码。我会按照真实的制作顺序,说明每一轮为什么要找 AI、我怎样描述需求、AI 完成了什么,以及拿到结果后应该检查什么。

先记住一个原则:一轮只解决一个问题

我没有让 AI 一次完成产品设计、视觉、代码、数据和部署,而是把工作拆成了几轮:

讨论想法
确定产品边界
生成视觉方案
搭建前端页面
逐项修改细节
接入真实天气
构建并部署

每一轮都给 AI 一个明确目标。上一轮的结果确认后,再进入下一轮。

这样做有两个好处:出了问题时容易定位,修改时也不会牵动整个项目。学习 AI Coding 时,这比寻找一条所谓的「万能提示词」更重要。

从查看风雨到分享守护的完整产品路径

第一步:先和 AI 讨论做什么,不急着写代码

最开始,我只有一个很模糊的想法:杭州临近台风,能不能围绕台风做一个有用的 Web 应用?

我当时先这样问 AI:

现在台风将近,我在浙江杭州。我能不能围绕台风做一个 Web Coding 的东西?最好是正能量、有一定价值的。我的想法是做一个个人台风监控,或者其他类似的东西。这个应该怎样做?

这一步我没有要求 AI 写页面,而是让它先帮我展开产品方向。讨论后,我保留了几个比较有价值的模块:

  • 实时风雨感知
  • 未来数小时的变化趋势
  • 防台安全准备清单
  • 一分钟台风科普
  • 可以分享给家人的守护卡片

随后我又补充了一条限制:

我主要想做得生动有趣一些,同时围绕台风这个主题,起到积极正能量的作用,千万不要消费灾情。

这句话很重要。它直接决定了后面的文案、配色和功能表达:网站不能用灾难片式的画面制造焦虑,也不能暗示「完成任务就绝对安全」。页面应该帮助用户看懂信息、做好准备,并提醒他们以当地气象部门的官方预警为准。

这一轮可以怎样复用

如果你也只有一个模糊想法,可以先用下面的结构和 AI 讨论:

我想围绕【主题】做一个 Web 应用。
目标用户是:【谁会使用】
我希望它解决:【具体问题】
整体感觉是:【风格和情绪】
明确不要出现:【风险和边界】
先不要写代码,请给出 3 个可在一个周末完成的方向,
并分别说明核心功能、实现难度和最小可用版本。

先讨论方向,再决定做什么。不要在产品边界还没确定时就让 AI 开始生成代码。

第二步:把想法缩成一个周末能完成的版本

方向确定后,我继续追问实时数据应该从哪里获取:

实时风雨感知需要去哪里获取?是调用 API 吗?

这时需要把「想做的功能」和「这周末能完成的功能」分开。最终的第一版被控制在五个页面:

  1. 首页:选择地区,查看当前风雨和未来 6 小时。
  2. 台风详情:先完成路径和强度信息的界面结构。
  3. 守护任务:提供可以逐项勾选的防台清单。
  4. 台风科普:解释台风眼、螺旋雨带和预报圈。
  5. 分享守护:生成一张可以保存的守护卡片。

这一轮还有一个重要决定:先用演示数据完成界面,等页面稳定后再接真实 API。

如果一开始同时处理视觉、交互、第三方接口和异常状态,问题会混在一起。先用固定数据把页面做通,可以更快判断信息结构是否合理。

风来有信完整首页

第三步:让 AI 先画方案,不要直接猜页面

产品范围明确后,我开始处理视觉。

我已经有自己的卡通 IP「蔚蓝小狐」,所以没有让 AI 随机设计新角色,而是把小狐的参考图和产品要求一起交给 imagegen,并要求一次生成 5 种方案。

当时的需求大致是:

为「风来有信 · 杭州台风守护站」设计移动端首页长图,
一次生成 5 种不同风格供我选择。
视觉使用深空蓝、星云青和生命绿,背景包含杭州夜景、
西湖和台风云系,但不要使用灾难片式表达。
保持参考图中蔚蓝小狐的身份一致。
小狐穿蓝色防风雨衣,提着发出青绿色光芒的守护灯。
页面包含当前风雨、未来 6 小时、防台清单、
一分钟科普和分享守护卡片入口。
界面保持简约、生动、有趣,适配移动端长页面。

为什么要一次看 5 个方向?因为在没有参考图时,「高级」「有温度」「科技感」这些词很难形成统一理解。先让 AI 给出不同画面,再从中选择,比不断用形容词修改更有效。

我选定第 1 张之后,又继续说:

选定图片 1 的风格,继续生成后续所需的移动端界面。不要太复杂,尽量简约、生动、有趣,页面也不需要过多。

从这一步开始,第 1 张图就成了整个项目的视觉参考。后续生成任务页、科普页和分享页时,都要求继续沿用同一套角色、配色和画面语言。

第四步:明确哪些交给 imagegen,哪些必须用代码

设计图不能直接当成网站。天气数值、按钮、趋势图和任务状态会变化,如果把它们全部烘焙进一张图片,页面就无法交互。

因此,我给 AI 的下一轮要求非常明确:

有一些素材无法直接通过代码编写,比如蔚蓝小狐、插画、贴图和台风效果,需要继续使用 imagegen 生成。其他能够使用代码编写的部分,都使用代码实现。基于 Next.js 官方脚手架完成前端界面。

最后的分工是:

imagegen 负责代码负责
蔚蓝小狐角色页面布局和响应式适配
杭州夜景和台风云系天气数值和趋势图
任务页、科普页场景插画地区切换和页面导航
分享卡片背景清单勾选和本地保存

插画素材与代码交互组合成完整应用

这套分工也适用于其他 AI Coding 项目:稳定的氛围和角色可以生成图片,所有需要更新、点击、输入和适配的内容都应该交给代码。

第五步:让 AI 搭好项目骨架

视觉资产准备好后,我才让 AI 正式创建项目。

项目使用 Next.js App Router、TypeScript、Lucide React 和 Zustand。AI 先创建官方脚手架,再按照页面拆分路由和组件。

Terminal window
pnpm create next-app fenglai-youxin
cd fenglai-youxin
pnpm install
pnpm dev

这一轮的任务可以写成:

请基于当前确认的移动端设计图创建 Next.js 项目。
要求:
1. 使用 App Router 和 TypeScript;
2. 先实现首页、台风详情、守护任务、科普、分享五个页面;
3. 图片只用于角色和场景,文字、卡片、按钮和数据全部用代码实现;
4. 第一版先使用演示数据;
5. 把可复用的标题、卡片、趋势图和导航拆成组件;
6. 完成后启动本地服务,并告诉我访问地址。

AI 完成后的项目结构大致如下:

src/
├── app/
│ ├── page.tsx
│ ├── storm/page.tsx
│ ├── tasks/page.tsx
│ ├── science/page.tsx
│ ├── share/page.tsx
│ └── api/
├── components/
├── lib/
│ ├── locations.ts
│ └── weather/
└── store/guard-tasks.ts

这里不需要自己逐行告诉 AI 应该写什么代码,但要检查它是否遵守了页面边界:有没有把所有内容堆在一个文件里,动态数据是否仍然写死在图片中,移动端是否可以正常滚动和点击。

第六步:不要说「再优化一下」,要指出具体差异

第一版页面出来后,真正花时间的是视觉修正。

我没有只说「不够好看」,而是直接在页面上标记元素,逐项告诉 AI 哪里不对。例如:

「风来有信」标题改成手写字体。

顶部图片必须完整显示,不要裁掉蔚蓝小狐,也不要在下方留下大块空白。

「此刻风雨」和「未来 6 小时」合并成一张大卡片。

「一分钟看懂台风」使用左右布局,左边是大图标,右边是标题和说明。

守护卡片按照参考图的横向比例排版,背景图必须完整呈现。

这种反馈可以归纳成一个简单格式:

位置:页面中的哪个区域
问题:现在具体哪里不对
目标:希望改成什么样
参考:截图、尺寸或已有设计
边界:哪些部分不要改

例如,不要只写「优化顶部图片」,而要写:

位置:首页首屏背景图。
问题:当前使用 cover 导致角色被裁切,底部还有较多空白。
目标:按 16:9 完整显示图片,并让图片底部自然过渡到预警卡片。
边界:不要修改下方天气卡片的结构和数据。

AI 在收到这种描述后,不需要重新猜测设计意图,修改范围也更稳定。

台风详情与路径示意

一分钟看懂台风

第七步:页面稳定后,再让 AI 调研真实天气 API

静态页面确认后,我才提出数据接入要求:

请深度搜索有没有免费的 API,接入真实的台风和天气数据,让用户看到此时风雨以及未来 6 小时预报。前端界面不要再改,只处理真实数据。如果需要 Token,我可以后续申请。

这段话包含了三个关键约束:

  1. 先调研数据源,不要直接随便接一个接口。
  2. 保持已经确认的前端界面不变。
  3. 需要凭据的服务可以保留配置入口,不要把 Key 写进浏览器。

AI 对比了 Open-Meteo、和风天气、台湾中央气象署 CWA 和香港天文台的数据能力。最后采用两级方案:

数据源在项目中的用途是否需要凭据
Open-Meteo风速、阵风、降雨、气压、未来 6 小时
和风天气中国城市近实时天气和官方预警增强
台湾中央气象署 CWA台湾官方台风警报和路径尚未接入,需要 Key

这里还要检查 AI 有没有混淆「天气预报」和「官方预警」。Open-Meteo 提供的是数值天气模式数据,不等同于当地气象站的官方观测,也不能替代气象部门发布的预警。和风天气的台风路径也不属于免费订阅范围。

因此,台风详情页当前仍然明确标注为演示数据,没有为了让页面显得完整而伪装成实时路径。

参考文档:

天气数据的默认来源、可选增强、自动回退与缓存

第八步:让 AI 把第三方数据包在自己的接口后面

数据源确定后,我没有让浏览器直接请求第三方服务,而是让 AI 在 Next.js 中增加两个服务端接口:

GET /api/locations
GET /api/weather?location=zhejiang-hangzhou

这一轮可以这样描述:

请在不改变现有前端布局的前提下接入天气数据。
要求:
1. 浏览器只请求项目自己的 /api/weather;
2. Open-Meteo 作为无 Key 的默认数据源;
3. 配置和风天气 Host 与 Key 后自动增强数据;
4. 和风天气失败时自动回退 Open-Meteo;
5. 第三方请求设置超时,天气结果在服务端缓存;
6. 响应必须返回数据来源和观测时间;
7. API Key 只能保存在服务端环境变量中。

实际的回退逻辑很短:

export async function getWeather(location: WeatherLocation) {
const openMeteo = await getOpenMeteoWeather(location);
const qweatherConfig = getQWeatherConfig();
if (!qweatherConfig) return openMeteo;
try {
return await getQWeatherWeather(location, openMeteo, qweatherConfig);
} catch {
return {
...openMeteo,
notice: "和风天气暂时不可用,已自动切换至 Open-Meteo。",
};
}
}

当前实现为第三方请求设置了 8 秒超时,天气接口使用 10 分钟服务端缓存。页面同时显示 sourceobservedAt,让用户知道数据来自哪里、是什么时间更新的。

启用和风天气时,只需要在服务端配置:

QWEATHER_API_HOST=你的专属Host.qweatherapi.com
QWEATHER_API_KEY=你的API_KEY

第九步:增加地区切换,但不开放任意经纬度

真实天气接通后,我又增加了地区切换:

右上角地区切换需要支持台风可能影响的省份,例如台湾、浙江和福建,并且这些省份中的部分城市可以切换。

AI 最终整理了 17 个城市,每个城市在服务端保存固定的 WGS84 坐标和时区。接口只接受白名单中的地区 ID,不接受用户传入任意经纬度。

{
id: "zhejiang-hangzhou",
province: "浙江",
city: "杭州",
latitude: 30.2741,
longitude: 120.1551,
timezone: "Asia/Shanghai"
}

这样做可以限制第三方接口的调用范围,也方便统一缓存。用户上一次选择的城市保存在 localStorage 中,下次打开页面时会自动恢复。

浙江福建台湾城市通过固定地区白名单切换

切换到台湾台北后的实时风雨

验收这一轮时,不能只看下拉框是否出现。还要确认切换城市后,标题、当前天气、未来 6 小时、数据来源和更新时间是否一起变化,并检查刷新页面后是否仍然保留上一次选择。

第十步:把防台清单做成真正可使用的交互

守护任务不是一张静态插图。用户需要勾选任务、看到进度,并在刷新页面后继续保留结果。

给 AI 的约束可以整理为:

请把防台清单实现为真实交互。
要求:
1. 一共 8 项任务,按居家、物资、关怀分组;
2. 用户可以逐项勾选和取消;
3. 页面实时计算完成数量;
4. 不做账号系统,进度只保存在本地浏览器;
5. 服务端渲染时不能直接访问 localStorage。

AI 使用 Zustand 管理任务,并通过持久化中间件把状态写入 localStorage。项目不要求注册,也不会上传用户的姓名、住址和实时定位。

把关窗充电备药和问候装进防台守护箱

可以逐项勾选的守护任务

这里的验收方法很简单:勾选几项任务,刷新页面,再确认任务状态和完成数量是否还在。只看代码没有报错,并不能证明本地持久化已经生效。

第十一步:生成守护卡片,同时守住隐私边界

分享页会读取当前城市和任务进度,生成一张 1080 × 1350 的守护卡片,内容包括城市、完成数量、报平安文案和应用二维码。

这一部分经历了多次视觉修正。我给 AI 的反馈是:

守护卡片的排版和布局需要按照参考图制作。如果背景图片比例不一致,就按原图比例重新调整,不能强行裁剪。

实现时,页面预览和最终导出的 Canvas 分别设置布局,避免横版背景直接塞进竖版卡片后出现大面积裁切。二维码使用 PNG 素材,减少浏览器导出时的兼容问题。

在保护个人信息的前提下分享守护卡片

带二维码的分享守护卡片

分享功能只写入城市和任务进度,不收集精确定位。所谓「报平安」应该是向家人传递准备情况,而不是要求用户提交更多个人信息。

第十二步:让 AI 完成构建、检查和部署

功能完成后,我最后给 AI 的指令很直接:

帮我打包并部署到 EdgeOne。

但在部署前,AI 需要先执行基础检查:

Terminal window
pnpm exec tsc --noEmit
pnpm lint
pnpm build

移动端页面按 430 × 932 的视口检查,重点不是看一张首页截图,而是逐项确认:

  • 图片是否被错误裁切
  • 标题和按钮是否溢出
  • 长页面能否正常滚动
  • 地区切换后数据是否更新
  • 刷新后任务进度是否保留
  • 守护卡片是否可以正常生成
  • 第三方接口失败时是否出现明确提示

部署命令为:

Terminal window
edgeone whoami
edgeone pages deploy -n fenglai-youxin -e production -a global

这个项目包含 Next.js Route Handler,因此部署平台不仅要托管静态图片,还要支持服务端天气接口。

将视觉素材 Next.js 和天气 API 组合并部署到 EdgeOne

回头看,真正需要学习的是怎样推进每一轮对话

整个网站的代码主要由 AI 完成,但产品并不是靠一条提示词自动出现的。

我在每一轮做的事情其实很固定:

告诉 AI 当前目标
补充背景和明确边界
让 AI 只处理这一轮任务
查看真实页面或真实数据
指出具体差异并继续修改

遇到视觉问题,就给截图、比例和目标布局;遇到数据问题,就要求 AI 查官方文档、说明免费额度和数据性质;接入后端时,明确告诉它不要改已经确认的前端;部署前,则让它先完成构建和必要检查。

这套方法并不只适用于台风网站。换成个人工具、数据看板或学习应用,推进方式仍然一样:先把问题说清楚,再让 AI 完成一个可以检查的小步骤。

当前项目的真实边界

已经完成的部分:

  • 浙江、福建、台湾 17 个城市切换
  • 当前风力、阵风、降雨、气压和未来 6 小时预报
  • Open-Meteo 默认数据与和风天气可选增强
  • 数据来源、观测时间、超时、缓存和自动回退
  • 防台清单、本地进度保存、科普页面
  • 守护卡片、二维码和 PNG 图片导出
  • Next.js 生产构建与 EdgeOne 部署

尚未完成的部分:

  • 中国沿海官方台风路径
  • 台湾中央气象署官方警报
  • 和风天气正式凭据配置
  • 自定义公开域名

台风详情页中的路径和中心数据仍然是演示内容。首页实时天气和未来 6 小时已经接入 Open-Meteo,但它不能替代官方预警。遇到实际台风天气,仍然要以当地气象部门和应急管理部门发布的信息为准。

「风来有信」规模不大,但它完整经历了想法讨论、需求收敛、视觉生成、前端开发、真实数据接入、交互修改和部署上线。对刚开始学习 AI Coding 的人来说,把这条过程走通,比单独记住某一段代码更有价值。

✦ Lead AI · Build everything

合集目录

  1. 第 01 期 · 我让 AI 几分钟给自己做了张海报
  2. 第 02 期 · 我用 AI 做了一个台风守护站
  3. 第 04 期 · 我用 AI 把自己孵成了电子宠物
  4. 第 05 期 · 我的 Mac 又快满了,这次我让 Codex 帮我清理