iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0

前言

Day 25 我們先把 final experiment 的設計固定下來。

當時沒有急著跑模型,原因是:

沒有固定實驗設計,就沒有可信的比較結果。

這一篇才正式開始執行實驗。

不過 Day 26 仍然先不下結論。

這次要做的是:

照 Day 25 的 experiment plan 執行各組設定,蒐集 eval run,並判斷哪些 run 可以進入 Day 27 分析。

Day 26 是資料蒐集日,分析留到下一篇。


這篇要完成什麼?

執行內容包括:

  1. 確認執行前環境。
  2. 執行 baseline。
  3. 執行 json_strict prompt。
  4. 執行 baseline + retry。
  5. 執行 json_strict + retry。
  6. 記錄每組實驗的 run id。
  7. 建立 final experiment run log。
  8. 判斷哪些 run 可以用於 Day 27 分析。

執行期間先不做:

  • 不修改 prompt。
  • 不修改 eval dataset。
  • 不臨時調整 evaluator。
  • 不因為結果不漂亮就重跑到滿意。
  • 不做完整結論。

範圍收斂在一件事:

把實驗資料乾淨地跑出來。

執行前檢查

在執行 Gemini 實驗前,先確認幾件事。

1. GEMINI_API_KEY 已設定

如果沒有設定 Gemini API key,會看到:

ValueError: GEMINI_API_KEY is not set

可以在同一個 terminal 裡設定:

export GEMINI_API_KEY="你的 Gemini API key"

如果只是要驗證本機流程,可以改用:

LLM_PROVIDER=fake

這次 final experiment 要觀察真實 LLM,因此主要使用 Gemini。

2. 不修改 evals/cases.json

Day 25 已經決定:

所有實驗組使用同一份 evals/cases.json。

執行前不要新增、刪除或修改 test cases。

如果中途改了 dataset,前面已經跑出的結果就不適合拿來比較。

3. 使用相同 delay 設定

為了降低短時間連續請求造成 Gemini 429,每組 Gemini run 都加上:

EVAL_DELAY_SECONDS=10

這不是正式的 rate limit 解法。

但對 MVP 階段來說,可以降低實驗過程被 429 干擾的機率。


四組實驗

Day 25 設計了幾組實驗。

先執行四組 Gemini run:

experiment id provider prompt version retry
gemini_baseline_no_retry gemini baseline off
gemini_json_strict_no_retry gemini json_strict off
gemini_baseline_retry gemini baseline on
gemini_json_strict_retry gemini json_strict on

這四組可以回答幾個基本問題:

baseline 表現如何?
json_strict prompt 是否改善 JSON output?
retry 能不能救回 format_error?
prompt 已經改善後,retry 是否還有額外價值?

實驗一:baseline,不開 retry

第一組先建立 baseline。

執行:

EVAL_DELAY_SECONDS=10 \
RETRY_ENABLED=0 \
PROMPT_VERSION=baseline \
LLM_PROVIDER=gemini \
python3 -m evals.runner

這一組代表:

原始 prompt
不做 retry 補救
使用 Gemini 真實回覆

本次執行結果:

Run ID: eval_run_20260924_184555
Provider: gemini
Prompt version: baseline
Retry enabled: False
Total cases: 15
Passed: 10
Failed: 5
Total latency: 88262.05 ms
Total LLM calls: 15
Total tokens: 264
Estimated cost: 0.00000000

這一組是後面比較的基準。

Day 27 會拿其他設定和它比較。


實驗二:json_strict,不開 retry

第二組測試 prompt 改善。

執行:

EVAL_DELAY_SECONDS=10 \
RETRY_ENABLED=0 \
PROMPT_VERSION=json_strict \
LLM_PROVIDER=gemini \
python3 -m evals.runner

這一組代表:

改用更嚴格的 JSON prompt
不做 retry 補救
觀察 prompt 本身是否有效

本次執行結果:

Run ID: eval_run_20260924_185011
Provider: gemini
Prompt version: json_strict
Retry enabled: False
Total cases: 15
Passed: 13
Failed: 2
Total latency: 80131.38 ms
Total LLM calls: 15
Total tokens: 140
Estimated cost: 0.00000000

