跳转到内容

事件总线与遥测

学习目标

理解 CrewAI 的事件总线架构——单例模式、双执行器、依赖图执行计划、事件懒加载,以及 OpenTelemetry 遥测的集成方式。


项目实践

CrewAIEventsBus 单例

crewai_event_bus: Final[CrewAIEventsBus] = CrewAIEventsBus()

双执行器

  • Sync 处理器在 ThreadPoolExecutor(max_workers=10) 执行
  • Async 处理器在独立的后台 asyncio.EventLoop 执行
  • 延迟初始化:executor 和 event loop 在第一次 emit() 时才创建,减少开销

读写锁_rwlock: RWLock 保护 handler 注册/注销。

依赖图:通过 depends_on 注册 handler 依赖,build_execution_plan() 构建分层执行计划。执行计划缓存到 handler 变更。

事件类型层次

所有事件继承自 BaseEvent,包含:

  • event_idparent_event_idprevious_event_idtriggered_by_event_id — 事件链追踪
  • emission_sequence — 全局递增序列号(context variable)
  • source_fingerprintsource_type — 来源标记

CrewAI 定义了 ~80+ 事件类型:Crew、Agent、Task、Flow、LLM、Tool、Memory、Knowledge、MCP、Skill、Checkpoint 等。

事件懒加载

__init__.py 使用 __getattr__ 实现事件的懒加载:

  • 通过 _LAZY_EVENT_MAPPING 字典延迟导入
  • 避免启动时加载 ~12 个 Pydantic 模块及其传递依赖
  • 首次引用某个事件类时才触发导入

重放机制

crewai_event_bus.replay(source, event) 方法:

  • 不修改事件的 event_idemission_sequence
  • 不重新记录事件到 event record
  • 通过 _replaying context variable 通知 handler(有副作用的 handler 应跳过)

事件上下文与范围栈

event_context.py 维护一个 scope 栈,实现事件父子关系:

  • push_event_scope(event_id, event_type) / pop_event_scope() — 成对的 Started/Completed 事件
  • VALID_EVENT_PAIRS 验证 Started/Completed 配对是否匹配
  • triggered_by_scope — 追踪因果链

OpenTelemetry 遥测

Telemetry 单例基于 OpenTelemetry:

  • 发送目标:https://telemetry.crewai.com:4319
  • 可通过 OTEL_SDK_DISABLED=trueCREWAI_DISABLE_TELEMETRY=trueCREWAI_DISABLE_TRACKING=true 禁用
  • SafeOTLPSpanExporter 包装器捕获导出失败
  • 默认只发送元数据,crew.share_crew=True 才发送详细数据
  • 信号处理器:SIGTERM/SIGINT/SIGHUP/SIGTSTP/SIGCONT

问题与规避

事件总线单例不支持多租户隔离

  • 全局唯一的 crewai_event_bus 不支持多租户隔离
  • 对策:使用 scoped_handlers() 上下文管理器提供临时隔离,测试间需要 clear_all_global_hooks()

懒加载的首次引用延迟

  • 首次引用某个事件时有导入开销
  • 对策:在应用启动时预热导入(引用所有常用事件类)

遥测的隐私顾虑

  • 即使默认只发送元数据,某些场景下仍需要完全禁用
  • 对策:设置 CREWAI_DISABLE_TELEMETRY=true 环境变量

设计取舍

单例事件总线 vs 可实例化事件总线

  • 单例简化了事件注册和发射,全局共享
  • 代价是不支持多租户隔离
  • scoped_handlers() 提供临时隔离,但不如完全独立的事件总线彻底

事件懒加载 vs 预加载

  • 懒加载减少启动开销,但首次引用时有延迟
  • 对于 CLI 工具(启动即退出),懒加载是更优选择
  • 对于长时运行的服务,预加载可能更合适

参考来源

  • 源码验证: lib/crewai/src/crewai/events/event_bus.py
  • 源码验证: lib/crewai/src/crewai/events/base_events.py
  • 源码验证: lib/crewai/src/crewai/events/__init__.py
  • 源码验证: lib/crewai/src/crewai/telemetry/telemetry.py