iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0

Part 5|第 23/30 篇
今日要做的事: 用第一天的冰箱照當起點,鎖定五天的時間、預算、設備和過敏,讓 DishFlow 每天只選一道;再跑一組「每天都以為冰箱還是第一天」的對照。
今天要解決的目的: 看連續記錄有沒有讓下一餐少買、少超支、少把快壞的東西放過期。不是一次把九道菜丟給模型認。

把九道菜的照片一次貼上去,模型是在考試「這是什麼菜」。

DishFlow 要做的是另一件事:今天冰箱裡有這些,時間和預算只有這些,今晚只煮一道。明天的冰箱,是今晚扣完、再過一天之後的冰箱。

https://ithelp.ithome.com.tw/upload/images/20261006/20121052GahxZJHdyY.jpg


今日任務卡

項目 內容
產出 鎖定的冰箱與五天條件、有記憶 5 天、沒記憶 5 天、兩邊的結算
Google 服務 Firebase Auth;Firestore 存 benchmark/replay_scenario_v1 和 replay_runs;Gemini Structured Output(gemini-3.5-flash)只負責從合格候選裡選一道
素材 冰箱 4 張:去殼蝦仁、花枝、雞蛋、青江菜、袖珍菇、花椰菜米。醬油、味醂、鵝油算常備。牛奶、優格、啤酒不算食材
候選 15 道。9 月煮過的菜只拿來當「有沒有照片」的註記,不拿來當標準答案
不做 九道菜一次送檢、重煮、用碼表、看完推薦再改五天條件
對照 規則、候選、Gemini 都一樣。唯一差別是規劃時看的冰箱

下面的數字來自網頁上這一次正式回放。


1. 問題:沒有昨天,今天的「不用買」是假的

直接問「冰箱有蝦仁、花枝、蛋、青菜,晚餐吃什麼」,模型可以每天都給出一道理直氣壯的答案。

問題是它不知道昨天已經把花枝用掉一尾、義大利麵買過了、青江菜只剩三天。沒記憶的規劃會一直對著第一天的冰箱說話。真的要煮的時候,冰箱已經不是那一格。

所以今天比的不是菜名猜不猜得中。比的是:

有記憶:每天看扣過、過完一天的冰箱
沒記憶:每天都拿第一天的冰箱來規劃
煮的時候:兩組都照真實冰箱扣

2. 設計:先鎖條件,再每天走同一條路

https://ithelp.ithome.com.tw/upload/images/20261006/201210526wC40uLiYN.png

2.1 第一天的冰箱只收照片看得到的

食材 數量 還能放 標記
去殼蝦仁 20 尾 60 天 冷凍
花枝 2 尾 60 天 冷凍
雞蛋 4 顆 12 天
青江菜 2 把 3 天 快過期
袖珍菇 1 把 3 天 快過期
花椰菜米 1 包 30 天 冷凍

數量和天數是看照片估的,鎖定之後就不能為了讓某一天好看再改。袖珍菇可以頂鴻喜菇或香菇。蝦不會自動換成花枝,因為過敏原不一樣。

常備品不扣量、不算錢:蒜、醬油、鹽、油、味醂、鵝油、米酒、辣椒片、水。

2.2 五天條件跑之前一起鎖

情境 時間 預算 設備 過敏
D1 週一晚餐,下班很累 30 分 低 全部 —
D2 週二朋友來吃 45 分 中 全部 不能有蝦
D3 週三電磁爐壞了 30 分 中 只有微波爐 —
D4 週四只有 15 分鐘 15 分 低 全部 —
D5 週五晚餐,想先清快壞的 60 分 中 全部 —

預算用點數,不用紙鈔。買一樣東西記一次該等級的點數:低 1、中 2、高 3。當天上限是低 2 點、中 4 點。0 點叫免買,1~2 點叫低,3~4 點叫中,5 點以上叫高。

買一次拿到的是一整包,用不完留到明天。雞腿肉買回來只放 2 天,蛤蜊只放 1 天。剩咖哩買不到,沒有先煮出歐姆蛋咖哩,咖哩烏龍就不能選。

2.3 Gemini 只做最後一步

硬規則先篩:設備、過敏、時間、食材買不買得到、預算。剩下的清單才送給 Gemini。

它必須用 Structured Output,從清單的 id 裡選一個,並寫一句理由、一句明天可以注意的事。選的順序寫在 prompt 裡:先用快過期的,再少買、少花錢,最後才是好不好吃。

週二沒出現蝦,不是模型突然很懂過敏。含 crustacean 的菜在進 Gemini 之前就被拿掉了。週三只有微波丼過得了「只有微波爐」這一關,所以那一天 Gemini 沒有真正的選擇。


