指南
教學:評估強化學習策略
一份針對兩類強化學習問題的可執行演練:一個您能執行的策略在各回合上表現如何;以及一個您無法在真實世界中試用的策略原本會表現如何,依據它將要取代的那個策略的日誌來評判。兩個範例都在本機執行,無需提供者憑證。
每個欄位和評估器的參考見強化學習;案例、評估器、指標、區間和閘門這些術語在核心概念中。本頁是貫穿它們的動手路線。
Oloproof 在這裡做什麼、不做什麼
Oloproof 不執行您的環境、不託管模擬器,也不訓練策略。您的系統在它自己的環境中執行每個回合(episode),並把它記錄為一個 rl_episode/v1 產物,每個回合指標都是從這份記錄中讀出來的。在第二部分中什麼都不執行:受測策略只說明它會給每個動作的機率。
把兩個問題分開:
| 問題 | 您擁有什麼 | 部分 |
|---|---|---|
| 這個策略在各回合上表現如何? | 一個您能執行的策略與環境 | 1 |
| 這個策略在正式環境中原本會表現如何? | 一個較舊策略所做決策的日誌,以及它使用的機率 | 2 |
事前準備
- Python 3.11 或更高版本,並已安裝 Oloproof(pip install oloproof)。
- 範例專案,它隨軟體套件一起提供。把它複製到一個新目錄:
oloproof init --example rl my-rl它包含兩個專案:episodes/ 與 off_policy/。下面的每條命令都在其中一個專案內執行,證據儲存在該專案的 .oloproof/ 目錄中。
第 1 部分:一個您能執行的策略
cd my-rl/episodes檔案
| 檔案 | 它是什麼 |
|---|---|
| env.py | 一個網格世界、兩個策略(wander 與 plan)以及執行它們的系統 |
| data/tasks.jsonl | 24 個網格,每個是一個任務:牆壁、危險格、一個起點與一個目標 |
| oloproof.yaml | 基準策略 wander 的套件 |
| candidate.yaml | 候選策略 plan 的同一個套件 |
| release.yaml | 發布政策 |
| comparison.yaml | 候選版本相對於基準必須滿足的規則 |
一個回合每步移動一格,直到抵達目標或用完步數。每一步得 -1,抵達目標得 +10,因此報酬(return)介於 -30(30 步,未抵達目標)與 10 之間。進入危險格的成本為 1:這就是安全限制條件。十次移動中有一次會滑向隨機方向,無論策略選擇了什麼,因此同一個策略在同一個網格上可能表現不同。
記錄一個回合
系統自己執行回合,並把記錄交給案例記錄器:
@system(name="grid-agent", version="wander-v1", records=("rl_episode/v1",))
def run_baseline(task):
return _run(task, wander)
def _run(task, policy):
recorder = current_case()
record = episode(task, policy, seed=task["seed"] * 1000 + recorder.replicate)
recorder.rl_episode(record)
return {"success": record["success"], "steps": len(record["steps"])}記錄列出了每一步的獎勵與成本、回合是否抵達了目標(success),以及是否是步數上限結束了它(truncated)。
每個任務多個回合
oloproof.yaml 宣告了 replicates: 5,因此每個任務執行五個回合。current_case().replicate 說明是哪一個(0 到 4),環境用它為回合設定種子:同一個任務的同一個回合總是以同樣的方式重播,而第二次執行會重複使用已儲存的回合,而不是再次執行它們。
任務仍然是單位。每個準則都是 24 個任務上的平均值,而每個任務的值是它自己在五個回合上的平均值,因此區間計數的是 24 個任務,而不是 120 個回合。按回合計數,等於假裝一個網格的五個回合是五個獨立的網格。
評估器:
evaluators:
- {type: episode_return, return_range: [-30, 10]}
- {type: episode_success}
- {type: episode_cost_within, budget: 0, criterion: hazard_free}
metrics:
- {id: solved_every_time, type: every_replicate, criterion: episode_success}return_range 是必需的:平均報酬上的區間只在每個報酬都落入的範圍內成立,而超出該範圍的報酬會停止執行。solved_every_time 只有在一個任務的全部五個回合都抵達目標時才計入該任務。
執行基準
oloproof runGate: BLOCK (exit 3)
Decisions
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Rule ┃ Metric ┃ State ┃ Reasons ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ success-floor │ episode_success │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
│ safety-floor │ hazard_free │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
└───────────────┴─────────────────┴───────────────────────┴─────────────────────────────┘
Metrics
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Metric ┃ Estimate ┃ Interval ┃ N ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ episode_return │ -10.51 │ [-16.44, -5.11] │ mean of 24 observed · 0 missing · 0 excluded │
│ episode_success │ 76.7% │ [55.4%, 89.6%] │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 14 flaky │
│ hazard_free │ 29.2% │ [10.3%, 54.0%] │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 9 flaky │
│ solved_every_time │ 37.5% │ [18.7%, 59.5%] │ 9 / 24 observed · 0 missing · 0 excluded · 5 replicates each · 14 flaky │
└───────────────────┴──────────┴─────────────────┴───────────────────────────────────────────────────────────────────────────┘
Cache: execution 0 hit/120 miss; judgment 0 hit/360 miss逐列閱讀:
- 漫遊策略在 76.7% 的回合中抵達目標,但區間從 55.4% 到 89.6%,因此 75% 的下限既沒有被達到,也沒有被錯過:INSUFFICIENT_EVIDENCE。
- 它只在 24 個任務中的 9 個上做到五個回合每次都解決。「通常有效」與「每次都有效」是不同的主張,而一個將在無人看管下執行的代理需要的是後者。
- 14 個任務不穩定:它們的成功與否在完全相同的回合之間有所變動。每個任務只跑一個回合是無法顯示這一點的。
- 它在 29.2% 的回合中避開了危險格。區間的上端 54.0% 高於 50% 的下限,因此即使是這樣糟糕的紀錄,也還不能證明這個策略不安全。
檢視一個任務:
oloproof inspect RUN_ID --case grid_03output: {
"success": false,
"steps": 30
}
judgments:
episode_return: score -30
episode_success: failed
hazard_free: passedgrid_03 的第一個回合用完了步數:報酬 -30,沒有抵達目標,沒有進入危險格。
執行候選版本
oloproof run --config candidate.yaml│ success-floor │ episode_success │ PASS │ lower_bound_meets_minimum │
│ safety-floor │ hazard_free │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold ││ episode_return │ 0.42 │ [-5.78, 2.59] │ mean of 24 observed · 0 missing · 0 excluded │
│ episode_success │ 100.0% │ [79.9%, 100.0%] │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each │
│ hazard_free │ 57.5% │ [29.3%, 81.5%] │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 6 flaky │
│ solved_every_time │ 100.0% │ [85.7%, 100.0%] │ 24 / 24 observed · 0 missing · 0 excluded · 5 replicates each │規劃策略在每個回合中都抵達目標,因此成功率下限通過。它仍然會進入危險格:有些網格沒有安全路徑,濕滑的地面又會把它推進其他危險格。它 57.5% 的安全率高於下限,但 24 個任務還不能證明它高於 50%。
比較兩個策略
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy comparison.yamlepisode_return: +10.92 [+0.21, +17.74] · 24 paired · 0 missing · 0 excluded
episode_success: +23.3 points [-3.2, +44.6] · 24 paired · 0 missing · 0 excluded
hazard_free: +28.3 points [-2.4, +54.7] · 24 paired · 0 missing · 0 excluded
solved_every_time: +62.5 points [+24.3, +87.7] · 24 paired · 0 missing · 0 excluded
Decisions
return-better episode_return superiority PASS difference_above_zero
safety-no-worse hazard_free non-inferiority, margin 5.0 points PASS lower_bound_above_margin
Gate: ALLOW (exit 0)比較把每個任務與它自己配對,每一側取它在五個回合上的平均值。報酬的差異以報酬本身的單位表示:規劃策略每個回合大約多得 10.9,至少多得 0.21。在相同的網格上配對後,5 個百分點的差距(margin)就足以表明規劃策略的安全性不比基準差,儘管兩次執行單獨都無法確定各自的安全下限。
第 2 部分:依據日誌評判的策略
cd ../off_policy一個客服台把每張工單路由到一個小模型或一個大模型。目前的路由器隨機地在 70% 的時間裡選擇小模型,30% 的時間裡選擇大模型。您寫了一條新規則:技術類工單以及較長的帳務類工單交給大模型。您還不能在真實工單上試用它,但舊路由器的日誌可以替它作答。這就是離策略評估(off-policy evaluation)。
日誌及其檔案
| 檔案 | 它是什麼 |
|---|---|
| data/decisions.jsonl | 目前的路由器做出的 600 筆決策 |
| make_log.py | 寫出該日誌的模擬程式,讓您能看到它是如何產生的 |
| router.py | 新規則,也就是受測系統 |
| oloproof.yaml | 套件 |
| release.yaml | 發布政策 |
日誌的每一行是一筆決策:
{"id":"t001","input":{"topic":"technical","length":"short"},"expected":{"action":"small","logging_probabilities":{"small":0.7,"large":0.3},"reward":1}}input 是路由器看到的內容,action 是它的選擇,logging_probabilities 是它在那一刻給每個模型的機率,reward 表示工單是否獲得解決。新規則只以它自己的機率作答:
@system(name="ticket-router", version="by-topic-v1")
def route_by_topic(ticket):
large = ticket["topic"] == "technical" or (
ticket["topic"] == "billing" and ticket["length"] == "long"
)
return {"probabilities": {"small": 0.0 if large else 1.0, "large": 1.0 if large else 0.0}}評估器:
evaluators:
- {type: off_policy_value, reward_range: [0, 1], propensity_floor: 0.3}
- {type: off_policy_improvement, reward_range: [0, 1], propensity_floor: 0.3}每筆已記錄的決策,都按新規則做出它的可能性比舊路由器高多少或低多少來重新加權:一張舊路由器以 0.3 的機率送往大模型、而新規則總會送往那裡的工單,計為 1 / 0.3 次;一筆新規則永遠不會做出的決策計為零。propensity_floor 是舊路由器給它可能選擇的任何模型的最小機率。它限制了該權重,而沒有限制,任何區間都不成立。
執行
oloproof run│ resolution-floor │ off_policy_value │ PASS │ lower_bound_meets_minimum │
│ better-than-current │ off_policy_improvement │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
│ │ │ │ about 2633 more cases would decide it, if the observed values hold (3233 in total) ││ off_policy_value │ 0.775 │ [0.632, 0.921] │ mean of 600 observed · 0 missing · 0 excluded │
│ off_policy_improvement │ 0.060 │ [-0.064, 0.188] │ mean of 600 observed · 0 missing · 0 excluded │新規則估計能解決 77.5% 的工單,在 95% 信賴水準下至少為 63.2%:60% 的下限通過。它是否勝過目前的路由器尚無定論。估計值好 6 個百分點,但區間從差 6.4 個百分點到好 18.8 個百分點,而引擎會說明大約還需要多少筆已記錄的決策才能作出決定。
這個寬度就是從別人的選擇中學習的代價。只有舊路由器碰巧送往大模型的那 30% 工單能說明大模型的情況,而且每一張都被計入三次以上。有兩件事能讓它變窄:更長的日誌,以及探索更多的舊路由器。
從您自己的系統記錄決策
- 在路由器做決策時記錄機率,而不是事後記錄;並記錄每個選項的機率,而不只是被選中的那個。Oloproof 不估計它們:猜測的機率會讓區間建立在這個猜測之上。
- 在 input 中只放入路由器做決策時看到的內容,絕不放入被選中的選項或結果:受測策略不得看到它們。
- 如果您的新策略以抽樣做出選擇,請回傳它抽樣所依據的機率,而不是它抽到的那一個選項。每個選項的名稱要與日誌中的完全一致:拼寫不同的選項會被視為舊路由器從未選擇過的選項。
- 在正式環境的路由中保留一定的隨機性。一個從不選擇某個選項的策略,不會在日誌中留下任何東西來評判一個會選擇它的規則。
- 答案描述的是與已記錄工單相似的工單,範圍是日誌所涵蓋的期間。您的流量發生的變化不在其中。
- 格式錯誤的行(機率總和不為 1、被選中選項的機率為 0、獎勵超出 reward_range)會停止執行。新規則會選擇一個舊路由器所給機率低於下限之選項的決策,或獎勵缺失的決策,都計為缺失,並會使區間變寬。
尚未建置的功能
- 對一連串決策的離策略評估,其中每一步的選擇都會改變接下來發生的事。只支援每個案例一筆決策。
- 路由器在時間範圍內一邊學習一邊改變機率的日誌。
- 託管或重設環境、模擬器或機器人。
下一步
- 強化學習:這些評估器與回合記錄的參考。
- 撰寫測試套件:重複量測以及其他套件欄位。
- 將候選版本與基準比較:配對比較讀取的是什麼。
- 核心概念:結果能延伸到哪裡、不能延伸到哪裡。