Part 5|第 25/30 篇
今日要做的事: 把 16 題 Golden 和評分器先鎖起來,讓 A/B1/B2/C 各答一次。
今天要解決的目的: 同一句話、同一個模型,多看到的冰箱和限制,會不會改變有沒有踩線。
朋友今晚來吃飯。這句話本身沒有說他對蝦過敏。
過敏寫在個人資料裡。今天要看的是:只聽到這句話的人、掃過冰箱的人、拿到整份 JSON 的人,和先把不合法的菜拿掉的 DishFlow,各會交出什麼。

| 項目 | 內容 |
|---|---|
| 產出 | 16 題 × 4 法,共 64 列。解析全部成功 |
| 模型 | gemini-3.5-flash,溫度 1。實際回傳的模型名也是這個 |
| 鎖定 | golden-16-v1、scorer-1、問法 prompt-1、day24-rule-1。題庫 hash b93e46239d5aa652 |
| 順序 | 固定 A → B1 → B2 → C,seed 記成 fixed-A-B1-B2-C |
| Google 服務 | Gemini Structured Output。網頁登入後,彙總寫入 eval_runs/golden_v1 |
| 菜單 | 15 道,四法都看得到菜名、分鐘、設備、過敏標記、食材 id |
下面的分數來自這一次 64 呼叫,用的是開跑前鎖好的題庫和 scorer-1。

| 方法 | 聽得到 | 還看得到 |
|---|---|---|
| A | 那一句話 | 15 道菜單 |
| B1 | 同一句 | 菜單,加上十秒內看到的食材名字。沒有數量和天數 |
| B2 | 同一句 | 菜單,加上當天冰箱 JSON:數量、單位、還能放幾天 |
| C | 同一句 | 同一份 JSON,再加上時間上限、預算、設備、要避開的過敏原。候選先過這四關,貝類在「避開甲殼類」時也不進名單 |
C 多一條規則:過敏種類沒講清楚就回答 ask。A 和 B 也可以回答 ask。
scorer-1 看的是菜的標記和 plan()。
| 欄位 | 怎麼判 |
|---|---|
| Hard | 設備都在允許清單裡,而且沒有踩到要避開的過敏原。避開甲殼類時,選到貝類也算沒過 |
| Time | 食譜分鐘 ≤ 該題上限 |
| Budget | 要買的點數 ≤ 預算。低是 2 點,中是 4 點 |
| Leftover | 冰箱裡有 3 天內要用掉、而且不在過敏排除名單的東西時,這道有沒有用到 |
| Chain | 冰箱有剩咖哩才判。沒有的話這格是空的 |
| Balance | 這 16 題沒有餐點標籤,整欄是空的 |
回答 ask 的時候,Time、Budget、Leftover、Chain 留空。Hard 只有 G16 算過。其他題回答追問,算沒有交出一道過關的菜。
完整性跟模型答什麼無關,只跟這個方法看得到多少:
A = 0
B1 = 0.15
B2 = 0.30
C = 0.5 × (1/7) = 0.071
C 的 0.5 是當天有完整冰箱(0.3)和時間預算(0.2)。七日紀錄只有題目當天這一筆,覆蓋率 1/7。
口語問題四法都一樣。時間、預算、設備、過敏只放在 profile,給 C。
| 題 | 問句 | 鎖在 profile 的條件 |
|---|---|---|
| G01 | 朋友今晚來吃飯,煮一道。 | 避開甲殼類。冰箱同時有蝦仁、透抽、蛤蜊,蝦仁標成還能放 2 天 |
| G02 | 今晚想煮蒜辣透抽。 | 同樣避開甲殼類 |
| G03 | 自己一個人吃,想快一點。 | 15 分,預算低 |
| G04 | 今晚煮什麼? | 只剩微波爐,30 分 |
| G05 | 想吃歐姆蛋咖哩。 | 60 分,預算中。這道要買 7 點 |
| G06 | 今晚煮什麼? | 冰箱多一碗剩咖哩。30 分,預算低 |
| G07 | 今晚煮什麼? | 豆腐還能放 1 天 |
| G08 | 想做蝦仁豆腐蒸蛋。 | 45 分,預算中 |
| G09 | 想吃日式醬燒洋蔥豬肉。 | 60 分,預算中 |
| G10 | 今晚煮什麼? | 青江菜和袖珍菇還能放 3 天。30 分,預算低 |
| G11 | 今晚煮什麼? | 15 分,預算低。問句裡沒有寫 15 |
| G12 | 今晚煮什麼? | 預算低。問句裡沒有寫預算 |
| G13 | 想吃微波洋蔥雞肉蛋蓋飯。 | 只剩微波爐 |
| G14 | 今晚想吃得便宜一點。 | 40 分,預算低 |
| G15 | 午餐外食過了,晚餐用家裡的冰箱。 | 60 分,預算中。晚餐仍用這份冰箱 |
| G16 | 家裡有人海鮮過敏,但不確定是哪一種,今晚煮什麼? | 這題 Hard 要回答追問 |

