EvoMap
Agent Hooks:將邏輯注入 AI 執行鏈

Agent Hooks:將邏輯注入 AI 執行鏈

2026年3月26日
283 次閱讀
agent-hooks execution-chain langchain middleware tool-calls error-handling

嗨,我是 Lena。上週我看著一個 Agent 處理工具呼叫時,隱約覺得哪裡有點不對。

那次呼叫失敗了。Agent 只是繼續往下走,沒有重試,沒有日誌,什麼都沒有。它像是什麼都沒發生一樣繼續執行。

我對著這件事想了一會兒。不是因為它當掉了,而是因為我找不到一個明確的位置,去放那段本來應該攔住它的邏輯。

也是從那時候起,我開始更仔細地看 hooks。

什麼是 Agent Hook?

所謂 agent hook,是 Agent 執行生命週期中的一個預先定義攔截點,你可以在這裡插入自訂邏輯。它不會改寫 Agent 的核心推理迴圈,而是附著在一些特定時刻上,例如工具呼叫前、模型回應後,或錯誤浮現時,讓你能在不碰 Agent 本體的情況下,在那些位置做點事。

如果你已經在用 Agent 框架開發,這大概是你熟悉的一種模式,只是可能還沒特別替它命名。你也許寫過在模型呼叫前注入上下文的邏輯,或在輸出往下游傳遞前先攔住處理的邏輯。那就是 hook。

Pre-hooks、Post-hooks 與 Error Hooks

不同框架的術語會有些差異,但整體結構其實很一致。

Pre-hooks 會在某一步執行前運作。它們可以檢查或修改輸入,例如注入認證標頭、附加上下文,或驗證必要欄位是否存在。舉例來說,before_model hook 可以先檢查對話是否長得太長,並在模型看到之前先把它裁掉。

Post-hooks 會在某一步完成後運作。它們會拿到輸出,然後轉換它、記錄它,或觸發下游動作。像 after_tool_call hook,就可以在 Agent 繼續前先把工具回傳內容記錄下來。

Error hooks 則是我覺得最值得觀察的一類。當執行鏈裡某個環節失敗時,它們就會觸發。可能是工具逾時、API 回傳 429,或模型輸出的內容沒有通過驗證。只要系統裡真的有這層設計,重試邏輯、備援路由和優雅降級通常都住在這裡。

Hooks 和 Middleware 有什麼不同

這個差別很微妙,而框架對這兩個術語的使用也不總是一致,這點不只一次讓我感到困惑。

Middleware 包裹的是整段執行,或其中某一個主要層級。請求進來,穿過 middleware 堆疊,再從另一邊出去。Hooks 則更細緻。它們附著在執行週期裡那些具名事件上,而不是把整個流程包起來。

在 LangChain 的 Agent 架構裡,wrap_model_call 的行為更像 middleware,因為它是圍在模型呼叫外層的一圈。但 before_tool_call 和 after_tool_call 則更接近狹義上的 hooks:它們只會在特定時間點觸發,而不會包裹整個步驟。LangChain agent documentation 即便把這兩種模式放在一起介紹,仍然很貼近它們在實務中的使用方式,就算概念上並不完全相同。

Hooks 常見的使用位置

攔截工具呼叫

這大概是我最常看到 hooks 落地的地方。工具呼叫是 Agent 與外部系統互動的入口,例如 API、資料庫、檔案系統,而外部系統出錯的方式,往往不是 Agent 靠自己就能優雅處理的。

before_tool_call hook 可以在請求發出前先驗證輸入。wrap_tool_call hook 可以捕捉失敗,並用退避策略重試。after_tool_call hook 則可以在 Agent 處理結果前,先把不一致的回應形狀整理成一致格式。

少了這些,工具失敗往往會悄無聲息地一路往下傳。

Memory 讀寫 Hooks

Memory 操作也是 hooks 很能放大價值的位置。在讀取 memory 之前,hook 可以依照目前的任務上下文,先過濾哪些內容應該被帶出來。在寫入 memory 之後,hook 也可以把那些看起來和現有紀錄不一致的條目標示出來。

Microsoft agent pipeline architecture 透過 AIContextProviders 採用了類似思路。這些可注入元件會在每次 LLM 呼叫前執行,用來豐富訊息歷史。它沒有明確把這種機制叫作 hook,但模式其實完全一樣:在某個特定執行點插入可組合、可替換的自訂邏輯。

輸出驗證 Hooks

就我目前的觀察,模型輸出之後的驗證 hooks 其實被低估了。Agent 產生了一段回應,但它真的符合預期 schema 嗎?裡面是否有超出可接受範圍的值?把它繼續交給下游是否安全?

如果能有一個驗證 hook 在這些問題往下傳之前先把它們攔住,成本會比事後排查低得多。

設計不打斷 Agent 流程的 Hooks

Stateless Hooks vs. Stateful Hooks

Stateless hook 只會讀取輸入、產生輸出,不依賴也不修改自己作用域之外的任何東西。它比較可預測。Stateful hook 則會讀寫共享狀態,這就帶來了執行順序依賴,以及潛在的競態條件,尤其在多 Agent 或平行執行場景裡更明顯。

Stateless hooks 更容易測試、更容易推理,也更適合安全地組合。 Stateful hooks 有時確實必要,但它們往往也是我在 hook 系統裡碰過那些隱晦 bug 的來源。LangGraph's extensibility patterns 建議把狀態變更寫得明確,並限制在清楚的作用域內,好避免這一類問題。

控制副作用

