Documentação

Hooks de predição

Os hooks deixam-te observar ou moldar cada decisão que o Laya toma, sem lhe fazer fork.

São o ponto de extensão para aquilo de que qualquer implementação real precisa: registo de auditoria, censura de PII antes da inferência, colocação em cache, métricas, gating por confiança, substituições de encaminhamento e encaminhamento de uma decisão para um serviço externo. São opt-in: sem hooks configurados, o comportamento de Agent, Router e ONNXAgent fica inalterado.

Não servem só para chamadas diretas. Cada runnable de LangChain e LangGraph aceita os mesmos cinco argumentos por chamada, por isso um hook pode ser ligado a um nó de um grafo em vez de ao agente inteiro.

Esta pasta é a referência completa. Começa aqui e depois aprofunda a página de que precisas:

página o que contém
Referência da API todas as classes, campos, parâmetros e valores predefinidos
Ciclo de vida exatamente quando corre cada hook, com fluxogramas
Erros hooks_raise, on_error, encadeamento de exceções, matriz de falhas
Padrões e antipadrões o que fazer, o que evitar e porquê
Exemplos receitas prontas a copiar para cada caso de uso
Tracing run_id, correlação de spans, OpenTelemetry

Início rápido

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?"}})

Um objeto pode implementar qualquer subconjunto dos eventos do ciclo de vida:

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()])

Os hooks também podem ser acrescentados mais tarde ou limitados a um bloco:

agent.add_hook(tracer)               # attach at runtime
with agent.hooks_installed(debug):   # installed for the block, removed on exit
    agent.system_one(state, questions)

Vê o registo em runtime. Para um hook que deva aplicar-se em todo o lado sem o passar por todas as chamadas, regista-o uma vez com as predefinições para todo o processo:

from laya import hooks

hooks.set_default_hooks(hooks=[Tracer()])

O modelo mental

Há três ideias.

  1. Um hook é um invocável ou um objeto. Uma função simples é cómoda para um evento; um objeto é cómodo para vários. Ambos são passados a hooks= / on_predict_start= / on_predict_end=.

  2. Todos os hooks de uma chamada partilham um mesmo PredictContext mutável. Transporta os estados, as perguntas, os resultados, a decisão de encaminhamento, o nome do modelo, o usage, a temporização e qualquer erro. Uma chamada pode transportar muitos estados ao mesmo tempo (predict_batch), por isso um hook que queira cobrir cada decisão tem de iterar ctx.states e ctx.results; ctx.usage e ctx.elapsed_ms são totais da chamada. Como o contexto é mutável, um hook pode moldar a chamada, e não apenas observá-la: censurar o estado, reescrever as perguntas, substituir o resultado, ou saltar a inferência com uma resposta em cache.

  3. Há dois âmbitos. Os hooks de Agent envolvem uma passagem direta; os hooks de Router envolvem o encaminhamento mais a inferência e também podem ver o ciclo de vida do modelo (on_route, on_load, on_evict). Isto espelha a divisão entre «hooks de execução» e «hooks de agente» de outras frameworks de agentes.

                             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

Âmbito num relance

Agent / ONNXAgent Router
on_predict_start sim sim
on_predict_end sim sim
on_error sim sim
on_route não sim
on_load não sim
on_evict não sim

O laya.serve e o servidor MCP chamam Router.predict, por isso os hooks de Router disparam para eles automaticamente. Os hooks de Agent disparam sempre que o Router corre um agente ligado ou construído.

Compatibilidade

  • Sem hooks configurados não há alteração de comportamento. O caminho sem configuração está coberto por testes de regressão.
  • Todos os parâmetros dos hooks são argumentos de palavra-chave com valores predefinidos, por isso as chamadas existentes continuam a funcionar.
  • laya/hooks.py é Python puro: import laya não arrasta a torch por causa dele.
  • Os hooks são síncronos por predefinição. Um evento async def pode ser envolvido num AsyncHook, ou passado como um invocável assíncrono simples, e corre até ao fim por ti.
  • hooks_timeout limita um hook lento para que não possa bloquear um pedido servido.
  • Mantém os hooks rápidos e sem bloqueios; vê erros e padrões para as consequências no laya.serve.

Ver também