场景与事件¶
TFRobot 的遥测系统需要回答两个基本问题:事件从哪里来(Scene)和发生了什么(Event)。这两个维度的组合构成了整个可观测性体系的基础语义。
设计背景¶
一个典型的 TFRobot 调用链路是 Robot → Brain → Chain → LLM/Tool/Memory。链路中每个组件都可能产生值得关注的运行时信息——LLM 返回了什么、Tool 执行是否成功、Memory 检索命中了多少结果。
如果只是把这些信息"发出去",接收方(Hook)会面临一个困境:它拿到一个事件,却不知道该如何处理。比如一个只关心 LLM Token 用量的 Hook,不应该被 Tool 的事件打扰;一个只在操作结束后才需要介入的 Hook,不应该在操作开始时就被触发。
Scene 和 Event 的设计正是为了解决这个问题:
- Scene(场景)提供空间维度的过滤——事件来自哪个组件
- Event(事件)提供时间维度的过滤——操作处于哪个阶段
两者结合,让 Hook 能够精确地订阅"在 LLM 生成完成后"或"在 Tool 执行出错时"这样的具体时刻,而不是淹没在全量事件流中。
场景 Scene¶
Scene 标识事件的来源组件。它与 TFRobot 的仿生架构一一对应:
| Scene | 对应组件 | 职责 |
|---|---|---|
Robot |
顶层机器人 | 接收用户输入,协调整个执行流程 |
Brain |
大脑 | 管理推理过程,调度 Chain 执行 |
Chain |
思维链 | 状态机驱动的推理单元 |
LLM |
大语言模型 | 调用模型进行文本生成 |
Tool |
工具 | 执行外部操作(搜索、计算等) |
Memory |
记忆 | 记忆的高层操作(检索、刷新、增强) |
MemoryStore |
记忆存储 | 记忆的底层存储操作(增删查序列化) |
Drive |
驱动 | 预留场景,尚未启用 |
Scene 在代码中定义为 Literal 类型,用于 EventContext 的 scene 字段:
EventScene: TypeAlias = Literal["Robot", "Brain", "Drive", "Memory", "MemoryStore", "Chain", "Tool", "LLM"]
Scene 的核心作用是路由:HookManager 根据 scene 字段决定将事件分发给哪些 Hook。当你通过 register_hook(hook, scene="LLM") 注册 Hook 时,只有 scene="LLM" 的事件才会触发该 Hook。
事件 Event¶
事件的生命周期模型¶
每个被监控的操作都遵循统一的四阶段生命周期:
BEFORE ──→ [操作执行] ──→ AFTER (正常完成)
├─→ RAISE (操作抛出异常)
└─→ ABORT (用户主动中止)
这个设计源自一个实际需求:仅靠"开始"和"结束"两个事件不够。在生产环境中,你需要区分三种截然不同的结束方式:
- AFTER:操作正常完成,EventContext 中包含返回值(如 LLM 的生成结果、Tool 的执行返回)
- RAISE:操作过程中抛出了异常,EventContext 中包含错误信息——你可能需要告警或记录
- ABORT:用户主动中止了操作(
TFUserInterruptError),这不是错误,而是正常的控制流——你可能只需要记录而不需要告警
如果把异常和中止混为一谈,监控系统就无法区分"LLM 接口挂了"和"用户按了取消",导致误报。
完整事件列表¶
Robot 事件¶
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_ROBOT_RUN |
before_robot_run |
Robot.run / async_run 执行前 |
AFTER_ROBOT_RUN |
after_robot_run |
Robot.run / async_run 正常完成 |
ROBOT_RUN_RAISE |
robot_run_raise |
运行期间抛出异常 |
ROBOT_RUN_ABORT |
robot_run_abort |
用户主动中止 |
Brain 事件¶
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_BRAIN_RUN |
before_brain_run |
Brain.run / async_run 执行前 |
AFTER_BRAIN_RUN |
after_brain_run |
Brain.run / async_run 正常完成 |
BRAIN_RUN_RAISE |
brain_run_raise |
运行期间抛出异常 |
BRAIN_RUN_ABORT |
brain_run_abort |
用户主动中止 |
Chain 事件¶
Chain 是事件最丰富的场景,因为思维链作为状态机驱动的推理核心,其运行状态最为复杂。
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_CHAIN_RUN |
before_chain_run |
单链执行前 |
AFTER_CHAIN_RUN |
after_chain_run |
单链正常完成 |
CHAIN_RUN_RAISE |
chain_run_raise |
单链执行期间抛出异常 |
CHAIN_RUN_ABORT |
chain_run_abort |
单链被用户中止 |
BEFORE_CHAINS_RUN |
before_chains_run |
多链(串行/并行/树/图)执行前 |
AFTER_CHAINS_RUN |
after_chains_run |
多链正常完成 |
CHAINS_RUN_RAISE |
chains_run_raise |
多链执行期间抛出异常 |
CHAINS_RUN_ABORT |
chains_run_abort |
多链被用户中止 |
CHAIN_TOKEN_LIMIT |
chain_token_limit |
上下文 Token 接近限制 |
CHAIN_COMPACT |
chain_compact |
触发上下文压缩 |
CHAIN_NON_BLOCKING_EXCEPTION |
chain_non_blocking_exception |
非阻塞异常(链可继续运行) |
CHAIN_BLOCKING_EXCEPTION |
chain_blocking_exception |
阻塞异常(链被迫终止) |
单链 vs 多链
CHAIN_RUN 系列对应单个 Chain 的执行;CHAINS_RUN 系列对应 SeqChains、ParallelChains 等多链编排的整体执行。两者的 EventContext 结构相同,但粒度不同。
LLM 事件¶
LLM 区分普通生成和流式输出两种模式,因为它们的监控需求不同:普通生成只需要关注"开始"和"结束";流式输出还需要监听中间的每一个 chunk(LLM_STREAMING 事件)。
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_LLM_GENERATE |
before_llm_generate |
普通生成前 |
AFTER_LLM_GENERATE |
after_llm_generate |
普通生成完成 |
LLM_GENERATE_RAISE |
llm_generate_raise |
普通生成期间抛出异常 |
LLM_GENERATE_ABORT |
llm_generate_abort |
普通生成被用户中止 |
BEFORE_LLM_STREAMING |
before_llm_streaming |
流式输出开始前 |
LLM_STREAMING |
llm_streaming |
流式输出的每个 chunk |
AFTER_LLM_STREAMING |
after_llm_streaming |
流式输出完成 |
LLM_STREAMING_RAISE |
llm_streaming_raise |
流式输出期间抛出异常 |
LLM_STREAMING_ABORT |
llm_streaming_abort |
流式输出被用户中止 |
Tool 事件¶
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_TOOL_RUN |
before_tool_run |
工具执行前 |
AFTER_TOOL_RUN |
after_tool_run |
工具执行完成 |
TOOL_RUN_RAISE |
tool_run_raise |
工具执行期间抛出异常 |
TOOL_RUN_ABORT |
tool_run_abort |
工具执行被用户中止 |
Memory 事件¶
Memory 场景覆盖三种高层操作:检索(recall)、刷新(refresh)、增强(enrich)。
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_MEMORY_RECALL |
before_memory_recall |
记忆检索前 |
AFTER_MEMORY_RECALL |
after_memory_recall |
记忆检索完成 |
MEMORY_RECALL_RAISE |
memory_recall_raise |
检索期间抛出异常 |
MEMORY_RECALL_ABORT |
memory_recall_abort |
检索被用户中止 |
BEFORE_MEMORY_REFRESH |
before_memory_refresh |
记忆刷新前 |
AFTER_MEMORY_REFRESH |
after_memory_refresh |
记忆刷新完成 |
MEMORY_REFRESH_RAISE |
memory_refresh_raise |
刷新期间抛出异常 |
MEMORY_REFRESH_ABORT |
memory_refresh_abort |
刷新被用户中止 |
BEFORE_MEMORY_ENRICH |
before_memory_enrich |
记忆增强前 |
AFTER_MEMORY_ENRICH |
after_memory_enrich |
记忆增强完成 |
MEMORY_ENRICH_RAISE |
memory_enrich_raise |
增强期间抛出异常 |
MEMORY_ENRICH_ABORT |
memory_enrich_abort |
增强被用户中止 |
MemoryStore 事件¶
MemoryStore 覆盖底层存储操作:增(add)、删(delete)、查(get)、清(clear)、序列化(serialization)、学习(learn)。
| 事件 | 值 | 触发时机 |
|---|---|---|
BEFORE_MEMORY_STORE_GET |
before_memory_store_get |
存储查询前 |
AFTER_MEMORY_STORE_GET |
after_memory_store_get |
存储查询完成 |
MEMORY_STORE_GET_RAISE |
memory_store_get_raise |
查询期间抛出异常 |
MEMORY_STORE_GET_ABORT |
memory_store_get_abort |
查询被用户中止 |
BEFORE_MEMORY_STORE_ADD |
before_memory_store_add |
存储添加前 |
AFTER_MEMORY_STORE_ADD |
after_memory_store_add |
存储添加完成 |
MEMORY_STORE_ADD_RAISE |
memory_store_add_raise |
添加期间抛出异常 |
MEMORY_STORE_ADD_ABORT |
memory_store_add_abort |
添加被用户中止 |
BEFORE_MEMORY_STORE_DELETE |
before_memory_store_delete |
存储删除前 |
AFTER_MEMORY_STORE_DELETE |
after_memory_store_delete |
存储删除完成 |
MEMORY_STORE_DELETE_RAISE |
memory_store_delete_raise |
删除期间抛出异常 |
MEMORY_STORE_DELETE_ABORT |
memory_store_delete_abort |
删除被用户中止 |
BEFORE_MEMORY_STORE_CLEAR |
before_memory_store_clear |
存储清空前 |
AFTER_MEMORY_STORE_CLEAR |
after_memory_store_clear |
存储清空完成 |
MEMORY_STORE_CLEAR_RAISE |
memory_store_clear_raise |
清空期间抛出异常 |
MEMORY_STORE_CLEAR_ABORT |
memory_store_clear_abort |
清空被用户中止 |
BEFORE_MEMORY_STORE_SERIALIZATION |
before_memory_store_serialization |
存储序列化前 |
AFTER_MEMORY_STORE_SERIALIZATION |
after_memory_store_serialization |
存储序列化完成 |
MEMORY_STORE_SERIALIZATION_RAISE |
memory_store_serialization_raise |
序列化期间抛出异常 |
MEMORY_STORE_SERIALIZATION_ABORT |
memory_store_serialization_abort |
序列化被用户中止 |
BEFORE_MEMORY_LEARN |
before_memory_learn |
记忆学习前 |
AFTER_MEMORY_LEARN |
after_memory_learn |
记忆学习完成 |
MEMORY_LEARN_RAISE |
memory_learn_raise |
学习期间抛出异常 |
MEMORY_LEARN_PROGRESS |
memory_learn_progress |
学习中间进度 |
MEMORY_LEARN_PROGRESS
学习操作是唯一使用 PROGRESS 事件而非 ABORT 事件的场景。这是因为学习是一个批量长时操作,需要报告中间进度(已处理数量、成功/失败计数等),而不仅仅是开始和结束。
EventContext:事件携带的上下文¶
每个事件都携带一个 EventContext,包含该事件的结构化信息。所有场景共享 BaseEventContext 的基础字段,各场景在此基础上扩展专属字段。
关于 EventContext 各场景字段的完整参考,参见 Event Hook — EventContext 参考。
这里重点说明两个容易混淆的字段:
| 字段 | 面向对象 | 用途 |
|---|---|---|
desc |
开发者 | 描述事件的性质(如"Before run"、"After generate"),与 scene + action 相关 |
info |
用户 | 事件的具体内容(如用户输入的文本、LLM 返回的结果),适合直接打印到日志 |
desc 帮助开发者在调试时快速定位事件的来源和阶段;info 帮助用户了解实际发生了什么。两者分离是因为开发者需要的信息粒度和用户需要的可读性是不同的。
事件如何产生:span_decorator¶
事件不需要业务代码手动触发。TFRobot 的各基类(Robot、Brain、Chain、LLM、Tool、Memory)在初始化时通过 decorate_span 方法,用 span_decorator 装饰器自动包装关键方法。
以 Robot 为例,decorate_span 的核心逻辑是:
# tfrobot/base.py
@classmethod
def decorate_span(cls) -> None:
decorated_run = span_decorator(
{"scene": "Robot", "desc": "Robot Run method"},
SpanEvent.BEFORE_ROBOT_RUN, # 方法执行前触发
SpanEvent.AFTER_ROBOT_RUN, # 方法正常完成触发
SpanEvent.ROBOT_RUN_RAISE, # 异常触发
SpanEvent.ROBOT_RUN_ABORT, # 用户中止触发
partial(cls._generate_context, desc="Before run"),
partial(cls._generate_context, desc="After run"),
)(cls.run)
setattr(cls, "run", decorated_run)
span_decorator 在被包装方法的执行前后自动构造 EventContext 并通过 TFSpan.add_event 发出事件。对于异常和用户中止,装饰器会捕获对应的异常类型并触发相应事件。
防重复包装
span_decorator 通过 __is_tf_span_wrapped__ 标记防止同一方法在继承链中被多次包装。子类如果没有覆写父类方法,不会重复添加装饰器。
与其他模块的协作¶
Scene + Event ──→ EventContext ──→ TFSpan.add_event ──→ HookManager ──→ Hook
(本文档) (本文档) (Trace 扩展) (Event Hook) (用户代码)
- Trace 扩展:TFSpan 的
add_event是事件进入 OpenTelemetry 和 HookManager 的入口 - Event Hook:Hook 通过 Scene 过滤事件,通过 Event 名称判断执行时机
- Meter 指标采集:指标采集本身也通过 Hook 机制实现,监听 LLM 事件采集 Token 用量
- 透传原始上下文:EventContext 的
baggage字段来自 OpenTelemetry Baggage,由调用方注入
扩展指南¶
如果内置事件无法满足需求,你可以在自己的组件中添加自定义事件。
简单方式:直接在 Span 上添加事件字符串,不需要修改 SpanEvent 枚举。你可以在任何拥有 Span 的地方调用 span.add_event("my_custom_event", attributes)。
完整方式:如果需要严格的类型安全和框架级集成,参见 扩展事件。