預測鉤子
鉤子讓你觀察或塑造 Laya 做出的每一個決策,而無需 fork 它。
它們是每個真實部署都需要的東西的擴充套件縫:審計日誌、推理前脫敏 PII、快取、指標、置信度門控、
路由覆蓋,以及把決策轉發給外部服務。它們是選用的:不配置任何鉤子時,Agent、Router 和
ONNXAgent 的行為不變。
它們不只用於直接呼叫。每個 LangChain 與 LangGraph runnable 都接受同樣五個逐呼叫 參數,所以鉤子可以掛到圖裡的某一個節點上,而不是整個智慧體上。
這個資料夾是完整的參考。從這裡開始,然後深入你需要的那一頁:
| 頁面 | 裡面有什麼 |
|---|---|
| API 參考 | 每一個類、欄位、參數和預設值 |
| 生命週期 | 每個鉤子究竟何時執行,帶流程圖 |
| 錯誤 | hooks_raise、on_error、異常鏈、失敗矩陣 |
| 模式與反模式 | 該做什麼、該避免什麼,以及為什麼 |
| 示例 | 每個用例都可複製貼上的配方 |
| 鏈路追蹤 | run_id、span 關聯、OpenTelemetry |
快速開始
import laya
def log(ctx):
print(ctx.model, ctx.results[0]["answers"], ctx.elapsed_ms)
agent = laya.load("convaiinnovations/laya", on_predict_end=log)
agent.system_one("I was charged twice.", {"urgent": {"type": "noul", "instructions": "Urgent?"}})
一個物件可以實現生命週期事件中的任意子集:
class Audit:
def on_predict_start(self, ctx):
print("start", ctx.run_id)
def on_predict_end(self, ctx):
print("end", ctx.run_id, ctx.usage, ctx.elapsed_ms)
def on_error(self, ctx):
print("failed", ctx.run_id, ctx.error)
laya.load("convaiinnovations/laya", hooks=[Audit()])
鉤子也可以在之後新增,或者限定在一段程式碼塊內:
agent.add_hook(tracer) # attach at runtime
with agent.hooks_installed(debug): # installed for the block, removed on exit
agent.system_one(state, questions)
見執行時註冊。對於一個應該處處生效、又不想穿過每次呼叫的 鉤子,用程序級預設值註冊一次:
from laya import hooks
hooks.set_default_hooks(hooks=[Tracer()])
心智模型
有三個概念。
-
鉤子是一個可呼叫物件或一個物件。 一個普通函式適合一個事件;一個物件適合多個。兩者都傳給
hooks=/on_predict_start=/on_predict_end=。 -
一次呼叫的每個鉤子共享同一個可變的
PredictContext。 它攜帶狀態、問題、結果、路由決策、 模型名、usage、計時和任何錯誤。一次呼叫可以同時攜帶很多狀態(predict_batch),所以一個想 覆蓋每一個決策的鉤子必須遍歷ctx.states和ctx.results;ctx.usage和ctx.elapsed_ms是整次呼叫的合計。因為上下文是可變的,鉤子可以塑造這次呼叫,而不只是旁觀:脫敏狀態、改寫 問題、替換結果,或用快取答案跳過推理。 -
有兩個作用域。
Agent鉤子包住一次前向傳播;Router鉤子包住路由加推理,還能看到模型 生命週期(on_route、on_load、on_evict)。這對應其他智慧體框架裡「run hooks」與 「agent hooks」的區分。
Router.predict(state, questions)
┌──────────────────────────────────────────────────────────────────────────┐
│ route() │
│ ├─ detect language / workflow │
│ └─ on_route ctx.decision (a hook may replace it) │
│ │
│ load(decision.model) │
│ ├─ build checkpoint on first use ──► on_load ctx.model, ctx.agent │
│ └─ evict LRU checkpoint ───────────► on_evict ctx.model │
│ │
│ on_predict_start ctx.states, ctx.questions, ctx.decision │
│ │ │
│ ├── ctx.skip(results)? ──► skip the forward pass │
│ │ │
│ └── Agent.system_one(...) ──► Agent-level hooks run here │
│ on_predict_start ─► forward ─► on_predict_end │
│ │
│ result["routing"] = decision │
│ on_predict_end ctx.results, ctx.usage, ctx.elapsed_ms │
└──────────────────────────────────────────────────────────────────────────┘
any failure on the way ──► on_error, then on_predict_end
作用域一覽
Agent / ONNXAgent |
Router |
|
|---|---|---|
on_predict_start |
是 | 是 |
on_predict_end |
是 | 是 |
on_error |
是 | 是 |
on_route |
否 | 是 |
on_load |
否 | 是 |
on_evict |
否 | 是 |
laya.serve 和 MCP 伺服器呼叫 Router.predict,所以 Router 鉤子對它們自動生效。Router 執行一個
掛載的或內建的 agent 時,Agent 鉤子就生效。
相容性
- 不配置鉤子就沒有任何行為變化。未設定的路徑有迴歸測試。
- 所有鉤子參數都是帶預設值的關鍵字參數,所以現有的呼叫繼續可用。
laya/hooks.py是純 Python:import laya不會因為它而拉進 torch。- 鉤子預設是同步的。一個
async def事件可以包進AsyncHook,或者 作為一個普通的非同步可呼叫物件傳入,它會替你執行到完成。 hooks_timeout給慢鉤子設上界,使它無法掛起一個正在服務的請求。- 保持鉤子快且非阻塞;關於對
laya.serve的後果見錯誤和 模式。
另見
examples/hooks/:可執行的審計、脫敏、快取和指標鉤子。tests/test_hooks.py:行為規範。tests/test_hooks_api.py:API 穩定性的守衛。laya/hooks.py:實現。