生命周期钩子参考#

除非另有说明,所有钩子都会收到AgentRunContext。生命周期钩子是返回 None 的普通异步函数。accept 是同步的,返回 bool。生命周期钩子的默认实现是空操作;中间件的默认实现会透明地调用下一层。只覆盖你的扩展需要的部分。

设置钩子#

每个请求运行一次,而不是每个 Agent 实例一次#

钩子

进入时的状态

预期操作

on_tool()

新的本地注册表已包含构造函数中的工具;服务端注册表为空。

通过 context.register_tool 或 context.register_server_tool 注册动态工具。

on_state()

所有动态工具都已注册;新输入尚未追加。

恢复历史记录并插入系统指令。

on_message()

历史记录已就绪;输入位于 context.input_message。

替换或校验当前输入;不要自行追加。

请求钩子#

成功和失败是两条不同的路径#

钩子

边界与约束

before_run()

转换后的输入已追加并发布;在这里初始化每个请求的工作。

after_run()

最终答案已就绪,且没有排队等待的输入。

on_success()

所有 after_run 钩子都已成功;该钩子先于 RUN_COMPLETED。释放成功路径上的状态。

on_error()

正在向外传播一个非取消类的请求错误。释放失败路径上的状态。

轮次钩子#

一个请求在每个模型/工具循环中构成一个轮次#

钩子

边界与约束

before_turn()

在 before_run 之后,或在上一个轮次的 after_turn 之后;位于压缩、before_model 和模型提供商调用之前。在这里修改的消息或工具只影响本轮次。

after_turn()

本轮次的 AssistantMessage 以及它所请求的每一条 ToolMessage 都已追加并发布。该钩子会收到开启本轮次的助手消息,包括工具调用失败或被 steering 取代的情况。最终答案在 after_run 之前结束自己的轮次。

模型与工具钩子#

在一个请求中可能执行多次#

钩子

边界与约束

before_model()

接收 context 和 ModelRequest;可以检查它,也可以修改 context.state.messages、context.tools 和 context.server_tools。

after_model()

完整的 AssistantMessage 已追加;该钩子收到包含用量信息的 ModelResponse。

before_tool()

在一次工具调用之前。抛出异常会让请求在执行之前就失败。

after_tool()

工具已执行完毕,但 ToolMessage 尚未追加。可以检查单独的 error 参数,并在上下文和持久化收到工具结果之前修改它。

中间件钩子#

包装整个操作,而不是只观察它的一侧#

钩子

边界与约束

on_model_request()

包装模型提供商的流式输出。把 ModelRequest 传给 call_next,并在提前退出时关闭返回的迭代器。

on_tool_call()

包装一个已注册的本地工具处理函数。它可以调整参数、转换或短路处理结果,也可以抛出普通的工具失败。

这些钩子使用与生命周期钩子相同的扩展优先级顺序,优先级更低者构成外层的中间件。模型提供商托管的工具在 on_model_request 内部运行,不经过本地的 on_tool_call 边界。

向外发出事件#

任何生命周期钩子都可以用 await context.emit(AgentEvent(...)) 发布可见的进度。事件会按钩子优先级顺序,恰好在那个位置进入属于本次请求的队列。运行时的内部方法和扩展从不对外暴露嵌套的 AgentEvent 异步生成器;只有stream()会排空队列并把事件产出给调用方。

自定义输出不会仅仅因为它的载荷里写着“working”就变成一次阶段切换。不要自行合成由核心循环拥有的 MODEL_STARTED、TOOL_STARTED 或终止事件。对于不应到达 UI 的扩展间内部通知,请改用 context.publish。

before_model 接收 (context, request)。运行时会为每个扩展刷新请求消息和两个工具注册表,并在调用模型提供商之前再刷新一次。请求的字段是冻结的;要影响后续钩子和模型提供商,请修改 context.state.messages、context.tools 或 context.server_tools。传入的 request 是进入时的浅层视图,不会反映之后注册表的变化。

通知与输入钩子#

这些钩子不是 UI 流式输出回调#

钩子

约定

on_event()

请求内部发布 ExtensionEvent 时会等待该钩子;可以检查具体的事件类型。

accept()

从外部调用方接收 config 和 ExternalEvent,可能位于另一个线程。返回是否接受投递。

处理待返回的响应时,请使用 ExternalEventExtension,而不要自己写跨线程的 Future 处理逻辑。如果要覆盖它的 on_event 或 on_error 方法,请调用 super(),让基类能够唤醒并释放待处理的等待。

优先级、命名与异常#

priority = 100 是默认值。在同一个钩子阶段内,值更小的先运行。不允许注册两个同名的实例。需要时,可以通过 extension.name 为独立配置的实例指定明确的名字。

如果某个钩子失败,之前已完成的钩子不会被回滚。清理必须幂等,并能容忍部分初始化。取消有自己内部的 RunCancelledEvent,而不是 on_cancel 方法。参见状态、并发与清理。