Vorhersage-Hooks
Mit Hooks kannst du jede Entscheidung von Laya beobachten oder formen, ohne sie zu forken.
Sie sind die Erweiterungsnaht für alles, was jedes echte Deployment braucht: Audit-Logging,
PII-Redaktion vor der Inferenz, Caching, Metriken, Konfidenz-Gating, Routing-Überschreibungen und
das Weiterleiten einer Entscheidung an einen externen Dienst. Sie sind opt-in: ohne
konfigurierte Hooks bleibt das Verhalten von Agent, Router und ONNXAgent unverändert.
Sie sind nicht nur für direkte Aufrufe gedacht. Jeder Runnable von LangChain und LangGraph nimmt dieselben fünf Argumente pro Aufruf entgegen, sodass du einen Hook an einen einzelnen Knoten in einem Graphen hängen kannst statt an den gesamten Agenten.
Dieser Ordner ist die vollständige Referenz. Beginne hier und tauche dann in die Seite ein, die du brauchst:
| Seite | Inhalt |
|---|---|
| API-Referenz | jede Klasse, jedes Feld, jeder Parameter und jeder Standardwert |
| Lebenszyklus | wann genau jeder Hook läuft, mit Flussdiagrammen |
| Fehler | hooks_raise, on_error, Verkettung von Ausnahmen, Fehlermatrix |
| Muster und Anti-Muster | was zu tun, was zu vermeiden ist und warum |
| Beispiele | Copy-Paste-Rezepte für jeden Anwendungsfall |
| Tracing | run_id, Span-Korrelation, OpenTelemetry |
Schnellstart
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?"}})
Ein Objekt kann jede Teilmenge der Lebenszyklus-Ereignisse implementieren:
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()])
Hooks lassen sich auch später hinzufügen oder auf einen Block begrenzen:
agent.add_hook(tracer) # attach at runtime
with agent.hooks_installed(debug): # installed for the block, removed on exit
agent.system_one(state, questions)
Siehe Registrierung zur Laufzeit. Für einen Hook, der überall gelten soll, ohne ihn durch jeden Aufruf zu schleusen, registriere ihn einmal mit prozessweiten Standardwerten:
from laya import hooks
hooks.set_default_hooks(hooks=[Tracer()])
Das mentale Modell
Es gibt drei Ideen.
-
Ein Hook ist ein Callable oder ein Objekt. Eine einfache Funktion ist praktisch für ein Ereignis; ein Objekt ist praktisch für mehrere. Beides wird an
hooks=/on_predict_start=/on_predict_end=übergeben. -
Alle Hooks eines Aufrufs teilen sich ein einziges veränderbares
PredictContext. Es trägt die Zustände, Fragen, Ergebnisse, die Routing-Entscheidung, den Modellnamen, die Nutzung, die Zeiten und jeden Fehler. Ein Aufruf kann viele Zustände auf einmal tragen (predict_batch), also muss ein Hook, der jede Entscheidung abdecken will, überctx.statesundctx.resultsiterieren;ctx.usageundctx.elapsed_mssind Summen für den Aufruf. Weil der Kontext veränderbar ist, kann ein Hook den Aufruf formen, nicht nur beobachten: den Zustand redigieren, die Fragen umschreiben, das Ergebnis ersetzen oder die Inferenz mit einer gecachten Antwort überspringen. -
Es gibt zwei Geltungsbereiche. Hooks von
Agentumschließen einen Vorwärtsdurchlauf; Hooks vonRouterumschließen Routing plus Inferenz und sehen zusätzlich den Modell-Lebenszyklus (on_route,on_load,on_evict). Das spiegelt die Trennung zwischen „Run-Hooks“ und „Agent-Hooks“ in anderen Agent-Frameworks wider.
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
Umfang auf einen Blick
Agent / ONNXAgent |
Router |
|
|---|---|---|
on_predict_start |
ja | ja |
on_predict_end |
ja | ja |
on_error |
ja | ja |
on_route |
nein | ja |
on_load |
nein | ja |
on_evict |
nein | ja |
laya.serve und der MCP-Server rufen Router.predict auf, also werden Router-Hooks für sie
automatisch ausgelöst. Agent-Hooks werden ausgelöst, wann immer der Router einen angehängten oder
gebauten Agenten ausführt.
Kompatibilität
- Ohne konfigurierte Hooks gibt es keine Verhaltensänderung. Der Pfad ohne Hooks ist regressionsgetestet.
- Alle Hook-Parameter sind Keyword-Argumente mit Standardwerten, sodass bestehende Aufrufe weiter funktionieren.
laya/hooks.pyist reines Python:import layazieht deswegen kein torch herein.- Hooks sind standardmäßig synchron. Ein
async def-Ereignis kann inAsyncHookverpackt oder als einfaches asynchrones Callable übergeben werden, und es läuft für dich bis zum Ende durch. hooks_timeoutbegrenzt einen langsamen Hook, damit er eine bediente Anfrage nicht aufhängen kann.- Halte Hooks schnell und nicht blockierend; siehe Fehler und
Muster für die Folgen für
laya.serve.
Siehe auch
examples/hooks/: ausführbare Hooks für Audit, Redaktion, Cache und Metriken.tests/test_hooks.py: die Verhaltensspezifikation.tests/test_hooks_api.py: die Absicherung der API-Stabilität.laya/hooks.py: die Implementierung.