這一組可以和 baseline 直接比較:

同樣不開 retry
只改 prompt version

這樣比較比較乾淨。


實驗三:baseline,開 retry

第三組測試 retry。

執行:

EVAL_DELAY_SECONDS=10 \
RETRY_ENABLED=1 \
PROMPT_VERSION=baseline \
LLM_PROVIDER=gemini \
python3 -m evals.runner

這一組代表:

維持 baseline prompt
遇到 JSON format_error 時 retry 一次
觀察 retry 能救回多少失敗

本次執行結果:

Run ID: eval_run_20260924_185518
Provider: gemini
Prompt version: baseline
Retry enabled: True
Total cases: 15
Passed: 11
Failed: 4
Total latency: 105118.41 ms
Total LLM calls: 18
Total tokens: 463
Estimated cost: 0.00000000

這裡可以先記下一個現象:

Total LLM calls 從 15 變成 18。

這表示有 3 個 case 觸發 retry。

這裡先記錄現象,完整解讀留到 Day 27。


實驗四:json_strict,開 retry

第四組測試 prompt + retry。

執行:

EVAL_DELAY_SECONDS=10 \
RETRY_ENABLED=1 \
PROMPT_VERSION=json_strict \
LLM_PROVIDER=gemini \
python3 -m evals.runner

這一組代表:

使用 json_strict prompt
同時允許 JSON format_error retry
觀察 prompt 改善後 retry 是否仍有發生

本次執行結果:

Run ID: eval_run_20260924_185945
Provider: gemini
Prompt version: json_strict
Retry enabled: True
Total cases: 15
Passed: 12
Failed: 3
Total latency: 79742.16 ms
Total LLM calls: 15
Total tokens: 133
Estimated cost: 0.00000000

這裡也先記下一個現象:

雖然 RETRY_ENABLED=1,但 Total LLM calls 仍然是 15。

這次沒有 case 觸發 retry;至少在這次 run 裡,json_strict 已經讓 JSON 題目一次通過。


建立 final experiment run log

接著把這四組結果記錄下來。

這裡先用 Markdown 手動整理。

新增 evals/final_experiment_runs.md:

# Final Experiment Runs

| experiment id | run id | provider | prompt version | retry | passed | failed | llm calls | total latency ms | usable | note |
|---|---|---|---|---:|---:|---:|---:|---:|---|---|
| gemini_baseline_no_retry | eval_run_20260924_184555 | gemini | baseline | 0 | 10 | 5 | 15 | 88262.05 | yes | baseline |
| gemini_json_strict_no_retry | eval_run_20260924_185011 | gemini | json_strict | 0 | 13 | 2 | 15 | 80131.38 | yes | prompt-only improvement |
| gemini_baseline_retry | eval_run_20260924_185518 | gemini | baseline | 1 | 11 | 4 | 18 | 105118.41 | yes | retry triggered on JSON cases |
| gemini_json_strict_retry | eval_run_20260924_185945 | gemini | json_strict | 1 | 12 | 3 | 15 | 79742.16 | yes | retry enabled but not triggered |

這個檔案不是給程式讀的。

它是給人看的實驗紀錄。

有了它,Day 27 分析時就不需要在 data/eval_runs/ 裡猜哪幾份 JSON 才是 final experiment。


檢查 run 是否可用

Day 25 有定義一個 run 是否可以進入 final comparison 的條件。

接著逐項檢查。

條件 檢查結果
total cases 相同 四組都是 15
provider 正確 四組都是 gemini
prompt version 正確 baseline / json_strict 符合設定
retry_enabled 正確 off / on 符合設定
沒有大量 429 這四組結果沒有看到 429
eval runner 成功跑完 四組都有完整 summary

所以這四組 run 都可以標記為:

usable for Day 27 analysis

這一步只要確認:

我們已經有一組乾淨、完整、可比較的實驗資料。


初步整理,不做深入分析

雖然 Day 27 才會正式分析,但 Day 26 可以先整理成一張總表。

experiment passed failed success rate LLM calls total latency
baseline / no retry 10 5 66.7% 15 88262.05 ms
json_strict / no retry 13 2 86.7% 15 80131.38 ms
baseline / retry 11 4 73.3% 18 105118.41 ms
json_strict / retry 12 3 80.0% 15 79742.16 ms

