尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Laya Prediction Hooks API 完全参考:在 Agent、Router 与 ONNXAgent 上观测与改写每一次决策

发布时间:2026/9/29 20:57:29

资讯中心
01
ARTICLE

Laya Prediction Hooks API 完全参考:在 Agent、Router 与 ONNXAgent 上观测与改写每一次决策

Laya Prediction Hooks API 完全参考:在 Agent、Router 与 ONNXAgent 上观测与改写每一次决策
人工智能NLP强化学习【免费下载链接】layaNon-autoregressive System 1 decision engine. Typed choice, score and yes/no decisions over any text in a single forward pass, in 100 languages, with a router that picks the right checkpoint per request.项目地址https://gitcode.com/gh_mirrors/lay/laya点击查看免费下载本文是 Laya 钩子系统的 API 级参考指南逐项覆盖PredictContext的字段语义、六事件Hook协议、Agent/Router/ONNXAgent三套运行时与laya.serve、MCP 服务器的全部配置入口、事件载荷矩阵、校验规则与底层辅助函数并配套给出laya/hooks.py、laya/agent.py、laya/router.py的源码级实现依据与tests/test_hooks.py、tests/test_hooks_api.py的行为契约。读完本文你可以不修改任何框架代码就在 Laya 上落地审计日志、推理前 PII 脱敏、决策缓存、指标采集、路由覆盖与外部服务转发等生产级能力。本文是 hooks 文档族的 API 参考页对应同一目录下的 生命周期、错误处理、模式与反模式、实例合集 与 链路追踪 共同构成完整参考。文档中的快速上手与心智模型见 hooks 索引可运行的完整示例见 examples/hooks/实现与规格见 laya/hooks.py、tests/test_hooks.py、tests/test_hooks_api.py。一、为什么需要 Hook一个可观测、可塑形的决策扩展缝Laya 是面向文本的 System 1 非自回归决策引擎单次前向即可输出带类型的 choice / score / yes-no 决策。生产部署中几乎每个环节都需要在推理链路之外做额外处理审计留痕、推理前的 PII 脱敏、结果缓存、指标统计、置信度门控、路由改写以及把决策转发给外部服务。Hooks 就是为此设计的扩展缝extension seam不 fork 仓库、不改内部代码通过注入回调即可观测或改写每一次决策。Hooks 严格可选opt-in——不配置任何 hook 时Agent、Router、ONNXAgent的行为与未启用钩子时完全一致这条无钩子路径在 tests/test_hooks.py 中作为回归基线被反复验证例如 defaults/unset hooks are a no-op 检查。同时所有 hook 参数都是带默认值的关键字参数已有调用代码无需改动。从源码看钩子系统的全部逻辑集中在 laya/hooks.py纯 Pythonimport laya不会因此拉入 torch三个运行时Agent、Router、ONNXAgent都混入了HookRegistry并通过compose_hooksdispatch在predict_batch、system_one、route等入口的 try/finally 结构中调度事件。心智模型三句话一个 hook 可以是可调用对象也可以是实现了任意事件方法的普通对象。前者适合只关心单个事件如on_predict_start后者适合同时处理多个事件两者都通过hooks/on_predict_start/on_predict_end传入。同一次调用中的所有 hook 共享同一个可变的PredictContext。它携带 states、questions、results、路由决策、模型名、用量、耗时与错误。因为可变hook 不仅能看调用还能塑形调用改写 state、重写 questions、替换结果甚至用缓存结果skip()跳过推理。存在两种作用域。Agent钩子包裹一次前向Router钩子包裹路由 推理整条链路并能看到模型生命周期on_route、on_load、on_evict。这与其它 Agent 框架中 run hooks 与 agent hooks 的划分对应。二、PredictContext同一次调用共享的可变上下文PredictContext每次公开调用创建一次并传递给该调用的每一个 hook。它是mutable可变的hook 可以改写states、questions与resultson_route可以改写decision。它使用同一性相等eqFalse因此 context 可哈希且两个 context 永不相等——这在 tests/test_hooks.py 的 context semantics 一节有专门断言hash(_c1)是 int_c1 _c2恒为False源码见 laya/hooks.py。dataclass(eqFalse) class PredictContext: states: List[Any] questions: Dict[str, Any] run_id: str uuid4 hex results: Optional[List[Dict[str, Any]]] None decision: Optional[Dict[str, Any]] None model: Optional[str] None agent: Any None router: Any None max_len: Optional[int] None head_max_len: Optional[int] None usage: Optional[Dict[str, int]] None started_at: float perf_counter() elapsed_ms: Optional[float] None error: Optional[BaseException] None字段逐个说明字段类型何时被设置可变性含义stateslist总是可变start 阶段本次调用的 states。system_one/Router.predict传入一个predict_batch传入多个。start hook 可以替换整个列表questionsdict总是可变start 阶段问题定义。start hook 可以替换整个 dictrun_idstr总是不可变本次调用所有 hook 共享的唯一 id用于关联事件与 spanresultslist \| Noneend以及 skip 时可变end 阶段每个 state 一个结果 dict形状与system_one的返回值一致。推理完成前为Nonedecisiondict \| None仅 Router可变route 阶段选中 checkpoint 的RouteDecision一个 dictmodelstr \| None总是不可变checkpoint idAgent时为Agent.model_idRouter时为解析后的别名如englishagentAgent \| ONNXAgent \| Nonepredict 事件不可变实际应答调用的运行时routerRouter \| NoneRouter 事件不可变有 Router 参与时的 Router 实例max_lenint \| None总是可变start 阶段本次调用的编码器 token 预算。None表示使用 agent 配置head_max_lenint \| None总是可变start 阶段本次调用的问题头 token 预算。None表示使用 agent 配置usagedict \| Noneend可变end 阶段{input_tokens, output_tokens}对本次调用各 state 求和started_atfloat总是不可变调用开始时的time.perf_counter()elapsed_msfloat \| Noneend不可变整个调用的墙钟耗时毫秒errorBaseException \| None失败路径不可变异常对象在on_error与on_predict_end之前被设置从源码看run_id由field(default_factorylambda: uuid.uuid4().hex)生成laya/hooks.pystarted_at由time.perf_counter()工厂生成laya/hooks.py。在 tests/test_hooks_api.py 中PredictContext的 14 个字段名与默认值states/questions必填、其余可选字段默认None、run_id有工厂都被逐一钉死作为 API 稳定性护栏。PredictContext.skip(results)短路推理skip(results)从 start hook 中调用直接设置ctx.results从而跳过前向传播on_predict_end仍然执行并返回这些预设结果。签名与实现见 laya/hooks.py行为契约见 tests/test_hooks.py 的 caching short-circuit 一节跳过时_forward_calls为空、end 仍被调用。def cache_read(ctx): hit CACHE.get(key(ctx.states[0], ctx.questions)) if hit is not None: ctx.skip([hit]) # list of per-state results, same shape as predict_batchs return在Router上被 skip 的载荷会获得一个routing键不会覆盖已有的从而保证Router.predict的返回形状始终稳定。这一点在 tests/test_hooks.py 的 Router skip 用例中验证skipped.get(routing, {}).get(model) english。一个可运行的缓存实现见 examples/hooks/cache.pycache_read命中时ctx.skip([hit])cache_write在on_predict_end把结果写回CACHE。三、Hook 协议六事件与 BaseHookHook是一个typing.Protocol。实现其中任意方法子集即可其余方法会被跳过。class Hook(Protocol): def on_predict_start(self, ctx: PredictContext) - None: ... def on_predict_end(self, ctx: PredictContext) - None: ... def on_route(self, ctx: PredictContext) - None: ... def on_load(self, ctx: PredictContext) - None: ... def on_evict(self, ctx: PredictContext) - None: ... def on_error(self, ctx: PredictContext) - None: ...事件一览事件触发位置运行时机可以改动on_predict_startAgent, Router分词/前向之前states、questions或skip()on_predict_endAgent, Router结果就绪之后成功或失败resultson_routeRouter检测之后、加载之前decisionon_loadRoutercheckpoint 构建完成后不可改仅观测on_evictRoutercheckpoint 释放后不可改仅观测on_errorAgent, Routerpredict 调用失败时不可改仅观测一个 hook 可以自由定义额外的属性与方法调度时只认这六个事件名。如果某个事件被定义为不可调用对象配置会在校验阶段快速失败见下文 校验。六事件元组HOOK_EVENTS定义于 laya/hooks.pytests/test_hooks_api.py 断言其集合与顺序。BaseHook具象的空操作基类BaseHook是协议对应的具体类每个事件都有一个 no-op 方法体。子类化它并只覆写你关心的事件即可。from laya import BaseHook class Audit(BaseHook): def on_predict_end(self, ctx): ship(ctx.run_id, ctx.results)选择建议需要结构化类型任何具有正确方法的对象时用Hook需要显式基类以便继承并调用super()时用BaseHook。BaseHook的六个空方法在 laya/hooks.py 中逐一实现测试中一个裸BaseHook()实例被证明是无害的tests/test_hooks.py 的 BaseHook/no-op instance is harmless。四、便利类型与配置入口PredictHook 便利类型PredictHook Callable[[PredictContext], None]PredictHook是配合on_predict_start/on_predict_end使用的普通可调用对象类型。传入单个 callable 或一个 callable 序列均可每个都会被包装成最小 hook_StartAdapter/_EndAdapter见 laya/hooks.py。统一的五个配置参数每一个入口都接受同一组五个 hook 参数。hooks接受一个对象或对象序列on_predict_start/on_predict_end接受一个 callable 或序列。参数类型默认值含义hooksHook \| Sequence[Hook] \| NoneNone生命周期钩子六个事件任意组合on_predict_startPredictHook \| Sequence[PredictHook] \| NoneNone单事件的便利 callableon_predict_endPredictHook \| Sequence[PredictHook] \| NoneNone单事件的便利 callablehooks_raiseboolTrueTruehook 抛出的异常向上传播False告警并继续hooks_concurrentboolTrueFalse在锁下逐个串行派发 hook这五个键值连同默认值被 tests/test_hooks_api.py 的HOOK_KEYS映射钉死逐一对Agent.__init__、load、Router.__init__、ONNXAgent.__init__校验。hooks_concurrentFalse时各运行时构造一个threading.RLock见 laya/agent.py 与 laya/router.py派发时用该锁串行化每个 hook 调用。Agent 配置面Agent( model_id_or_pathconvaiinnovations/laya, deviceNone, tokenNone, subfolderNone, fastFalse, compileFalse, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseTrue, hooks_concurrentTrue, ) load(..., hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseTrue, hooks_concurrentTrue) agent.predict_batch(states, questions, batch_sizeNone, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseNone, max_lenNone, head_max_lenNone, sort_by_lengthFalse) agent.system_one(state, questions, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseNone, max_lenNone, head_max_lenNone) agent.predict(...) # alias of system_one单次调用方法上的hooks_raise默认为None含义是使用实例级取值。hooks_concurrent仅存在于实例级。max_len/head_max_len是本次调用的 token 预算覆盖start hook 也可以改写ctx.max_len/ctx.head_max_len。在 laya/agent.py 的predict_batch实现中compose_hooks先组合出有效钩子列表PredictContext携带modelself.model_id, agentself与 token 覆盖随后在try/finally中依次dispatchstart / error / end 事件_encode_state会把ctx.max_len/ctx.head_max_len透传为本次调用的编码预算laya/agent.py。system_one是predict_batch单 state 特例Agent.predict is Agent.system_one在 tests/test_hooks_api.py 中被断言为同一函数因此它继承全部钩子与相同的生命周期此时ctx.states [state]。Router 配置面Router( modelsNone, deviceNone, tokenNone, max_loaded2, defaultenglish, auto_task_detectionFalse, standalone_reposFalse, preloadFalse, lang_guessNone, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseTrue, hooks_concurrentTrue, ) router.route(state, questionsNone, modelNone, taskNone, langNone, lang_guessNone, hooksNone, hooks_raiseNone) router.predict(state, questions, modelNone, taskNone, langNone, lang_guessNone, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseNone, max_lenNone, head_max_lenNone) router.system_one(...) # alias of predict router.load(name) # builds on first use; fires on_load router.preload(namesNone) # builds several; fires on_load per build router.unload(nameNone) # frees one or all; fires on_evict router.attach(name, agent) # registers an existing agent; does not fire on_load router.loaded # list of resident checkpoint namesroute/predict上的单次调用hooks应用于整个调用包括on_route。route()是公开 API调用它会用已安装钩子加单次调用hooks派发on_route。Router 钩子的底层调度在 laya/router.py 中清晰可见route()构造PredictContext(states[state], questions..., decisiondecision, routerself)并dispatch(active, on_route, ctx)laya/router.pypredict()在route之后load(decision[model])构建 agent再以modeldecision[model], agentagent, routerself构造上下文派发 predict 事件laya/router.pyload/_dispatch_lifecycle在释放内部锁之后派发on_load/on_evictlaya/router.py。tests/test_hooks.py 的 Router 部分验证了on_route可替换决策ctx.decision RouteDecision(modelmultilingual, ...)后返回值随之改变、on_load/on_evict按构建/逐出触发以及 per-call hooks 同样作用于on_route。ONNXAgent 配置面ONNXAgent(model_id_or_path, onnx_pathlaya.onnx, subfolderNone, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseTrue, hooks_concurrentTrue) onnx_agent.system_one(state, questions, hooksNone, on_predict_startNone, on_predict_endNone, hooks_raiseNone, max_lenNone, head_max_lenNone) onnx_agent.predict(...) # alias of system_oneONNXAgent没有 Router因此只暴露 predict 级别的事件。其钩子行为在 tests/test_hooks.py 的 ONNXAgent parity 一节验证start/end 触发、ctx.model携带model_id、skip短路推理。五、运行时注册构造之后仍可增删与作用域化每个运行时都混入了HookRegistrylaya/hooks.py因此钩子可以在构造之后添加、移除或临时作用域化。变更线程安全调用读取的是列表的快照因此增删钩子绝不会干扰进行中的调用。agent.add_hook(tracer) # one hook or a sequence; returns self for chaining agent.remove_hook(tracer) # by identity; True if it was installed with agent.hooks_installed(debug): # installed for the block, removed on exit agent.system_one(state, questions)add_hook接受与hooks相同的对象不接受裸 callable返回self以便链式调用。remove_hook按同一性移除返回True表示它曾被安装。hooks_installed接受任意数量的 hook 对象或序列在with块退出时包括块内抛异常恢复先前的列表。行为契约在 tests/test_hooks.py 的 dynamic registration 一节完整覆盖add_hook触发、remove_hook后不再触发、未知对象返回False、序列按序触发、hooks_installed仅在块内生效以及 Router 上的add_hook同样生效。六、进程级默认钩子一处注册处处生效laya.hooks维护一个小的进程级注册表这样 tracer、指标 hook 或租户标记器就不必被手动穿线到每一个Agent和Router构造中。执行顺序是默认钩子先跑然后实例钩子最后单次调用钩子。from laya import hooks hooks.set_default_hooks(hooks[Tracer()]) # replaces the set, accepts the hooks arguments hooks.add_default_hook(Metrics()) # appends hooks.clear_default_hooks() # removes everything hooks.default_hooks() # a copy of the current list hooks.compose_hooks(agent.hooks) # defaults installed (advanced)默认钩子作用于每一个事件包括 Router 生命周期事件on_load与on_evict。注册表在调用时被读取因此构造Agent/Router之后设置的钩子仍然生效。没有实例级的退出开关调用clear_default_hooks()才能关闭进程级集合。实现细节值得注意_DEFAULT_HOOKS列表由_DEFAULT_HOOKS_LOCK保护compose_hooks在调用时读取注册表laya/hooks.py并支持_SKIP_DEFAULTS这个ContextVar实现按上下文跳过默认钩子。set_default_hooks/add_default_hook/clear_default_hooks/default_hooks/compose_hooks全部位于laya.hooks而不在顶层导出tests/test_hooks_api.py 专门断言了这一 API 布局。tests/test_hooks.py 的 process-wide defaults 一节验证了顺序default → installed → per-call、Router 与predict_batch路径也接收默认钩子、以及默认钩子覆盖on_load/on_evict生命周期。七、Validation校验规则配置在钩子被归一化时校验——实例钩子在构造时单次调用钩子在调用时。以下情况抛出TypeError情形消息传入类而不是实例hooks entries must be instances, not classes; ...对象未实现六个事件中的任何一个hooks entries must implement at least one of ...事件属性不可调用hooks entry X.on_predict_start must be callable, got inton_predict_start/on_predict_end不可调用on_predict_start must be callable, got inthooks不接受裸 callable因为裸 callable 无法说明它服务于哪个事件请为它们使用on_predict_start/on_predict_end。校验实现在 laya/hooks.py 的normalise_hooks中三类检查依次是实例而非类、至少实现一个事件、事件属性可调用。适配器构造器_StartAdapter/_EndAdapter对非 callable 输入直接抛TypeErrorlaya/hooks.py。tests/test_hooks.py 的 validation 一节逐条验证拒绝类、拒绝裸 callable、拒绝非 callable 的on_predict_start、拒绝事件属性为非 callable 的对象。错误处理策略的完整矩阵hooks_raise的行为、异常链见 errors.md。八、事件载荷矩阵每个事件能看到什么哪些字段被填充按事件与运行时区分事件运行时statesquestionsdecisionmodelagentrouterresultsusageelapsed_mserroron_predict_startAgent✓✓–✓✓–––––on_predict_startRouter✓✓✓✓✓✓––––on_predict_endAgent✓✓–✓✓–✓成功时✓失败时on_predict_endRouter✓✓✓✓✓✓✓成功时✓失败时on_error两者✓✓✓ (Router)✓✓✓ (Router)–––✓on_routeRouter✓✓✓––✓––––on_loadRouter[]{}–✓✓✓––––on_evictRouter[]{}–✓–✓––––时间语义的细节on_predict_end在成功路径上能看到results。失败路径上results为None——除非 start hook 通过skip()设置了它们——因此usage也为None它由results推导elapsed_ms始终被设置。on_error在计算elapsed_ms和usage的finally块之前运行因此两者在其间均为None。请改从on_predict_end读取耗时与用量。run_id始终被填充。这些时序与 laya/agent.py 的实现逐条对应ctx.error exc后先派发on_errorfinally中计算elapsed_ms、用aggregate_usage(ctx.results)汇总usage、再派发on_predict_end。同一ctx对象贯穿 start、error、end 三个事件所以run_id可以关联三者end hook 可以直接读ctx.error。tests/test_hooks.py 用大量断言钉死了这套矩阵例如 start 阶段results为None、end 的results就是返回对象、usage被聚合、失败路径 end 仍执行且能看到ctx.error、on_error抛错不掩盖原始异常而只是链入__context__。九、高级辅助函数以下函数为内部使用接口稳定但多数用户不需要HOOK_EVENTS # tuple of the six event names, in dispatch order normalise_hooks(hooksNone, on_predict_startNone, on_predict_endNone) - list dispatch(hooks, event, ctx, *, raise_errorsTrue, lockNone) - None aggregate_usage(results) - {input_tokens: int, output_tokens: int}normalise_hooks把一个hooks对象/序列和两个便利 callable 展开为一个有序列表。展开后的顺序是hooks序列依序然后是on_predict_start适配器最后是on_predict_end适配器laya/hooks.py。实例钩子在构造时归一化一次单次调用参数随后追加因此单次调用钩子总是最后运行。dispatch对每个实现了该事件的 hook 调用event应用 raise 策略与锁。raise_errorsFalse时告警并继续适合不允许拖垮请求的遥测类钩子有锁时在锁内逐个调用laya/hooks.py。aggregate_usage把每个 state 的用量块求和为一个总量laya/hooks.py。from laya.hooks import normalise_hooks, dispatch, PredictContext hooks normalise_hooks(on_predict_start[log, redact]) ctx PredictContext(states[...], questions{...}) dispatch(hooks, on_predict_start, ctx)这套组合正是 laya/agent.py 与 laya/router.py 内部执行的同一模式因此可以视为手写一个迷你运行时的模板。十、Hook 在服务与 MCP 场景中的自动生效一个容易被忽略但重要的集成事实laya.serve与 MCP 服务器通过Router.predict调用因此 Router 钩子会自动对它们生效Router 运行已附加或已构建的 Agent 时Agent 钩子也会触发。这意味着你可以在服务层统一配置脱敏、审计与指标钩子而不必改动 serve 代码。相关生命周期细节laya.serve下 hook 失败的影响见 errors.md 与 patterns.md。关于兼容性承诺不配置钩子即零行为变更该无钩子路径被回归测试覆盖所有钩子参数均为带默认值的关键字参数旧调用无需改动laya/hooks.py 是纯 Pythonimport laya不会因它拉入 torch钩子为同步执行请保持其快速且非阻塞——patterns.md 对laya.serve下的后果有专门讨论。十一、快速起步与最小示例把上面所有 API 串起来的最小完整示例可运行首次运行会下载 checkpointimport laya def log(ctx): print(ctx.model, ctx.results[0][answers], ctx.elapsed_ms) agent laya.load(convaiinnovations/laya, on_predict_endlog) 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()])可运行的完整示例审计、脱敏、缓存、OTel 指标见 examples/hooks/——audit.py 记录每次决策并可选转发外部服务redact.py 在推理前剥离邮箱/电话cache.py 命中缓存即ctx.skip()跳过前向otel.py 输出计数与延迟直方图。每个示例都加载真实 checkpoint首次运行会下载模型。十二、进一步阅读Lifecycle每个事件在何时运行含逐入口流程图与顺序规则。Errors失败矩阵与异常链规则。Patterns and anti-patterns如何良好地组织钩子。Examples每种用例的复制粘贴配方。Tracingrun_id、span 关联与 OpenTelemetry。行为规格tests/test_hooks.pyAPI 稳定性护栏tests/test_hooks_api.py核心实现laya/hooks.py。赞分享人工智能NLP强化学习【免费下载链接】layaNon-autoregressive System 1 decision engine. Typed choice, score and yes/no decisions over any text in a single forward pass, in 100 languages, with a router that picks the right checkpoint per request.项目地址https://gitcode.com/gh_mirrors/lay/laya点击查看免费下载相关推荐Laya API完全参考Agent与Router全部核心方法及参数详解Laya API完全参考Agent与Router全部核心方法及参数详解 本文是 Laya API 的完整参考指南。Laya 是一个多语言、非自回归的 Syst人工智能NLP强化学习Laya Python API 参考指南Agent、Router、Helpers 与 LangChain 组件全解析Laya Python API 参考指南Agent、Router、Helpers 与 LangChain 组件全解析 Laya 是一个多语言、非自回归non人工智能NLP强化学习laya Agent 推理运行时完全指南Agent / load / RLAgent / ONNXAgent 加载与类型化决策laya Agent 推理运行时完全指南Agent / load / RLAgent / ONNXAgent 加载与类型化决策 导读 docs/referen人工智能NLP强化学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。