Hooks предсказаний
Hooks позволяют наблюдать за каждым решением Laya или формировать его, не делая форк.
Это шов расширения для всего, что нужно каждому реальному развёртыванию: журналирование аудита,
редактирование PII до инференса, кэширование, метрики, gating по уверенности, переопределения
маршрутизации и пересылка решения во внешний сервис. Они opt-in: без настроенных hooks поведение
Agent, Router и ONNXAgent не меняется.
Они нужны не только для прямых вызовов. Каждый runnable из LangChain и LangGraph принимает те же пять аргументов на вызов, поэтому hook можно привязать к одному узлу графа, а не ко всему агенту.
Эта папка — полный справочник. Начните здесь, затем переходите на нужную страницу:
| страница | что в ней |
|---|---|
| Справочник API | каждый класс, поле, параметр и значение по умолчанию |
| Жизненный цикл | точно, когда запускается каждый hook, со схемами |
| Ошибки | 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()])
Hooks также можно добавить позже или ограничить блоком:
agent.add_hook(tracer) # attach at runtime
with agent.hooks_installed(debug): # installed for the block, removed on exit
agent.system_one(state, questions)
Смотрите регистрацию во время выполнения. Для hook, который должен применяться везде, без прокидывания через каждый вызов, зарегистрируйте его один раз с помощью общих настроек процесса:
from laya import hooks
hooks.set_default_hooks(hooks=[Tracer()])
Мысленная модель
Есть три идеи.
-
Hook — это вызываемый объект или объект. Обычная функция удобна для одного события; объект — для нескольких. Оба передаются в
hooks=/on_predict_start=/on_predict_end=. -
Все hooks одного вызова разделяют один изменяемый
PredictContext. Он несёт состояния, вопросы, результаты, решение маршрутизации, имя модели, использование, тайминги и любую ошибку. Вызов может нести много состояний сразу (predict_batch), поэтому hook, который намерен покрыть каждое решение, должен перебиратьctx.statesиctx.results;ctx.usageиctx.elapsed_ms— это итоги по вызову. Поскольку контекст изменяем, hook может формировать вызов, а не только наблюдать: редактировать состояние, переписывать вопросы, заменять результат или пропускать инференс с кэшированным ответом. -
Есть две области видимости. Hooks
Agentоборачивают прямой проход; hooksRouterоборачивают маршрутизацию плюс инференс и могут также видеть жизненный цикл модели (on_route,on_load,on_evict). Это повторяет разделение «hooks запуска» и «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, поэтому hooks Router срабатывают для них
автоматически. Hooks Agent срабатывают всегда, когда Router запускает присоединённого или
встроенного агента.
Совместимость
- Без настроенных hooks поведение не меняется. Несконфигурированный путь покрыт регрессионными тестами.
- Все параметры hooks — это именованные аргументы со значениями по умолчанию, поэтому существующие вызовы продолжают работать.
laya/hooks.py— чистый Python: из-за негоimport layaне тянет torch.- Hooks по умолчанию синхронны. Событие
async defможно обернуть вAsyncHookили передать как обычный асинхронный вызываемый объект, и оно выполнится до конца за вас. hooks_timeoutограничивает медленный hook, чтобы он не мог подвесить обслуживаемый запрос.- Держите hooks быстрыми и неблокирующими; о последствиях для
laya.serveсмотрите ошибки и паттерны.
Смотрите также
examples/hooks/: исполняемые hooks аудита, редактирования, кэша и метрик.tests/test_hooks.py: спецификация поведения.tests/test_hooks_api.py: страховка стабильности API.laya/hooks.py: реализация.