如果一個 hook 會去呼叫外部 API、寫入資料庫,或觸發通知,那它就是帶副作用的 hook。副作用本身不是錯,但它們需要被收束:邊界要清楚,最好能做到冪等,而且要盡量和核心執行路徑隔離,這樣 hook 自己出錯時,問題才不會一路級聯到 Agent 身上。

這也是我在實務裡至今仍覺得有些模糊的部分。「Agent 本身的邏輯」和「hook 被允許做的事」之間的邊界,並不總是那麼清楚。

值得重用的 Hook 模式

針對工具失敗的重試 Hooks

重試 hook 會包住一次工具呼叫,並在特定失敗條件下重新執行,例如逾時、速率限制錯誤,或暫時性的網路問題。真正關鍵的設計問題有三個:哪些錯誤值得重試、要重試幾次,以及採用什麼退避策略。

LangChain middleware 協定裡的 wrap_tool_call 正是拿來處理這件事。handler callback 這個模式,讓每一層 middleware 都能拿到內層執行的參照,因此你不需要改動工具本身,就能加上重試邏輯。

用於執行記錄的稽核 Hooks

稽核 hook 會在每個重要步驟之後觸發,記下發生了什麼:呼叫了哪個工具、回傳了什麼、花了多久、是否成功。時間一久,這份紀錄就會變成你在正式環境裡除錯 Agent 行為時最重要的工件。

Microsoft Agent Governance Toolkit 把這件事做成了一道更完整的治理閘門:每一次工具呼叫、每一份輸出、每一次 Agent 與 Agent 之間的互動,都會在執行前先經過策略引擎,並留下稽核軌跡。這是同一個底層模式,只是做得更有約束力。

針對 API 呼叫的速率限制 Hooks

速率限制 hook 會追蹤對外 API 呼叫,並在接近閾值時引入延遲或排隊。概念本身不難,但往往要等 Agent 工作流程真的在規模上撞到限制時,大家才會發現前期投入不夠。

放置位置很重要。掛得太早,可能會過度限流;掛得太晚,呼叫早就發出去了。在工具呼叫上使用 pre-hooks,通常才是插入速率限制邏輯的正確位置:既靠近呼叫本身、判斷更準,也足夠早,還來得及介入。

侷限與權衡

Hooks 確實解決了一個真問題:你可以在不重寫核心流程的前提下,往執行鏈裡注入邏輯。但它們也會帶來自己的複雜度表面。

執行順序會變得重要。 Hooks 往往按照固定順序運作,例如所有 before hooks 依序執行,接著才是呼叫本身,最後由 after hooks 逆序執行。當多個 hook 同時修改同一份狀態時,順序就會直接影響結果,而這點並不總是顯而易見。

Hooks 可能會悄悄吞掉錯誤。 一個 error hook 如果攔住並處理了失敗,可能會讓 Agent 根本不知道剛才發生過失敗。這到底是不是正確行為,完全取決於情境,而且很容易做錯。

要除錯一整條 hook 鏈,比除錯線性程式碼困難得多。 當行為不符合預期時,原因可能藏在組合 hook 堆疊的任何一層。可觀測性在正式環境裡不是可選項,而是必需品:trace、結構化日誌、明確的 hook ID,一個都不能少。OpenTelemetry specification 在這裡很值得理解;如今大多數正式環境中的 Agent 框架都會用這種格式輸出 traces,而 hooks 往往就是提供這些觀測資訊的那一層。

我還在繼續摸索:hooks 到底在什麼地方是正確的抽象,而在什麼地方又讓事情變得太重。那條界線並不是固定的。

FAQ

  1. AI 裡的 Agent Hook 是什麼?

所謂 agent hook,是在 Agent 執行週期某個特定階段插入自訂邏輯的點,例如工具呼叫前、模型回應後,或錯誤發生時。Hooks 讓開發者可以在不改動 Agent 核心迴圈的前提下,攔截、檢查、修改或擴展 Agent 的行為。LangChain、LangGraph 與 Microsoft Agent Framework 等主流框架都支援這種模式。

  1. Hook 和 Agent 裡的 Middleware 有什麼差別?

Middleware 通常包裹的是整層執行,就像一個每個請求都會經過的 pipeline decorator。Hooks 則更細,它們附著在執行週期裡的具名事件上。實務上,很多框架兩種都會使用:模型呼叫用 middleware 風格的 wrapper,before_tool_call 或 after_model 這類離散事件則用 hook 風格的 listener。兩者的邊界在工程裡經常會變得模糊。

  1. Pre-hooks 和 Post-hooks 在 AI Agent 執行中是怎麼運作的?

Pre-hooks 會在某一步執行前運作,可以修改輸入、注入上下文,或根據條件阻止執行。Post-hooks 會在某一步完成後運作,它們拿到輸出後,可以記錄、驗證,或觸發下游動作。執行順序是固定的:所有 pre-hooks 依序觸發,接著執行步驟本身,最後由 post-hooks 逆序觸發。這和 Web 伺服器 middleware 的 request/response 週期非常相似。

  1. 不修改 Agent 核心,要怎麼加入自訂邏輯?

標準做法是把 hooks 或 middleware 註冊到 Agent 的執行 pipeline 裡。在 LangChain 中,這通常意味著把 middleware 物件或經過裝飾的函式傳給 create_agent。在 Microsoft Agent Framework 裡,則是使用 .Use() decorators 或 AIContextProviders。不同框架寫法不同,但原則一致:定義攔截點、寫入邏輯、完成註冊。Agent 的核心迴圈本身不用動。

我會繼續觀察 hook 模式在正式環境裡如何演化。這種本來就被設計成「盡量不可見」的機制其實很有意思:你通常只有在它失效時,或者它本來應該在那裡卻缺席、結果別的東西先出問題時,才會真正注意到它。

相關文章