Mingyu's Library主页

OpenTelemetry GenAI 语义约定与 Agent 可观测性

OpenTelemetry GenAI Semantic Conventions for Agent Observability

2026-10-15 · 今日精选主题 · 依据 Claude Code v2.1.300 changelog 与公开说明文章
2026-10-15 · Topic of the day · Based on the Claude Code v2.1.300 changelog and public write-ups

1. 这是什么、为什么现在值得看

1. What it is, and why it matters now

OpenTelemetry GenAI 语义约定(semantic conventions,简称 semconv)是一份「命名词典」:规定 LLM 调用、agent 运行、工具执行在 trace(链路追踪)、metric(指标)和 event(事件)里该用什么名字、带哪些属性(都以 gen_ai.* 开头)。好处是:不同框架、不同语言、不同模型厂商吐出的遥测,可以进同一个看板、同一套告警。

The OpenTelemetry GenAI semantic conventions (semconv) are a naming dictionary: they say what names and attributes (all prefixed gen_ai.*) LLM calls, agent runs and tool executions should use in traces, metrics and events. The payoff is that telemetry from different frameworks, languages and model vendors can land in the same dashboards and alerts.

为什么是今天:Claude Code v2.1.300(2026-10-14)的 changelog 写明 span 上新增了 OpenTelemetry GenAI 语义约定的属性(如 gen_ai.provider.name、gen_ai.tool.name、error.type)。同时,据 Dash0 的说明文章,这套约定在 v1.42.0(2026-06-12)搬到了独立仓库 semantic-conventions-genai,且所有 gen_ai.* 仍处于 Development(开发中)阶段——名称可能在没有弃用期的情况下改变。也就是说:标准值得用,但要带着「会改名」的心理预期用。

Why today: the Claude Code v2.1.300 changelog (2026-10-14) says spans now carry attributes from the OpenTelemetry GenAI semantic conventions (e.g. gen_ai.provider.name, gen_ai.tool.name, error.type). Meanwhile, per Dash0's explainer, the conventions moved to a separate repository, semantic-conventions-genai, in v1.42.0 (2026-06-12), and every gen_ai.* item is still at Development stability, so names can change without a deprecation window. In short: worth adopting, but adopt expecting renames.

诚实提示:不同来源对稳定度的说法不完全一致——OpenObserve(2026-05)认为核心 chat 属性相对稳定、agent/工具属性仍在变;Dash0(更新于 09-14)则称全部为 Development。本文按更保守的说法处理。官方旧页面(opentelemetry.io/docs/specs/semconv/gen-ai/)现在只剩一条「已迁移」提示,我没能直接读到新仓库 docs 里的原文,所以属性细节来自上述两篇二手说明,落地前请对照新仓库核对。
A candid note: sources disagree slightly on stability. OpenObserve (May 2026) treats core chat attributes as relatively settled and agent/tool attributes as still moving; Dash0 (updated Sep 14) says everything is Development. This document takes the more conservative view. The old official spec pages now show only a "moved" notice, and I could not read the new repository's docs directly, so attribute details below come from those two secondary write-ups; verify against the new repo before you commit.

2. 一次 agent 运行在 trace 里长什么样

2. What one agent run looks like as a trace

核心思路:一次 agent 运行是一棵树。最外层是 invoke_agent,里面交替出现模型调用(chat)和工具执行(execute_tool);子 agent 就是再嵌一层 invoke_agent。字段 gen_ai.operation.name 标明每个 span 是哪种操作。

The core idea: an agent run is a tree. The outermost span is invoke_agent; inside it, model calls (chat) alternate with tool executions (execute_tool); a sub-agent is just another nested invoke_agent. The gen_ai.operation.name attribute says which kind of operation each span is.