這張表先只做資料整理。

暫時不要急著說:

哪一組最好

因為正式分析還要看:

  • failure type。
  • 哪些 case 被救回。
  • 哪些失敗其實是 evaluator 太嚴格。
  • retry 增加的 latency 是否值得。
  • json_strict + retry 為什麼沒有比 json_strict 更高。

這些都留到 Day 27。


觀察 retry 是否真的發生

有一個欄位值得先確認:

Total LLM calls

如果總共有 15 個 cases,而且沒有 retry,理論上:

Total LLM calls = 15

這在三組實驗中成立:

experiment LLM calls
baseline / no retry 15
json_strict / no retry 15
json_strict / retry 15

但 baseline / retry 是:

Total LLM calls = 18

這表示 retry 真的有發生,而且發生了 3 次。

這和 JSON 題目數量一致。

也就是:

case_013
case_014
case_015

這三題在 baseline 下容易產生 JSON format error。

retry 開啟後,系統多送一次修正 prompt。

這也驗證了 Day 19 和 Day 23 的設計:

retry 可以被觸發
retry 次數可以被記錄
retry 對 LLM call count 有影響

為什麼 Estimated cost 是 0?

這次四組結果的 estimated cost 都是:

0.00000000

這不是成本真的為 0。

而是 Day 23 的 cost estimation 使用環境變數:

INPUT_COST_PER_1K_TOKENS
OUTPUT_COST_PER_1K_TOKENS

如果沒有設定,預設就是 0。

如果想讓 estimated cost 顯示非 0,可以執行時加上:

INPUT_COST_PER_1K_TOKENS=0.0001 \
OUTPUT_COST_PER_1K_TOKENS=0.0004 \
EVAL_DELAY_SECONDS=10 \
RETRY_ENABLED=0 \
PROMPT_VERSION=baseline \
LLM_PROVIDER=gemini \
python3 -m evals.runner

不過要注意:

這些價格只是示範,不代表 Gemini 實際價格。

Day 26 不處理精準帳單,只確認成本欄位能否統一記錄。


如何把結果放進 dashboard

四組實驗跑完後,可以啟動 Day 24 的 dashboard:

streamlit run failure_dashboard_app.py

Dashboard 可以用來確認:

  • 每個 run 是否出現在選單裡。
  • summary 是否顯示正確。
  • case metrics 是否有 latency 和 token。
  • prompt version comparison 是否讀到四組 run。
  • failure type distribution 是否正常。

如果 dashboard 裡有很多舊 run,要注意不要直接把所有 run 都當成 final experiment。

真正要送進 Day 27 分析的是這四組:

eval_run_20260924_184555
eval_run_20260924_185011
eval_run_20260924_185518
eval_run_20260924_185945

執行整理

依照 Day 25 的實驗設計,四組 Gemini final runs 都已完成。

完成內容包含:

  • 執行 baseline / no retry。
  • 執行 json_strict / no retry。
  • 執行 baseline / retry。
  • 執行 json_strict / retry。
  • 記錄四組 run id。
  • 建立 evals/final_experiment_runs.md 作為實驗紀錄。
  • 確認四組 run 都沒有大量 429。
  • 確認四組 run 都可以進入 Day 27 分析。

這次先不選出勝負,得到的是:

我們已經有一組固定 dataset、固定條件、可比較的 eval run。

Day 27 可以據此回到幾個工程問題:

哪個改善真的有效?
它多花了多少成本與延遲?
剩下的失敗是 Agent 問題,還是 evaluator 問題?

下一步

Day 27 會正式分析這四組結果。

我們會比較:

  • success rate。
  • failure type。
  • JSON format error 是否被修正。
  • retry 對 latency 和 LLM calls 的影響。
  • rule-based evaluator 的限制。

最後會整理出一個比較務實的結論:

在目前這組 eval dataset 上,哪一種改善最值得保留?

上一篇
Day 25|最終實驗設計
下一篇
Day 27|分析最終實驗結果
系列文
從黑盒到可驗證:30 天打造 AI Agent 的 Trace、Eval 與 Guardrails 系統 共 27 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言