3. 實作

3.0 骨架

day22/
├─ index.html          冰箱、五天條件、兩條時間軸、結算
├─ test.js             10 個測試,不打 Gemini
└─ src/
   ├─ scenario.js      第一天冰箱、採購表、五天條件
   ├─ recipes.json     15 道候選
   ├─ engine.js        規劃、篩選、扣庫存、過一天、回放
   ├─ choose.js        Gemini 從候選裡選一道
   ├─ main.js          鎖定、兩組回放、寫 Firestore
   └─ firebase.js

.env 沿用 Day 19。金鑰在前端,這頁只在 localhost 跑。

Firestore 寫在 users/{uid} 底下:

benchmark/replay_scenario_v1     冰箱、五天、採購表、15 道 id,附 hash
replay_runs/memory               有記憶的結算
replay_runs/no_memory            沒記憶的結算
replay_runs/{mode}/days/D1…D5   每一天的候選、選擇、實際購買、過期

內容和已鎖定的 hash 不同就拒絕寫入。要改冰箱或五天條件,得開新版本。

3.1 規劃和篩選

export function candidates(recipes, day, pantry) {
  const rejected = [];
  const ok = [];
  for (const r of recipes) {
    const why = [];
    if (!r.equipment.every((e) => day.equipment.includes(e))) why.push("設備");
    if (r.allergens.some((a) => day.avoid_allergens.includes(a))) why.push("過敏");
    if (r.minutes > day.time_cap) why.push("時間");
    const p = plan(r, pantry);
    if (!p.feasible) why.push("食材");
    else if (p.points > BUDGET_POINTS[day.budget]) why.push("預算");
    if (why.length) rejected.push({ id: r.id, why });
    else ok.push({ id: r.id, name_zh: r.name_zh, minutes: r.minutes, ...p });
  }
  return { ok, rejected };
}

以第一天的冰箱來說,週一過關 6 道,週二 7 道,週三只剩微波丼,週四只剩花椰菜米蛋炒飯、蔥花玉子燒、蝦仁滑蛋。後面幾天的候選數會跟著真實冰箱變,所以不能拿這組數字套到每一天。

3.2 沒記憶的那組,規劃和實煮看的不是同一個冰箱

const seen = memory ? real : fridge;
const { ok } = candidates(recipes, day, seen);
const pick = ok.find((c) => c.id === ai.result.pick);
const cooked = cook(recipe, real);

seen 用來產生候選和「要買什麼」。cook() 永遠扣真實冰箱。沒記憶的那組會出現一種錯:規劃時以為不用買,真的煮卻要買。這就是畫面上的「意外要買」。多買的點數如果超過當天預算,再標「超出預算」。

煮完之後天數減一。天數變成負的,記成浪費,移出冰箱。


4. 網頁上這一次

四步:登入、鎖定情境、回放有記憶、回放沒記憶。

https://ithelp.ithome.com.tw/upload/images/20261006/20121052ORxTxCln5a.png

4.1 每天選了什麼

有記憶 沒記憶
D1 週一晚餐 蒜辣透抽義大利麵,買義大利麵,低 蒜辣透抽義大利麵,買義大利麵,低
D2 週二朋友來吃 同一道,不用再買 同一道,但標了意外要買
D3 週三只剩微波爐 微波洋蔥雞肉蛋蓋飯,買雞腿肉、洋蔥、白飯,中 同一道
D4 只有 15 分鐘 蝦仁滑蛋;當晚袖珍菇過期 花椰菜米蛋炒飯,另外出現意外要買,袖珍菇也過期
D5 週五晚餐 又是微波丼;當晚雞腿肉過期 蛤蜊番茄蛋,花費高,超出預算,雞腿肉過期

週一兩邊一樣,是因為真實冰箱還是第一天,記憶還沒有差別。週二起才分開。

週二兩組都再選蒜辣透抽義大利麵。有記憶知道義大利麵昨天買過,所以不用再買。沒記憶還對著第一天的空櫥櫃規劃。連續兩天同一道,規則沒有擋。prompt 只說少買、用掉快過期,沒說不要連著吃一樣的。

週三沒有選擇餘地。設備篩選之後只剩微波丼。

週四有記憶選了冰箱裡就有的蝦仁滑蛋,沒有去動只剩一天的袖珍菇,菇當晚過期。沒記憶改選花椰菜米蛋炒飯,規劃和真實冰箱對不上,出現意外採購。

週五有記憶又選微波丼。D3 買的雞腿肉只放兩天,沒在期限內用完,D5 過期。沒記憶選了蛤蜊番茄蛋,蛤蜊是高單價,再加上番茄和高麗菜,超過「中」的 4 點,畫面上標超出預算。

