OpenTelemetry GenAI 语义约定
OpenTelemetry 的 GenAI SIG(2024 年 4 月成立)定义了 agent 遥测的标准 schema。span 名、属性和内容捕获规则在各厂商间收敛,于是 agent trace 在 Datadog、Grafana、Jaeger 和 Honeycomb 里含义一致。
类型: Learn + Build 语言: Python(标准库) 前置要求: 阶段 14 · 13(LangGraph)、阶段 14 · 24(可观测性平台) 预计时间: ~60 分钟
学习目标
- 说出 GenAI 的 span 类别:model/client、agent、tool。
- 区分
invoke_agentCLIENT span 和 INTERNAL span,以及各自何时适用。 - 列出顶层 GenAI 属性:提供方名称、请求模型、数据源 ID。
- 解释内容捕获契约:opt-in、
OTEL_SEMCONV_STABILITY_OPT_IN、外部引用建议。
问题背景
每个厂商都发明自己的 span 名。运维团队最后得为每个框架各建一套仪表盘。OpenTelemetry 的 GenAI SIG 通过定义一个整个生态都对齐的标准来修这个问题。
核心概念
span 类别
- Model / client span。 覆盖原始 LLM 调用。由提供方 SDK(Anthropic、OpenAI、Bedrock)和框架的模型适配器发出。
- Agent span。
create_agent(agent 被构造时)和invoke_agent(它运行时)。 - Tool span。 每次工具调用一个;通过父子关系连到 agent span。
Agent span 命名
- span 名:如果有命名就是
invoke_agent \{gen_ai.agent.name\};回退到invoke_agent。 - span 类型:
- CLIENT —— 用于远程 agent 服务(OpenAI Assistants API、Bedrock Agents)。
- INTERNAL —— 用于进程内 agent 框架(LangChain、CrewAI、本地 ReAct)。
关键属性
gen_ai.provider.name——anthropic、openai、aws.bedrock、google.vertex。gen_ai.request.model—— 模型 ID。gen_ai.response.model—— 解析后的模型(可能因路由与请求不同)。gen_ai.agent.name—— agent 标识符。gen_ai.operation.name——chat、completion、invoke_agent、tool_call。gen_ai.data_source.id—— 用于 RAG:咨询了哪个语料或存储。
针对 Anthropic、Azure AI Inference、AWS Bedrock、OpenAI 有技术专用的约定。
内容捕获
默认规则:instrumentation 默认不应捕获输入/输出。捕获通过以下选项 opt-in:
gen_ai.system_instructionsgen_ai.input.messagesgen_ai.output.messages
推荐的生产模式:把内容外部存储(S3、你的日志存储),在 span 上记录引用(指针 ID,而非散文)。这就是把第 27 课的内容投毒防御接进了可观测性。
稳定性
截至 2026 年 3 月,大多数约定还是实验性的。用下面这个选项 opt-in 进稳定预览:
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimentalDatadog v1.37+ 把 GenAI 属性原生映射进它的 LLM Observability schema。其他后端(Grafana、Honeycomb、Jaeger)支持原始属性。
这个模式在哪里会出错
- 在 span 里捕获完整 prompt。 PII、密钥、客户数据进了运维能读的 trace。外部存储。
- 没有
gen_ai.provider.name。 缺归因时多提供方仪表盘崩掉。 - 没有父链接的 span。 孤儿工具 span。永远传播 context。
- 没设稳定性 opt-in。 你的属性可能在后端升级时被重命名。
ae-genai-span-tree动手构建
code/main.py 用标准库实现一个匹配 GenAI 约定的 span 发射器:
- 带 GenAI 属性 schema 的
Span。 - 带
start_span、嵌套 context 的Tracer。 - 一次脚本化 agent 运行,发出:
create_agent、invoke_agent(INTERNAL)、每工具 span、LLM 调用的chatspan。 - 一个内容捕获模式,把 prompt 外部存储并在 span 上记录 ID。
运行它:
python3 code/main.py输出:一棵带所有必需 GenAI 属性的 span 树,以及一个展示 opt-in 内容引用的「外部存储」。
实际使用
- Datadog LLM Observability(v1.37+)原生映射属性。
- Langfuse / Phoenix / Opik(第 24 课)—— 自动 instrument 整个生态。
- Jaeger / Honeycomb / Grafana Tempo —— 原始 OTel trace;从 GenAI 属性建仪表盘。
- 自托管 —— 用带 GenAI processor 的 OTel Collector 跑。
拿去用
outputs/skill-otel-genai.md 把 OTel GenAI span 接进一个现有 agent,带内容捕获默认值和外部引用存储。
练习
- 给你第 01 课的 ReAct 循环 instrument 上
invoke_agent(INTERNAL)+ 每工具 span。发送到一个 Jaeger 实例。 - 用「仅引用」模式加内容捕获:prompt 进 SQLite,span 属性只带行 ID。
- 读
gen_ai.data_source.id的规范。把它接进你第 09 课的 Mem0 搜索。 - 设置
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental,验证你的属性不会被 collector 重命名。 - 构建一个仪表盘:仅从 GenAI 属性看「哪些工具错误与哪些模型相关」。
关键术语
| 术语 | 大家怎么说 | 它实际是什么 |
|---|---|---|
| GenAI SIG | 「OpenTelemetry GenAI 组」 | 定义 schema 的 OTel 工作组 |
| invoke_agent | 「agent span」 | 表示一次 agent 运行的 span 名 |
| CLIENT span | 「远程调用」 | 对一个远程 agent 服务调用的 span |
| INTERNAL span | 「进程内」 | 一次进程内 agent 运行的 span |
| gen_ai.provider.name | 「提供方」 | anthropic / openai / aws.bedrock / google.vertex |
| gen_ai.data_source.id | 「RAG 来源」 | 一次检索命中了哪个语料/存储 |
| Content capture | 「prompt 记录」 | 消息的 opt-in 捕获;生产里外部存储 |
| Stability opt-in | 「预览模式」 | 用来钉住实验性约定的环境变量 |
延伸阅读
- OpenTelemetry GenAI semantic conventions —— 规范
- OpenAI Agents SDK —— 默认 GenAI span
- AutoGen v0.4 (Microsoft Research) —— 内置 OTel span
- Claude Agent SDK —— W3C trace context 传播