invoke_agent(agent 运行) chat(模型调用 #1) execute_tool(工具:读文件) chat(模型调用 #2) invoke_agent(子 agent) chat 最终 chat(给出答案) 同一个 trace ID 串起整棵树
invoke_agent (agent run) chat (model call #1) execute_tool (tool: read file) chat (model call #2) invoke_agent (sub-agent) chat final chat (answer) one trace ID ties the whole tree together
operation.name含义span 类型(据 OpenObserve)
chat / text_completion / generate_content一次模型推理调用CLIENT
embeddings生成向量CLIENT
create_agent创建(远端)agentCLIENT
invoke_agent运行 agent;远端为 CLIENT,进程内框架执行为 INTERNAL(v1.41 起)CLIENT / INTERNAL
invoke_workflow固定路径的工作流(区别于自主决策的 agent),v1.41 新增—
execute_tool执行一次工具调用;v1.41 起 span 名里要带工具名INTERNAL
retrieval / plan / 记忆类操作RAG 检索、规划、记忆读写(据 Dash0 列表)—
operation.nameMeaningSpan kind (per OpenObserve)
chat / text_completion / generate_contentOne model inference callCLIENT
embeddingsEmbedding generationCLIENT
create_agentCreating a (remote) agentCLIENT
invoke_agentRunning an agent; CLIENT for remote, INTERNAL for in-process framework execution (since v1.41)CLIENT / INTERNAL
invoke_workflowA fixed-path workflow (as opposed to autonomous agent reasoning), added in v1.41—
execute_toolOne tool execution; since v1.41 the tool name must appear in the span nameINTERNAL
retrieval / plan / memory opsRAG lookups, planning, memory reads/writes (per Dash0's list)—

3. 最该先认识的属性

3. The attributes to learn first

属性作用
gen_ai.operation.name操作类型(必填)
gen_ai.provider.name厂商标识,如 anthropic;取代了旧的 gen_ai.system(必填)
gen_ai.request.model / gen_ai.response.model请求的模型 vs 实际响应的模型,二者可能不同(例如带日期的快照)
gen_ai.usage.input_tokens / output_tokenstoken 用量,成本的主要来源;另有缓存读取、推理 token 属性(v1.40、v1.41 加入)
gen_ai.response.finish_reasons结束原因,是数组不是字符串
gen_ai.conversation.id把多轮会话/agent 循环的 span 串在一起
gen_ai.agent.name / .id / .versionagent 身份
gen_ai.tool.name / gen_ai.tool.call.id工具名与调用 ID(用来把调用和结果配对)
error.type失败类别;来自核心约定,是少数已 Stable 的属性之一(另有 server.address、server.port,据 Dash0)
AttributePurpose
gen_ai.operation.nameOperation type (required)
gen_ai.provider.nameVendor identifier such as anthropic; replaces the older gen_ai.system (required)
gen_ai.request.model / gen_ai.response.modelRequested vs actually serving model; they can differ (e.g. dated snapshots)
gen_ai.usage.input_tokens / output_tokensToken usage, the main cost driver; cache-read and reasoning token attributes were added in v1.40 and v1.41
gen_ai.response.finish_reasonsWhy generation stopped; an array, not a string
gen_ai.conversation.idGroups spans of a multi-turn session or agent loop
gen_ai.agent.name / .id / .versionAgent identity
gen_ai.tool.name / gen_ai.tool.call.idTool name and call ID (to pair a call with its result)
error.typeFailure category; from the core conventions and one of the few Stable attributes (along with server.address and server.port, per Dash0)

4. 指标与事件

4. Metrics and events

5. 内容采集:默认不记,记就要有章法

5. Content capture: off by default, and deliberate when on

prompt 和回答里常有个人信息或商业机密,也可能很大,所以规范把它们放在事件里而不是 span 属性里,并且默认不记录。OpenObserve 总结了三种做法:不记录(默认);记在 span 属性(简单,但有大小限制,且能看 trace 的人都能看到);存到外部存储、span 上只放引用(规范推荐用于敏感或大流量的生产环境)。启用开关由各库自己决定——规范只把 OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT 作为示例,不同库的取值写法不一样,务必看库文档。

Prompts and responses often contain personal or confidential data and can be large, so the spec puts them in events rather than span attributes and does not record them by default. OpenObserve describes three approaches: not recorded (default); recorded as span attributes (simple, but size-limited and visible to anyone with trace access); or stored externally with only a reference on the span (recommended for sensitive or high-volume production). The switch is up to each library: the spec offers OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT only as an example, and accepted values differ, so read your library's docs.

① 不记录(默认)只留元数据 ② 写进 span 属性有大小限制、人人可见 ③ 外部存储+引用独立权限与保留期 适合:默认/生产排障看元数据 适合:测试/预发调试 适合:生产且含敏感数据 建议在源头脱敏/过滤,而不是指望下游。
1. Not recorded (default)metadata only 2. Span attributessize-limited, visible to all 3. External store + refown access and retention Fits: default / prod triage on metadata Fits: test / staging debugging Fits: prod with sensitive data Redact at the source rather than relying on downstream consumers.

6. Claude Code 怎么对应这套标准

6. How Claude Code maps onto the standard

Claude Code 的官方监控文档里,traces 仍是 beta,层级是:claude_code.interaction(每次用户提问一个)→ claude_code.llm_request、claude_code.tool(其下有 blocked_on_user 与 execution)、claude_code.hook;子 agent 的 span 嵌在工具之下。它自己的 span 名是 claude_code.*,GenAI 约定的属性是「叠加」在这些 span 上的:文档列出 gen_ai.system(恒为 anthropic)、gen_ai.request.model、gen_ai.response.id、gen_ai.response.finish_reasons、gen_ai.tool.call.id;而 v2.1.300 changelog 则提到 gen_ai.provider.name、gen_ai.tool.name、error.type。两处并存,说明它正处在从旧名到新名的过渡中——查询时两个名字都要考虑。

In Claude Code's official monitoring docs, traces are still beta, with this hierarchy: claude_code.interaction (one per user prompt) → claude_code.llm_request, claude_code.tool (with blocked_on_user and execution beneath it) and claude_code.hook; subagent spans nest under tools. Span names are Claude Code's own claude_code.*; GenAI attributes are layered on top. The docs list gen_ai.system (always anthropic), gen_ai.request.model, gen_ai.response.id, gen_ai.response.finish_reasons and gen_ai.tool.call.id, while the v2.1.300 changelog mentions gen_ai.provider.name, gen_ai.tool.name and error.type. Both coexisting suggests a transition from old names to new, so queries should consider both.

export CLAUDE_CODE_ENABLE_TELEMETRY=1
export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1      # traces are beta
export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
# content stays redacted unless you opt in, one switch per category:
# OTEL_LOG_USER_PROMPTS=1  OTEL_LOG_TOOL_DETAILS=1  OTEL_LOG_TOOL_CONTENT=1
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1      # traces are beta
export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
# content stays redacted unless you opt in, one switch per category:
# OTEL_LOG_USER_PROMPTS=1  OTEL_LOG_TOOL_DETAILS=1  OTEL_LOG_TOOL_CONTENT=1

另外,Claude Code 的 Bash/PowerShell 子进程会继承 TRACEPARENT,你的脚本可以把自己的 span 挂到同一条 trace 上;经自定义 ANTHROPIC_BASE_URL 代理时需设 CLAUDE_CODE_PROPAGATE_TRACEPARENT=1 才会透传。管理员可在 managed settings 里固定 OTLP 端点,仓库内的 .claude/settings.json 不能开启遥测或改目的地。

Also, Bash and PowerShell subprocesses inherit TRACEPARENT, so your scripts can attach their own spans to the same trace; behind a custom ANTHROPIC_BASE_URL proxy you need CLAUDE_CODE_PROPAGATE_TRACEPARENT=1 to propagate it. Admins can pin the OTLP endpoint in managed settings, and a repository's .claude/settings.json cannot enable telemetry or change its destination.

7. 配套:MCP 的链路怎么接上

7. Companion piece: connecting MCP into the trace

据 OpenObserve,MCP 约定(v1.39)解决的是「agent 侧与 MCP server 侧的 trace 断开」:靠 W3C Trace Context 传播,让 server 的 span 挂在 client 的 span 之下;关键属性有 mcp.method.name、mcp.session.id、mcp.protocol.version。如果外层 GenAI 插桩已经记录了工具执行,MCP 插桩应当丰富那个 span,而不是再造一个重复的。两侧都不传播上下文,链路就连不起来。

Per OpenObserve, the MCP conventions (v1.39) fix the problem of agent-side and MCP-server-side traces being disconnected: W3C Trace Context propagation nests the server span under the client span, with key attributes mcp.method.name, mcp.session.id and mcp.protocol.version. If outer GenAI instrumentation already tracks tool execution, MCP instrumentation should enrich that span rather than create a duplicate. Without propagation on both sides, the traces will not connect.

8. 什么场景用、怎么选

8. When to use it, and how to choose

9. 常见坑

9. Common pitfalls

10. 术语表

10. Glossary

术语人话解释
spantrace 里的一段操作记录,有起止时间和属性
trace由 span 组成的一棵树,代表一次完整请求/运行
attribute挂在 span 上的键值对,如模型名、token 数
semantic conventions规定名字和含义的「命名词典」
OTLPOpenTelemetry 的数据传输协议
Development(稳定度)最早的稳定度级别,名称可能随时变
TermPlain meaning
spanOne recorded operation in a trace, with start/end time and attributes
traceA tree of spans representing one complete request or run
attributeA key-value pair on a span, e.g. model name or token count
semantic conventionsA naming dictionary that fixes names and meanings
OTLPOpenTelemetry's wire protocol for sending data
Development (stability)The earliest stability level; names may change at any time

11. 来源与说明

11. Sources and notes