4.2 五天結算

有記憶 沒記憶
5 天花費點數 7 12
意外要買的東西 0 2
超出預算的天數 0 1
用掉的快過期食材 2 1
有 9 月實煮證據的天數 2 3

有記憶比較省,也沒有意外採購、沒有超支。它多記住的是「昨天買過的還在、昨天用掉的不能再算一次」。

這不是零浪費。袖珍菇和雞腿肉兩邊都有過期。有記憶沒有因為「想把快壞的先用掉」就把 D5 拿去清冰箱,它又選了一道要買雞肉的微波丼。

「有 9 月實煮證據」沒記憶是 3、有記憶是 2。這個數字只表示推薦碰巧是我 9 月煮過的菜。沒記憶較高,不代表它比較會選晚餐。蒜辣透抽和蝦仁滑蛋 9 月沒煮過,所以有記憶的 D1、D2、D4 不算在這欄。

網頁截圖證明畫面上長這樣。Firestore 再留兩張,證明這次有寫進去。麵包屑上的 uid 已遮掉。

https://ithelp.ithome.com.tw/upload/images/20261006/20121052YiHpiq6Th5.png

benchmark/replay_scenario_v1 裡是跑之前鎖進去的採購表。義大利麵、梅花豬、馬鈴薯、白飯的等級和天數都在這份文件裡,不是事後補的。

https://ithelp.ithome.com.tw/upload/images/20261006/201210522DY4PV60Gb.png

replay_runs/memory 的 summary 對得上網頁:花費點數 7、意外採購 0、超支 0 天、煮完 5 天。scenario_hash 是 0c0b8d49338fd10c,寫入時間是 2026/10/6 11:37。右邊打開的是 D1,選的是蒜辣透抽義大利麵,實際買了義大利麵,1 點。過期清單裡有袖珍菇。D2 到 D5 在同一個 days 集合,沒有另外貼十張。


5. 驗證

https://ithelp.ithome.com.tw/upload/images/20261006/20121052qLnJZD1hKD.png

這 10 個測試不打 Gemini,守的是冰箱怎麼扣:

  • 夠就不用買,不夠才列採購
  • 同一樣食材被兩個材料搶,第二個要算缺
  • 袖珍菇可以頂鴻喜菇,蝦不會換成花枝
  • 朋友蝦過敏那天,含甲殼類的菜全部被擋
  • 只剩微波爐那天,只有微波丼過得了
  • 沒有剩咖哩,咖哩烏龍不能選;煮完歐姆蛋咖哩才行
  • 買的多出來留到明天
  • 過期的移出冰箱,記成浪費
  • 0 免買、1~2 低、3~4 中、5 以上高
  • 沒記憶的規劃看第一天,煮的時候看真實冰箱,所以會出現意外要買

6. 限制

  • 五天是依冰箱照編的劇本,不是連續住了五個晚上。
  • 數量和保存天數是看照片鎖定的估計。冷凍蝦寫 60 天、青菜寫 3 天,之後沒有再改。
  • 過敏、設備、時間、預算是規則先做的。Gemini 的工作只有「合格清單裡選一道」。
  • 同一組照片再跑一次,Gemini 可能選不同菜。這篇的 7 和 12 是網頁這一次。
  • 沒有碼表。菜譜上的分鐘是估計或回憶,只用來過時間關,不當成實測。

7. 今日結論

同一格冰箱回放五天,有記憶的花費是 7 點,沒記憶是 12 點;意外採購 0 對 2,超支 0 天對 1 天。差別從第二天開始,因為第一天兩邊看到的冰箱一樣。有記憶仍讓袖珍菇和雞腿肉過期,也連著兩天選了同一道透抽麵。

下一篇: 拿這五天裡的一筆,做成一張 Result Card。時間用這次的估計分鐘,不假裝有碼表。


附錄:一天寫進 Firestore 的樣子

day: D2
seen_pantry: real          有記憶;沒記憶這欄是 day1
outcome: COOKED
pick: garlic-chili-squid-pasta
planned.buy                規劃時以為要買的
actual.buy                 照真實冰箱真正買的
surprise_buy               actual 有、planned 沒有的
over_budget                actual 點數超過當天上限
wasted                     這天結束時過期的

上一篇
[Day 20] 模型說 15 分鐘,我到底從哪一秒開始算?Alpha 控制台先把計時協定鎖進 Firestore
系列文
DishFlow AI Agent:用 Google AI 打造 Eat-Cost Balance 的下一餐決策系統 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言