Tracing 概览
CubePi 发出符合 GenAI Semantic Conventions v1.41 的 OpenTelemetry span,任何兼容 OTel 的后端 (Jaeger、Tempo、Honeycomb、Datadog、AWS X-Ray、Azure Monitor……)都能直接接收 agent 运行数据,无需额外自定义埋点。
将 Tracer 挂载到 Agent 后,每次 prompt 都会产生一棵 span 树,可对其进行
聚合、查询,并与服务内其他链路数据关联:
trace
└── invoke_agent 14425.8ms [0x1cd97cdb] ← 每次 agent.prompt() 一个
├── cubepi.turn 1283.1ms [0x5cfda93e] ← 每次 LLM 往返一个
│ ├── chat deepseek-v4-flash 1208.7ms tok 6845/68 [0x0d130229]
│ └── execute_tool subagent 9610.2ms subagent [0x38bdd10a]
│ └── invoke_agent 9601.0ms [0x8094f99b] ← subagent 运行,嵌套其中
│ └── cubepi.turn 9598.4ms [0x57c5cfc7]
│ ├── chat deepseek-v4-flash 1190.3ms [0x8205ca6b]
│ └── execute_tool web_search 6500.2ms web_search [0xca4e59fc]
└── cubepi.turn 491.9ms ERROR [0xce25f242]
└── chat deepseek-v4-flash 427.2ms ERROR [0x0bff68ec]
└── error: Error code: 400 - ... `tool_use` ids were found without
`tool_result` blocks immediately after: call_01_...
每一层都携带标准 gen_ai.* 属性——gen_ai.operation.name、
gen_ai.request.model、gen_ai.provider.name、gen_ai.usage.input_tokens、
gen_ai.usage.output_tokens、gen_ai.response.finish_reasons……
开箱即用的功能
- Tracer —— 构建 SDK
TracerProvider,为每个 exporter 挂载一个BatchSpanProcessor,将 CubePi 事件流接入 span。 - Meter —— 用于 OTel 直方图的同级组件:
gen_ai.client.operation.duration、gen_ai.client.operation.time_to_first_chunk、gen_ai.client.token.usage。 - JsonlSpanExporter —— 将每条 span 以 JSON 单行写入
./cubepi-traces/<date>/<trace_id>.jsonl。文件按trace_id分片, 因此一个文件包含整条 trace——运行本身加上所有嵌套 subagent 运行(继承同一 trace)。适合本地开发与离线调试;可与任何支持 JSONL 的 OTel 查看工具配合, 也可与cubepi traceCLI 配合。 - OTLP —— 通过
opentelemetry-exporter-otlp-proto-http(HTTP)或…-grpc带入自己的 exporter,传入Tracer(exporters=[…])即可。 - W3C trace context 传播 —— 出站 MCP 调用会自动将当前
traceparent注入 HTTP 头,让下游已埋点的 MCP 服务器能够续接 trace。 tracer.attached(agent)/meter.attached(agent)—— 以 RAII 方式 包裹 attach/detach 的 async context manager,清理只需一个async with块,无需显式try/finally。atexitflush hook ——Tracer(atexit_flush=True)(默认开启)注册 进程退出处理程序,在进程正常退出时同步 flush 缓冲 span,即使忘记调用await tracer.shutdown()也不会丢失数据。tracing_context()—— 通过 contextvar 作用域块为单次运行设置标签和 元数据(cubepi.tags = ("beta-arm",)、cubepi.metadata.user_id = "u-42"), 并发 agent 各自看到独立的值。
开销
- 每次 agent 运行一个纯 Python recorder,订阅 agent 的事件流和 provider 的监听注册——不做 monkey-patching,不新起线程。
- 每层一个 OTel SDK span。
BatchSpanProcessor在后台批量导出,不阻塞热路径。 - 默认不记录任何 payload。
gen_ai.input.messages、gen_ai.output.messages、 原始请求/响应以及工具参数/结果均需通过record_content=True显式开启, 避免意外将 PII 发送到后端。详见内容记录与脱敏。
各功能使用场景
| 需求 | 使用 |
|---|---|
| 跟踪本地单次 agent 运行并检查 JSONL 文件 | Tracer + JsonlSpanExporter |
| 发送到 Jaeger / Tempo / Honeycomb / Datadog | Tracer + OTLP exporter |
| 在 span 旁边获取延迟与 token 直方图 | Meter 与 Tracer 并用 |
| 记录 prompt / 模型输出用于评测 | Tracer(record_content=True) |
| 在数据离开进程前脱敏 PII | Tracer(redact=…) |
为运行打上 user_id / session_id / A-B 分组标签 | tracing_context(tags=…, metadata=…) |
| 一行代码完成清理,无需 try/finally | async with tracer.attached(agent): … |
忘记调用 shutdown() 也不丢 span | Tracer(atexit_flush=True)(默认) |
| 从上游服务续接 trace | Tracer(resource=…) + W3C traceparent(MCP 自动,HTTP 手动) |