Hooks de prédiction
Les hooks te permettent d’observer ou de façonner chaque décision de Laya, sans le forker.
Ils sont la couture d’extension pour ce dont chaque déploiement réel a besoin : journal d’audit, masquage
des PII avant l’inférence, mise en cache, métriques, gating par confiance, surcharges de routage, et
transmission d’une décision à un service externe. Ils sont opt-in : sans hook configuré, le
comportement de Agent, Router et ONNXAgent est inchangé.
Ils ne servent pas qu’aux appels directs. Chaque runnable LangChain et LangGraph prend les mêmes cinq arguments par appel, donc un hook peut être attaché à un nœud d’un graphe plutôt qu’à tout l’agent.
Ce dossier est la référence complète. Commence ici, puis plonge dans la page dont tu as besoin :
| page | ce qu’elle contient |
|---|---|
| Référence de l’API | chaque classe, champ, paramètre et valeur par défaut |
| Cycle de vie | exactement quand chaque hook tourne, avec des organigrammes |
| Erreurs | hooks_raise, on_error, enchaînement des exceptions, matrice de défaillance |
| Motifs et anti-motifs | quoi faire, quoi éviter, et pourquoi |
| Exemples | des recettes à copier-coller pour chaque cas d’usage |
| Traçage | run_id, corrélation des spans, OpenTelemetry |
Démarrage rapide
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?"}})
Un objet peut implémenter n’importe quel sous-ensemble des événements du cycle de vie :
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()])
Les hooks peuvent aussi être ajoutés plus tard ou limités à un bloc :
agent.add_hook(tracer) # attach at runtime
with agent.hooks_installed(debug): # installed for the block, removed on exit
agent.system_one(state, questions)
Voir l’enregistrement à l’exécution. Pour un hook qui doit s’appliquer partout sans être passé à chaque appel, enregistre-le une fois avec les valeurs par défaut pour tout le processus :
from laya import hooks
hooks.set_default_hooks(hooks=[Tracer()])
Le modèle mental
Il y a trois idées.
-
Un hook est un appelable ou un objet. Une fonction simple est pratique pour un événement ; un objet est pratique pour plusieurs. Les deux se passent à
hooks=/on_predict_start=/on_predict_end=. -
Tous les hooks d’un appel partagent un même
PredictContextmutable. Il porte les états, les questions, les résultats, la décision de routage, le nom du modèle, l’usage, le timing et toute erreur. Un appel peut porter plusieurs états à la fois (predict_batch), donc un hook qui veut couvrir chaque décision doit itérerctx.statesetctx.results;ctx.usageetctx.elapsed_mssont des totaux pour l’appel. Comme le contexte est mutable, un hook peut façonner l’appel, pas seulement l’observer : masquer l’état, réécrire les questions, remplacer le résultat, ou sauter l’inférence avec une réponse en cache. -
Il y a deux portées. Les hooks
Agentenveloppent une passe avant ; les hooksRouterenveloppent le routage plus l’inférence et peuvent aussi voir le cycle de vie du modèle (on_route,on_load,on_evict). Cela reflète le découpage « hooks de run » vs « hooks d’agent » d’autres frameworks d’agents.
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
Portée en un coup d’œil
Agent / ONNXAgent |
Router |
|
|---|---|---|
on_predict_start |
oui | oui |
on_predict_end |
oui | oui |
on_error |
oui | oui |
on_route |
non | oui |
on_load |
non | oui |
on_evict |
non | oui |
laya.serve et le serveur MCP appellent Router.predict, donc les hooks Router se déclenchent
automatiquement pour eux. Les hooks Agent se déclenchent chaque fois que le Router exécute un agent
attaché ou construit.
Compatibilité
- Sans hook configuré, aucun changement de comportement. Le chemin non configuré est couvert par des tests de régression.
- Tous les paramètres de hook sont des arguments nommés avec des valeurs par défaut, donc les appels existants continuent de fonctionner.
laya/hooks.pyest du Python pur :import layane tire pas torch à cause de lui.- Les hooks sont synchrones par défaut. Un événement
async defpeut être enveloppé dansAsyncHook, ou passé comme un appelable async simple, et il s’exécute jusqu’au bout pour toi. hooks_timeoutborne un hook lent pour qu’il ne puisse pas bloquer une requête servie.- Garde les hooks rapides et non bloquants ; voir erreurs et motifs
pour les conséquences sur
laya.serve.
Voir aussi
examples/hooks/: hooks d’audit, de masquage, de cache et de métriques exécutables.tests/test_hooks.py: la spécification de comportement.tests/test_hooks_api.py: la garde de stabilité de l’API.laya/hooks.py: l’implémentation.