Hook 是什麼?PreModelSwitch 又是屬於哪一類的 hook?
Hook 是 Claude Code 讓你在特定時間點自動執行動作的機制——你可以寫一段 shell 指令、呼叫一個 HTTP 端點、呼叫一個 MCP 工具、給一個 LLM 提示,或是叫用一個 subagent,在某個事件觸發的當下自動執行。最常見的兩個 hook 是 PreToolUse(工具執行前)跟 PostToolUse(工具執行後),分別對應「工具還沒跑,可以攔下來」跟「工具已經跑完,只能事後處理」這兩種時機。
PreModelSwitch 就是同樣邏輯套用在「切換模型」這個動作上的版本——它在切換發生「之前」觸發,所以理論上可以攔截、可以拒絕。跟它成對的 PostModelSwitch,則對應「切換已經發生」的時機,邏輯上跟 PostToolUse 是同一種:能記錄,不能阻止。
為什麼模型切換值得特別做一組 hook,而不是套用一般的 PreToolUse/PostToolUse 就好?
最直接的原因,是模型切換不是一個「工具呼叫」——它是 session 本身狀態的改變,影響的是接下來所有請求會用哪個模型處理,而不是單一一次工具執行的結果。用 PreToolUse/PostToolUse 這種通用機制去攔截模型切換,沒辦法拿到模型切換特有的關鍵資訊,例如目前的提示詞快取是不是還熱著、預估的快取重建成本是多少——這些資訊只有在「知道這是一次模型切換」的前提下才有意義。
更深層的原因,是模型切換牽涉到提示詞快取(prompt caching)的運作邏輯:每個模型都有自己獨立的快取,一旦切換模型,下一次請求就會讀取整段對話,完全沒有快取命中。如果沒有一個專門的攔截點讓你在切換之前就先評估這個代價,模型切換造成的快取重建成本會是「切換完才發現」,而不是「切換前就能權衡」——這正是 PreModelSwitch 存在的核心理由。
實際上要怎麼開始用這兩個 hook?有沒有一個最小可行的設定方式?
第一步是先觀察、不要急著攔截——在還沒寫任何攔截規則之前,先跑一個具代表性的長任務,不刻意切換模型,單純觀察 /usage 裡新增的提示詞快取那一行,以及(如果你有自訂狀態列)prompt_cache.warm、prompt_cache.hit_ratio 這類欄位長什麼樣子——先建立一個「正常情況下快取表現如何」的基準,再開始寫規則會更準確。
第二步是先用簡單的三種結果分類,而不是一條寫死「Opus 太貴」的規則:目標模型不在你允許的清單裡就 deny;目前快取還熱、預估的快取重建成本超過你設定的門檻就 ask;快取本來就已經冷掉、或上下文很小、或這次切換本來就是任務流程裡預期會發生的一部分,就 allow。每次觸發都記錄下來源模型、目標模型、來源(是手動要求還是自動)、上下文大小、快取是否熱著、預估成本——但不要記錄任何憑證或對話內容本身。
第三步才是針對 PostModelSwitch 補上事後記錄的邏輯,尤其要留意自動回退跟 session 恢復這兩種不會經過 PreModelSwitch 的情境,確保這兩種切換也有被記錄下來,不是完全沒有留下痕跡。
如果我只是個人開發者,平常對話都不長,這兩個 hook 對我來說值得花時間設定嗎?
如果你平常的使用模式是短時間、單次的對話,不常在模型之間切換,也很少恢復很久以前的舊 session,老實說這兩個 hook 帶來的實際幫助有限——你可能不會真的因為快取重建而感受到明顯的延遲或費用差異,花時間去寫攔截規則,投入產出比不見得划算。
但如果你符合以下任一情況,即使是個人開發者也值得花點時間設定:你經常讓 session 跑很長(例如一次任務持續好幾個小時甚至跨天),而且中途會手動或透過快速模式切換模型;你習慣恢復幾天前的舊 session 繼續工作,而不是每次都開新的;或是你在用某個會自動幫你選模型的 SDK 或 Remote Control 客戶端,自己並不完全清楚它什麼時候會換模型。這些情境下,即使只是先加上 PostModelSwitch 的記錄邏輯(不做任何攔截,純粹先觀察),都能幫你看清楚「模型切換」這件事在你的實際使用中,到底發生得多頻繁、代價有多大——有了這層可見度,再決定要不要進一步加攔截規則,會比一開始就寫規則更踏實。
Claude Code 2.1.251(2026 年 8 月 28 日)新增了 PreModelSwitch 跟 PostModelSwitch 兩個 hook 事件——這代表一個原本在 session 裡「悄悄發生」的動作(切換模型),現在可以被攔截、被記錄,甚至被擋下來。如果你完全沒聽過 hooks 這個機制,或是只聽過 PreToolUse、PostToolUse,這篇會從基礎解釋這兩個新事件實際在做什麼。
Claude Code 允許你在一個 session 裡切換模型——例如從 Sonnet 換成 Opus,或是啟用某個會自動換模型的快速模式。過去這件事沒有任何攔截點:切換就切換了,系統不會問你、不會記錄細節,你也沒辦法寫一條規則說「如果現在的對話快取還是熱的,不要輕易換模型」。這在個人使用時可能感覺不出差異,但對於跑很長 session、或是背後有多人共用同一個 gateway 的團隊而言,模型切換其實是一個會直接影響費用跟結果一致性的決策點,只是過去這個決策點完全不可見、不可控。
`PreModelSwitch` 在切換「即將發生」的當下觸發,能看到的資訊包括請求切換的來源模型、目標模型、目前的上下文大小、快取是否還熱著、快取存活時間、預估的快取重建成本、以及計價方式——拿到這些資訊之後,這個 hook 可以決定 allow(放行)、deny(拒絕)或 ask(詢問)。`PostModelSwitch` 則是在切換「已經完成」之後觸發,能看到的是這次切換的完整結果,包括自動回退(fallback)跟 session 恢復(resume)造成的切換——但這個 hook 只能記錄或附加脈絡,沒辦法阻止已經發生的事。
官方文件特別強調一個容易被忽略的細節:透過 /model、選單、或 /config 主動要求切換,會同時觸發 PreModelSwitch 跟 PostModelSwitch;但自動回退(例如某個模型暫時不可用,系統自動換到備援模型)跟 session 恢復時還原原本使用的模型,這兩種情況只會觸發 PostModelSwitch,不會先經過 PreModelSwitch 讓你攔截。換句話說,如果你只寫了 PreModelSwitch 的攔截規則,以為這樣就能掌控所有模型切換,實際上還是會漏掉自動回退跟 session 恢復這兩種情境——這兩種情況只能靠 PostModelSwitch 事後補記錄,沒辦法事前擋下來。
如果你平常只是短時間、單次的對話,模型切換的影響通常有限,不太需要特別去寫這兩個 hook。但如果你符合以下任何一種情況,這兩個 hook 值得花時間設定:session 經常跑很長、常常在 Sonnet 跟 Opus 之間切換、有在用會自動換模型的快速模式、會恢復舊的 session、或是背後有 SDK、Remote Control 客戶端會自動選擇模型——這些情境下,模型切換往往意味著下一次請求會讀取整段對話而完全沒有快取命中,如果切換的時間點沒有被有意識地控管,可能造成意料之外的延遲跟費用。