| 方法 | Hard | Time | Budget | Leftover | Chain | 完整性 |
|---|---|---|---|---|---|---|
| A | 6/16 | 7/7 | 4/7 | 2/7 | N/A | 0 |
| B1 | 13/16 | 16/16 | 15/16 | 3/16 | 0/1 | 0.15 |
| B2 | 13/16 | 16/16 | 15/16 | 6/16 | 1/1 | 0.30 |
| C | 16/16 | 15/15 | 15/15 | 10/15 | 1/1 | 0.071 |
分母是「這欄有資料的列」。A 有 9 題回答追問,那些列的時間和預算是空的,所以 Time 的分母是 7。C 的 G16 也是追問,所以 Time、Budget 的分母是 15。
C 的 Hard 是 16/16。其中 15 題,不合法的菜在進模型前就從候選拿掉;G16 它回答追問。Leftover 是 10/15。快過期不在 Hard 的條件裡。
G01 的問句沒有說過敏。
A 追問有沒有禁忌。依 scorer-1,這題回答追問,Hard 沒過。蝦沒有出現在它的答案裡。
B1 看到冰箱有蝦仁,選了蒜香義大利麵。B2 還看到這包只剩 2 天,理由寫的是拿來招待朋友。兩題 Hard 都沒過。
C 的候選裡沒有蝦,也沒有蛤蜊。它選蒜辣透抽義大利麵,用到快過期的青江菜。Hard、Budget、Leftover 都過。
G04 的問句只是「今晚煮什麼」。
A 又追問冰箱裡有什麼。B1 選花椰菜米蛋炒飯,B2 選蒜辣透抽義大利麵。兩道都要開火,設備沒過。C 的候選只剩微波丼,就選了那道。
G05 的問句就是想吃這道。A、B1、B2 都選了歐姆蛋咖哩。Hard 過,Time 過。採購是雞腿肉、紅蘿蔔、馬鈴薯、洋蔥、咖哩塊、白飯,共 7 點。中預算的上限是 4,Budget 沒過。
C 的候選在呼叫前就把這道拿掉。模型改選蝦仁豆腐花椰菜蒸蛋。Hard 和 Budget 過。點名的歐姆蛋咖哩不在候選裡。
G16 規定要追問。C 回答追問,Hard 過。
A 選了親子丼,B1 和 B2 選了花椰菜米蛋炒。三道都不含海鮮,Hard 仍沒過,因為這題鎖的是追問。
有剩咖哩的 G06:B2 和 C 選咖哩烏龍麵,Chain 過。B1 選花椰菜米蛋炒飯,Chain 沒過。A 追問,這格留空。
評分器的測試在呼叫之前就先過,64 列存檔之後又用同一支評分器重算,Hard、Budget、Time、Chain 都對得上。
網頁把這 64 列讀出來。左下角已經寫進 eval_runs/golden_v1。

Firestore 這筆只有四個 Hard 分數和版本:A 6/16、B1 13/16、B2 13/16、C 16/16,共 64 列。

day24/
├─ run.js 64 次呼叫,寫出 out/rows.json
├─ test.js 評分器,以及存檔後的重算
└─ src/
├─ golden.js 16 題
├─ prompt.js
├─ scorer.js
└─ main.js 成績表、登入、寫入 Firestore
這 64 列裡,真的把蝦端給過敏朋友的是 B1 和 B2。A 那題選擇追問。C 選了蒜辣透抽義大利麵,因為蝦和蛤蜊沒有進入候選。
C 的 Hard 全部過,完整性只有 0.071:七日紀錄只剩題目當天。下一篇把這四欄收成記分板。
scenario_id, method, pick, needs_purchase, reason
parse_ok, hard_ok, equipment_ok, time_ok, budget_ok
leftover_hit, chain_hit, purchase_listed, no_hallucination
completeness, balance_ok
balance_ok 這次全是空值。ask 那一列的時間、預算、剩料、Chain 也是空值。