05 - 可观测性系统:Callback + Instrumentation
05 - 可观测性系统:Callback + Instrumentation
学习目标
本章将带你分析 LlamaIndex 的可观测性系统。你将学到:
- 双层架构设计(CallbackManager + Instrumentation)
- CallbackManager 的多 handler 注册机制
- Instrumentation 的 dispatcher → handler → span 三层架构
- 自动 span 追踪(LLM 调用、工具调用、检索操作)
- 性能 overhead 与生产环境的使用建议
项目实践
双层架构
LlamaIndex 的可观测性系统由两层组成:
Instrumentation(底层):自动为每个操作创建 span,通过 dispatcher 推送给 handler。无需手动调用。
CallbackManager(高层):在关键操作的入口和出口触发回调事件,需要手动注册 handler。
CallbackManager 多 Handler 注册
CallbackManager 支持注册多个 handler,每个 handler 监听不同的事件:
from llama_index.core.callbacks import CallbackManagerfrom llama_index.core.callbacks.global_handlers import set_global_handler
# 注册调试 handler(打印所有事件)from llama_index.core.callbacks import LlamaDebugHandlercallback_manager = CallbackManager(handlers=[LlamaDebugHandler()])
# 注册 token 计数 handlerfrom llama_index.core.callbacks import TokenCountingHandlercallback_manager.add_handler(TokenCountingHandler())每个 handler 实现特定的回调方法:
class BaseCallbackHandler: def on_event_start(self, event_type, payload): ... def on_event_end(self, event_type, payload): ... def on_llm_start(self, ...): ... def on_llm_end(self, ...): ... def on_tool_start(self, ...): ... def on_tool_end(self, ...): ...Instrumentation 的三层架构
Instrumentation 模块使用 dispatcher → handler → span 三层架构:
# Dispatcher: 事件分发器,将 span 推送给注册的 handlers# SpanHandler: 处理 span 事件(如打印、发送到 OpenTelemetry)# OpenTelemetryHandler: 发送到 OpenTelemetry 后端每个 LLM 调用、工具调用、检索操作自动创建 span:
自动 Span 追踪
以下操作自动创建 span,无需手动添加:
| 操作 | Span 名称 | 包含信息 |
|---|---|---|
| LLM 调用 | llm.chat / llm.complete | 模型名称、prompt、响应 |
| 工具调用 | tool.call | 工具名、参数、结果 |
| 检索 | retriever.retrieve | 查询、返回节点数 |
| 嵌入 | embedding.embed | 模型名称、文本数量 |
| 响应合成 | response.synthesize | 模式(refine/tree_summarize) |
性能 Overhead
重要配置:在 llama-index-core/pyproject.toml 的 coverage 配置中,Instrumentation 和 Workflow 被排除在覆盖率统计之外:
[tool.coverage.run]omit = [ "llama_index/core/instrumentation/*", "llama_index/core/workflow/*",]这说明 Instrumentation 模块的 overhead 较大——它通过装饰器和上下文管理器在每个操作入口/出口执行额外代码。
生产环境建议:
| 环境 | 推荐配置 |
|---|---|
| 开发调试 | 启用所有 CallbackHandler + Instrumentation |
| 测试环境 | 仅启用 TokenCountHandler(轻量) |
| 生产环境 | 仅启用 OpenTelemetryHandler(批量发送)或禁用 |
问题与规避
| 陷阱 | 对策 |
|---|---|
| Instrumentation overhead 导致延迟增加 | 生产环境使用 OpenTelemetryHandler 批量发送,或完全禁用 |
| Callback handler 抛异常导致操作中断 | 在 handler 的回调方法中捕获所有异常,不要向上抛出 |
| 多 handler 注册时事件重复触发 | 理解 CallbackManager 和 Instrumentation 是两个独立的系统,避免重复注册 |
| TokenCountHandler 计数不准确 | 确保 tokenizer 与 LLM 实际使用的 tokenizer 一致 |
设计取舍
Callback vs Instrumentation
| 维度 | CallbackManager | Instrumentation |
|---|---|---|
| 触发方式 | 手动注册,自动触发 | 自动注册,自动触发 |
| 灵活性 | 高(可选择性注册 handler) | 低(全局启用/禁用) |
| 性能 | 中(取决于 handler 数量) | 高(overhead 较大) |
| 集成 | 自定义 Python handler | 支持 OpenTelemetry 标准 |
| 耦合度 | 低(handler 可独立开发) | 高(dispatcher 嵌入核心代码) |
双层架构的原因:CallbackManager 提供轻量、灵活的自定义回调;Instrumentation 提供标准化的 span 追踪(支持 OpenTelemetry)。两者互补而非替代。
参考来源
- LlamaIndex CallbackManager 源码:
llama-index-core/llama_index/core/callbacks/ - LlamaIndex Instrumentation 源码:
llama-index-core/llama_index/core/instrumentation/