Day 20 把同一份合成 CSV 加上來源背景、再整理成 structured summary,三組仍都收到「請根據資料給我健康建議」。三組各 3 份回應,不能判定哪種輸入較穩定;但已露出值得追的問題:summary 明說 baseline 資料不足,回應仍把週初數值寫成「良好水準」;來源背景的 basis 註明缺值原因是資料設計說明,回應卻寫成「裝置提示」。把證據放進 context,不等於模型會照證據的界線說話。
今天要做第一版洞察 prompt:指定模型的角色、它能引用哪些資料、哪些推論不能做,以及資料不足時如何表達不確定。用合成情境比較輸出,檢查它能否描述觀測與程式判定,同時停在證據容許的範圍。這是要測的問題,不是預先宣稱 prompt 能解決 Day 20 看到的錯誤。
Day 19 的 feature contract 記錄指標定義、品質與判定狀態;Day 20 的 summary-v1 選出可供敘述的內容。這兩層處理輸入,還需要一句明確的任務規則處理輸出。第一版 prompt 預計讓 LLM 擔任資料說明者:引用提供的觀測、來源背景與已計算的結果,交代其時間範圍和限制;不得自己重設 baseline、補算未提供的 score,或從數值直接推定疾病、疲勞成因與恢復期限。模型若提出下一步,也要分清一般性的資料檢查與有醫療含義的個人建議。Day 20 三組回應各有 5~14 項歸為「外加建議」的數值(輸入裡沒有、也算不出來;多是睡眠「7.5~8 小時」這類建議,少數是對資料的不精確描述),prompt v1 要先決定這類一般性建議能不能出現,能出現時要怎麼標明不是來自資料。
「只根據證據」要落到句子層級。數字能在輸入裡找到,整句話仍可能越界:Day 20 的 summary 回應提到資料不足,卻把週初的 RHR 與 HRV 當成要「回到」的「良好水準」,引用的週初 HRV「55–58 ms」還漏了 09-10 的 52。規則參數也會被讀錯:同一則回應寫「通常需要至少 14~21 天」,把觀測筆數門檻 14 和視窗日數 21 拼成一個天數區間。即使描述了一個真實出現的變化,也不代表能把它稱作個人的正常值。檢查 prompt 時,要看每個主張依賴哪個欄位、規則或來源;找不到依據的比較或成因,就不能用肯定句補上。
同一份輸入裡有不同身分的資訊。逐日值是合成情境中的資料;baseline 狀態與偏離標旗是程式依指定規則算出的結果;「09-11 訊號品質不足」則是 Day 1 資料設計說明,不是 CSV 或裝置品質旗標。不過輸入本身的說法並不一致:known_missing.reason 寫「裝置未輸出 HRV」,只有 basis 註明是設計說明,summary-v1 的 missing_kind 則是 unknown。Day 20 的「裝置提示」較像照搬 reason、略過 basis;若 prompt v1 沒有改善,可能要改輸入的寫法,那屬於 context 變動。Prompt 應要求模型保留這些差別,引用背景時說出它是情境設定,不能轉述為裝置實際偵測。null、insufficient 或 decidable=false 也各有語意:沒有可判定的偏離,不等於已證實沒有偏離。
Day 19 依 09-1 將參考標準未查或為空的輸出標成 auxiliary(進 summary-v1 後欄名為 auxiliary_observation),只容許作「輔助觀察」,不能讓模型把它升格為健康結論。Day 1 的三個指標都沒有查過驗證,全部是輔助觀察;而這個旗標只標得到輸入欄位,Day 20 回應裡的「疲勞累積」不是任何欄位,要靠 §1 的推論限制來擋。這不表示 auxiliary=false 就足以支持診斷;數值、驗證狀態與推論範圍仍要一起讀。第一版 prompt 可以要求在證據不足時直說哪一項無法判定、缺什麼資料,而不是用模糊的「可能」接上一段具體成因。這些都是擬定的行為約束,效果要看實際回應。
測試時先讓輸入資料、模型與呼叫設定保持一致,再比較 Day 20 的開放式請求與 prompt v1;否則資料選擇和任務指令同時改變,無法判讀差異。Day 20 沒有設 system instruction,只有一句要求健康建議的使用者訊息;把 prompt v1 放進 system instruction,等於改了 Day 20 要在同一次比較內固定的呼叫設定,若連使用者訊息也換成「說明資料」,任務和約束會一起變,兩者要分開記錄。對照組也很薄:Day 20 三組與有標旗的補充案例各 3 份成功回應;temperature 1.0 下,3 份對 3 份只看得出行為是否重複出現,估不出穩定的比例。合成案例至少要涵蓋 baseline 不足、缺值原因只有情境說明,以及有可判定標旗的情況。逐句記錄模型有沒有引用證據、把輔助觀察寫成結論、自選比較基準、把未知寫成已知,或把相關變化寫成因果。Day 1 的七項清單(Day 20 沿用)可作起點,但驗收要看句意是否符合欄位語意,不能只計算某個詞有沒有出現。
Day 20 的 summary-v1 含逐日序列,模型仍可自行挑幾天作比較;也預留了不放序列的版本作為後續比較,但 build_summary 目前還沒有這個選項。若加入這一組,必須另列為 context 變動,不能把差異算成 prompt 的效果。即使 prompt v1 在幾個案例中沒有越界,也只表示這些回應通過檢查;自由文字的固定欄位驗證與更系統的回歸評測,仍分別是 Day 22、Day 26 的工作。
直接讀 Day 20 實際送出的四份輸入 days/day20/inputs/*.txt,不重新計算。raw、raw+context、summary 是 Day 1 七日合成 CSV 的三種呈現;supplement 是 baseline 已 stable、rmssd 有偏離標旗的合成日。
uv run python days/day21/compare_demo.py --section 1 # 組出四份輸入 = prompt v1 + Day 20 原文,不呼叫 API
uv run python days/day21/compare_demo.py --section 2 --out days/day21/runs_new # 新一輪:四組各 3 次,共 12 次邏輯呼叫,重試另計
uv run python days/day21/compare_demo.py --section 2 --retry-failed # 只補跑 days/day21/runs/ 裡失敗或缺少的呼叫
輸入的組法只有一行(src/wearable_ai/ai/prompts.py);呼叫、節流與重試從 Day 20 抽成共用的 batch.run_batch:
def with_prompt(prompt: str, base_input: str) -> str:
return f"{prompt.rstrip()}\n\n{base_input}"
inputs = {g: with_prompt(PROMPT_V1, day20_text) for g, day20_text in base_inputs().items()}
prompt v1 中和 Day 20 問題最直接相關的兩條:
2. 分清三種來源,引用時說出是哪一種:
- 觀測:資料裡的逐日數值。
- 程式判定:摘要裡已經算好的結果,例如 baseline 狀態、偏離判定、平均值。照原樣引用,不要自己重算,也不要另訂標準。
- 資料說明:欄位定義、缺值原因、匯出時間等背景。說明若註明依據(basis),轉述時一併交代,不要說成裝置偵測到的事。
6. 不自己挑某幾天當作「正常」「良好」或應該回到的水準。資料裡沒有可用的個人基準時,就直說沒有。
先看整體:12 份回應都以「我是資料說明者」或同義句開頭,沒有一份給健康建議;外加建議中的數值從 Day 20 的每份 4~14 項降到 0。回應變長:前三組從 1,323~1,594 字元增為 1,927~3,733,supplement 從 1,493~1,732 增為 3,033~4,661,多出來的主要是逐日數值與出處標註。
| 原本以為 | 實際發現 |
|---|---|
| 我原本以為,只要原句還在要求健康建議、輸入又保留逐日數值,模型即使被禁止自選正常值,仍會拿週初當成應該回到的水準。 | Day 20 三組 9 份都以週初為對照,7 份給了要回到的門檻或目標;Day 21 三組 9 份都沒有把週初當成正常值或要回到的水準(R1、C2 仍描述 09-09 的 58 ms 降到 09-14 的 42 ms,只是描述變化)。raw r2:「無法定義哪一天的數值屬於『正常』或『良好』,也無法界定數值應該回到多少」;raw+context r1 明說不能把「數值看似平穩的 09-08 或 09-09」認定為應回復的水準。 |
我原本以為,明確要求轉述時一併交代 basis,模型就會在整份回答裡保留「資料設計說明」的前提,不再把缺值原因說成已確認的事實。 |
有背景的 6 份都在資料段引用了 basis(raw+context r1:「依據(basis)是『資料設計說明』,並非穿戴裝置本身輸出的品質旗標」)。但其中 5 份到後段又把原因寫成事實:「2026-09-11 出現訊號品質不足導致 HRV 缺失」(raw+context r1)、「原因為睡眠訊號品質不足」(summary r3)。raw 3 份從 Day 20 的完全跳過 09-11,變成都說明缺值、且輸入沒有給原因。 |
| 我原本以為,要求照原樣引用程式判定、每個數字標出處,就能讓模型把「14 筆有效觀測」和「21 天視窗」分清楚。 | summary 3 份都正確引用 n_obs 5~6 與 min_obs_for_center 14,但 2 份仍寫成天數:r1 前段「至少 14 筆有效觀測」、後段「待資料累積滿 14 天以上」;r2「尚未達到建立個人基準所需的 14 天觀測值標準」。Day 20 是 3 份。 |
| 我原本以為,禁止推測成因與身體狀態、要求沿用程式判定後,模型就會只描述旗標與數值,不再自行替指標加上判斷。 | Day 20 前三組 9 份都判定身體狀態、都用因果語氣;Day 21 都沒有,「疲勞」「壓力」「自律神經」「疾病」只出現在「不能推論」這類句子裡。supplement 的成因清單從 3 份各列 4 項(感染、飲酒、訓練、心理壓力)變成 0。但 supplement r2 寫「較高的睡眠時間(476.07 分鐘)及靜止心率(56.82 bpm)」:兩者是七日最大值、也高於 baseline 中心;前段兩個小節也都寫了 flag 為 false,但這一句沒說比較對象,也沒重申未超過門檻,單看這句容易讀成超過偏離門檻;r1 把 deviation.lower 稱為「基準線下限」。 |
| 我原本以為,把來源列成觀測、程式判定、資料說明三類,模型加上的標籤就能直接對回輸入裡的對應區塊。 | summary 3 份與 supplement 3 份把摘要 JSON 的 definition、date_attribution(supplement 另有 coverage)標成「資料說明」。依規則 2,欄位定義本來就屬資料說明,類型沒標錯;但輸入裡另有「資料說明:」區塊(補充案例沒有),標籤無法指出引用的是哪一個位置。 |
我原本以為,要求模型交代資料不足與缺少的資訊,即使 raw 沒有匯出時間,也會提醒最後一天的步數未必完整,不宜直接拿來比較。 |
raw 輸入沒有匯出時間。Day 20 的 3 份都把 09-14 的 1,850 步讀成疲勞;Day 21 都沒有,但也沒有人說它可能不完整,r3 把它當成波動舉例:「2026-09-13 為 21480 步,2026-09-14 為 1850 步」。有背景的 6 份都說明了步數不完整。 |
兩個沒有預期的副作用。一是數值精度:prompt 要求「照原樣引用」,summary r2、r3 與 supplement r1 照抄完整浮點數(「61.666666666666664」「−3.3955111401775726」)。二是 supplement 輸入有 rmssd 在合成評測(無事件序列、A 組)下的誤報率,每 100 個負例日 1.137 次,Day 20 與 Day 21 的 6 份都沒有提到;prompt 沒要求引用,算資訊遺漏,留作下一版的候選規則。
這次比較的是整份 prompt v1 加入前後的回應,10 條規則與角色設定一起改變,無法拆出哪一條起作用;位置固定在使用者訊息開頭,也沒有測 system instruction 或資料順序。每組只有 3 次、temperature 為 1.0,「這次沒有出現」不能當成穩定的錯誤率估計。Day 21 的回應跨兩把 API key,連同 Day 20 對照則跨三把與不同時段;模型版本與呼叫設定相同,但無法確認背後服務狀態完全一致。判讀由 agent 單一評閱者逐句進行,沒有獨立複核的一致性結果;Day 21 又大量列舉數值,未重做 Day 20 的四類總項數,因此外加數值降到 0 是本次回應的計數結果,不能換算成兩天可直接比較的整體正確率。
資料也只有一份七日合成序列的三種呈現,以及一個 baseline 穩定、有偏離標旗的合成補充案例;12 份回應不代表 12 個不同情境,更不能據此推論真實穿戴資料或其他模型的表現。這裡測的是模型能否忠實轉述給定資料與規則,沒有驗證那些規則能否支持健康判斷。輸入本身也限制了驗收:raw 缺少匯出時間,背景的缺值原因與 basis 必須一起讀,prompt 的「資料說明」分類又未與輸入區塊一一對應。因此,來源標籤不一致不能全歸因於模型忽略規則;而不再推測疲勞,也不表示已完整交代資料限制,這次仍有原因前提遺失、觀測筆數被寫成天數,以及補充案例誤報率未被提及的情形。
Prompt 改掉了一部分越界,不是全部。 Day 20 補背景與摘要,改變的是模型提到什麼,三組仍照「請給我健康建議」寫出一套建議。Day 21 在同樣的輸入前加 10 條規則,12 份都在開頭說明角色與資料不足以支持建議;輸入沒有也算不出來的數值(、身體狀態判斷、成因清單都沒有再出現。仍在的是:缺值原因的前提在後段遺失、觀測筆數寫成天數、比較對象沒說清楚。這只是兩個合成案例、四種輸入各 3 份的結果。
規則被遵守在段落,不在每一句。 有背景的 6 份都在資料段正確引用了 basis,5 份在後段又把原因寫成事實;summary 前段寫「14 筆」,後段寫「14 天」。只檢查回應有沒有出現某個欄位或某個詞,這兩種錯誤都會通過。Day 26 的確定性檢查要以句子為單位,同一份回應前後的說法也要比對。
來源類型和來源位置要分開。 規則 2 只要模型標出觀測、程式判定、資料說明三種類型,同一類型在輸入裡可能出現在不同區塊,標籤對了也找不回出處。Day 22 的 structured output 可以把類型做成固定列舉,另加位置欄位(例如 JSON path);列舉只固定類型,位置與句意仍要另外驗。
能讓程式格式化的,就不要交給 prompt。 「照原樣引用」換來小數點後十幾位的浮點數;raw 輸入沒有匯出時間,prompt 再嚴格也補不出 1,850 步不完整這件事。數值精度與缺的資訊都屬於輸入端,這是 Day 20「誰算誰說」的延續。代價也要記:輸入多 530 token,各組平均回應長度是 Day 20 同組的 1.51、1.58、2.31、2.35 倍(raw、raw+context、summary、supplement)。