> 关键工具:Bolt.new(浏览器内全栈生成 + 一键部署)+ Gemini Vision API(多模态识别)
> 技术栈阶:低阶起步,30% 落在中阶
> 完整演示:构思 → 创建项目 → 提示词编写 → AI 制作 → 项目检验 → 落地上线
> 预计耗时:第一个能分享的版本约 1.5~2 小时(含申请 API Key、调试、部署)
这一篇怎么读
本篇把这个项目从一句想法到一个能发给朋友的网址,完整走一遍。每个阶段都给出你真正要做的动作、要敲的提示词、AI 大致产出的关键代码片段,以及怎么验收。跟着做,你会得到一个真实上线的小产品。
阶段一 · 构思:先把"要做什么"想清楚
动手前先回答四个问题,这一步只用纸笔或脑子,不碰任何工具。它决定了后面提示词的质量。
- 给谁用、解决什么痛点:给"懒得想晚饭做什么"的人。痛点是"冰箱里有零散食材,但不知道能做什么菜"。
- 核心流程一句话:拍照 → AI 认出食材 → 生成带卡路里的食谱。
- 最小可用范围(MVP):只做"拍照识别 + 出 3 个食谱",不做账号、不做收藏、不做历史记录。砍掉一切非核心功能,是新手最该学的纪律。
- 什么算成功:在手机上拍一张冰箱照片,30 秒内看到 3 个像样的食谱,且认错的食材能手动删掉。
构思阶段的产物:一句话规格
"一个移动端网页:拍照上传冰箱食材 → Gemini 识别 → 列出可删的食材标签 → 生成 3 张含卡路里的食谱卡片。纯前端,免登录。"
这句话就是你接下来所有提示词的"宪法"。
阶段二 · 创建项目:把工具和钥匙备好
这一步是上一版完全没讲、但"详解"必须有的——真正把项目脚手架立起来。分两件事:建项目、拿 API Key。
2.1 建项目(Bolt.new)
- 浏览器打开 bolt.new,用 GitHub 账号登录(方便后面同步代码和部署)。
- 在首页中央的输入框里,先不要写复杂需求,只写一句话起个底子,让它把脚手架搭好:
用 React + Vite + Tailwind 建一个移动端优先的空白单页应用,
项目名 fridge-chef,先给我一个干净的 Hello 页面能预览即可。
- Bolt 会在浏览器里直接生成项目、装依赖、起开发服务器,右侧实时预览。这一步你得到的是一个能跑的空壳——确认预览正常,再往下走。
为什么先要空壳
先让脚手架跑通,把"环境/依赖能不能起来"这类问题和"业务逻辑对不对"分开。环境一旦绿了,后面就只用关心功能。
2.2 拿 Gemini API Key(这是项目的"钥匙")
识别食材要调 Gemini Vision,需要一把 API Key:
- 打开 aistudio.google.com(Google AI Studio),登录。
- 找到 Get API Key → Create API Key,复制生成的密钥(形如
AIza...)。 - 回到 Bolt,不要把密钥硬写进代码。在项目里新建
.env,加一行:
VITE_GEMINI_API_KEY=你复制的密钥
第一条安全纪律
密钥进 .env,并确认 .env 在 .gitignore 里。绝不能把密钥写进源码或提交到 GitHub——一旦泄露,别人能拿你的额度疯狂调用、给你刷出账单。这条从项目第一天就要守。
到这里,"项目"和"钥匙"都备齐了,可以让 AI 正式开工。
阶段三 · 具体提示词编写:把宪法翻译成工单
很多人此处直接说"做一个识别冰箱食材的 App",结果得到四不像。正确做法是把阶段一的"一句话规格"展开成一份结构清晰、留好接口的工单——尤其要"先用假数据跑通界面",把接 API 的风险推后。
主提示词(贴进 Bolt 对话框)
在当前项目上实现"冰箱剩菜食谱",按下面规格来:
【界面】移动端优先,米白底、圆角卡片、温暖风格。
- 顶部一个大的"拍照/上传食材照片"按钮。
- 上传后显示"识别到的食材":用一排标签(chips)列出每种食材,
每个标签带一个可删除的小叉。
- 下方"为你推荐的食谱":3 张卡片,每张含 菜名 / 所需食材 /
预计卡路里 / 3~5 步做法。
- 底部一个"重新生成食谱"按钮。
【先用假数据】识别和生成先各写一个返回 mock 数据的占位函数:
recognizeIngredients(image) 和 generateRecipes(ingredients),
让我先看到完整界面和交互。真实 API 我下一步再接。
【交互】食材标签可删除;删除后点"重新生成食谱"刷新食谱区。
【代码结构】把这两个函数单独放在 src/api/ 下,方便我后面替换成真实接口。
用 React 函数组件 + hooks,状态放组件内即可。注意这份工单的三处用心:先 mock 跑界面、把 API 函数抽离、允许手动删标签——这三点正是为后面"接真实 API""AI 会认错"埋的伏笔。提示词的功力不在辞藻,在这些工程性的安排。
阶段四 · AI 制作:看 AI 产出了什么(关键片段)
Bolt 几十秒就生成了项目。这里只看最关键的几块,理解 AI 给了你什么、哪里需要你后续介入。
项目结构(AI 自动组织成了清晰的分层):
src/
api/
recognize.js # 识别食材(先 mock,后接 Gemini)
recipes.js # 生成食谱(先 mock)
components/
UploadButton.jsx
IngredientChips.jsx
RecipeCard.jsx
App.jsx
占位的识别函数(mock 版,先让界面跑起来):
// src/api/recognize.js —— 第一版:mock
export async function recognizeIngredients(imageFile) {
await new Promise(r => setTimeout(r, 600)); // 模拟网络延迟
return [
{ name: '西兰花', confidence: 0.93 },
{ name: '鸡蛋', confidence: 0.88 },
{ name: '豆腐', confidence: 0.71 },
];
}
食材标签组件(可删除的 chips,对应交互需求):
// src/components/IngredientChips.jsx
export default function IngredientChips({ items, onRemove }) {
return (
<div className="flex flex-wrap gap-2">
{items.map((it) => (
<span key={it.name}
className="px-3 py-1 rounded-full bg-emerald-50 border border-emerald-200 text-sm">
{it.name}
<button onClick={() => onRemove(it.name)} className="ml-2 text-gray-400">×</button>
</span>
))}
</div>
);
}
此刻在右侧预览里点一遍:上传(假的)、删标签、重新生成——交互闭环通了,但还没接真识别。这就是 70% 里"最丝滑"的部分,AI 几乎免费交付。
阶段五 · 项目检验(上):接真实 API 并逐个排雷
现在把 mock 换成真 Gemini,这一步会接连撞上三个真实的坑——也正是这个案例的 30% 工程所在。
5.1 接入 Gemini,强约束输出格式
接入提示词
把 src/api/recognize.js 换成真实实现,调用 Gemini Vision:
- 读 import.meta.env.VITE_GEMINI_API_KEY。
- 把图片转 base64 传给 Gemini。
- 给模型的 prompt 要求它【只】返回 JSON 数组,禁止 markdown 和解释:
[{ "name": "中文食材名", "confidence": 0~1 }]
- 把给模型的 prompt 抽成单独常量 RECOGNIZE_PROMPT 方便我调。AI 产出的真实版关键片段:
// src/api/recognize.js —— 第二版:真实调用(关键片段)
const RECOGNIZE_PROMPT = `你是食材识别助手。识别图片里所有可食用食材。
严格只输出 JSON 数组,禁止 markdown、解释或代码块标记。
每个元素:{"name": 中文食材名, "confidence": 0到1}。只列你确实看到的。`;
export async function recognizeIngredients(imageFile) {
const base64 = await toBase64(imageFile);
const res = await fetch(GEMINI_URL + `?key=${import.meta.env.VITE_GEMINI_API_KEY}`, {
method: 'POST',
body: JSON.stringify({ contents: [{ parts: [
{ text: RECOGNIZE_PROMPT },
{ inline_data: { mime_type: imageFile.type, data: base64 } },
]}]}),
});
const data = await res.json();
return parseIngredients(data); // 见下一步:要做清洗和兜底
}
5.2 坑①:模型不老实——返回被 markdown 包裹
第一次真机一跑就报错:JSON.parse 失败。打开控制台看到 Gemini 把 JSON 包进了 ``` `json ``` 代码块。不要回头跟 AI 纠缠"你又错了",直接给现象和修法:
修 bug 提示词
Gemini 有时把 JSON 包在 ```json ``` 里导致 parse 失败。
写一个 parseIngredients:先用正则截取第一个 [ 到最后一个 ] 之间的内容,
再 JSON.parse;整体 try/catch,失败返回 [] 并让界面提示"识别失败,请重试"。function parseIngredients(data) {
try {
const text = data.candidates[0].content.parts[0].text;
const json = text.slice(text.indexOf('['), text.lastIndexOf(']') + 1);
return JSON.parse(json);
} catch (e) {
return []; // 上层据此提示"识别失败,请重试"
}
}
5.3 坑②:概率结果——把"长颈鹿 11%"挡在门外
测试时它偶尔识别出"可能是橙子(0.18)"。置信度过滤是必须由人定阈值的取舍:
过滤提示词
显示前过滤掉 confidence < 0.5 的食材,阈值设为常量 CONFIDENCE_THRESHOLD。
过滤后为空时不要白屏,提示"没认出明确食材,换张更清晰、光线好的照片试试"。5.4 坑③:跨端拍照——上线前最后一道坎
电脑上正常,发给朋友手机点"拍照"没反应。移动端唤起相机要正确的 input 配置 + HTTPS:
兼容提示词
上传按钮在手机上要能直接唤起相机,也要能从相册选:
用 <input type="file" accept="image/*" capture="environment">。
在 iOS Safari 和安卓 Chrome 都要正常。阶段五 · 项目检验(下):按"边界清单"验收
验收不是看"它能跑",而是专测那 30% 的边界。逐项打勾:
| 检验项 | 操作 | 期望 |
|---|---|---|
| 空冰箱 | 拍一张没食材的照片 | 提示"没认出明确食材",不白屏 |
| 糊照片 | 拍一张很模糊的照片 | 低置信度被过滤,提示换清晰图 |
| 识别失败 | 断网后上传 | 提示"识别失败,请重试",应用不崩 |
| 跨端 | iPhone + 安卓各测拍照 | 都能唤起相机 |
| 删除联动 | 删一个标签后重新生成 | 食谱据剩余食材刷新 |
四到五项全过,才算"能用",而不只是"能演示"。
阶段六 · 落地:部署上线,拿到能分享的网址
做出来不上线,等于没做。Bolt 内置部署,几步就能拿到公网地址。
- 在 Bolt 项目右上角点 Deploy(默认走 Netlify 集成),授权后它自动构建。
- 关键:部署环境也要配密钥。在部署设置(Netlify 站点的 Environment variables)里加上
VITE_GEMINI_API_KEY,否则线上识别会失败——本地.env不会被打包上去。 - 构建完成后得到一个
https://fridge-chef-xxx.netlify.app网址,手机打开即可用。 - (可选)在 Netlify 绑定自定义域名,让它更像个正经产品。
落地阶段最常见的翻车
"本地好好的,线上识别全失败"——九成是忘了在部署平台配环境变量。本地 .env 只在你电脑上生效,云端构建看不到它。部署后第一件事就是去线上环境变量里补上密钥。
落地后的小事,但很重要
- 限额保护:去 Google AI Studio 给这把 Key 设个用量上限,防止被刷爆。
- 冷启动测试:用一台没缓存的设备、点开网址完整走一遍,确认陌生人也能顺利用。
- 收集反馈:把网址发给三五个朋友,看他们卡在哪——真实用户永远会用出你没测到的姿势。
30% 复盘:人类到底守住了什么
AI 丝滑交付了界面、mock 交互、happy-path 识别(约 70%)。人类亲手补上的 30%,是四件 AI 不会主动替你做的事:
| 30% 工程点 | 人类做了什么 | 不做会怎样 |
|---|---|---|
| 输出不老实 | 清洗 markdown 包裹 + try/catch 兜底 | 偶发 JSON 报错、白屏 |
| 概率结果 | 置信度阈值过滤 + 空结果提示 | 显示"长颈鹿 11%",沦为笑话 |
| 跨端兼容 | capture 配置 + HTTPS + 相册回退 | 一半用户手机点了没反应 |
| 落地配置 | 部署平台补环境变量、设限额 | 线上识别全挂、或被刷爆额度 |
一句话:AI 让你 10 分钟有了 demo,但这几件事决定了它是玩具,还是真能上线、敢发给朋友用的产品。
可复用心法与提示词模板
带得走的四条
- 先 mock 后接真:让 AI 先用假数据交付能点通的空壳,再替换真实 API。
- 强约束输出格式:要程序解析 AI 输出,就在提示词里写死"只返回 JSON、禁止 markdown",代码侧再清洗兜底。
- 为"AI 会错"留后路:置信度过滤 + 手动删除 + 友好失败提示。
- 落地即配密钥:部署后第一件事是去云端环境变量补上 Key,并设用量上限。
通用"接多模态 API"提示词模板:
把 <占位函数> 换成真实实现,调用 <模型>。要求:
1. 输入转 base64;密钥读环境变量。
2. 提示词强制只返回 JSON(写清字段与类型),禁止 markdown 与解释。
3. 解析前清洗代码块包裹,try/catch 兜底,失败返回空 + 界面友好提示。
4. 过滤低置信度结果,阈值设为常量;为空时给引导提示。
5. 把模型 prompt 抽成单独常量,便于调参。