主页
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.
核心思路:一次 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.
| operation.name | 含义 | span 类型(据 OpenObserve) |
|---|---|---|
chat / text_completion / generate_content | 一次模型推理调用 | CLIENT |
embeddings | 生成向量 | CLIENT |
create_agent | 创建(远端)agent | CLIENT |
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.name | Meaning | Span kind (per OpenObserve) |
|---|---|---|
chat / text_completion / generate_content | One model inference call | CLIENT |
embeddings | Embedding generation | CLIENT |
create_agent | Creating a (remote) agent | CLIENT |
invoke_agent | Running an agent; CLIENT for remote, INTERNAL for in-process framework execution (since v1.41) | CLIENT / INTERNAL |
invoke_workflow | A fixed-path workflow (as opposed to autonomous agent reasoning), added in v1.41 | — |
execute_tool | One tool execution; since v1.41 the tool name must appear in the span name | INTERNAL |
retrieval / plan / memory ops | RAG lookups, planning, memory reads/writes (per Dash0's list) | — |
| 属性 | 作用 |
|---|---|
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_tokens | token 用量,成本的主要来源;另有缓存读取、推理 token 属性(v1.40、v1.41 加入) |
gen_ai.response.finish_reasons | 结束原因,是数组不是字符串 |
gen_ai.conversation.id | 把多轮会话/agent 循环的 span 串在一起 |
gen_ai.agent.name / .id / .version | agent 身份 |
gen_ai.tool.name / gen_ai.tool.call.id | 工具名与调用 ID(用来把调用和结果配对) |
error.type | 失败类别;来自核心约定,是少数已 Stable 的属性之一(另有 server.address、server.port,据 Dash0) |
| Attribute | Purpose |
|---|---|
gen_ai.operation.name | Operation type (required) |
gen_ai.provider.name | Vendor identifier such as anthropic; replaces the older gen_ai.system (required) |
gen_ai.request.model / gen_ai.response.model | Requested vs actually serving model; they can differ (e.g. dated snapshots) |
gen_ai.usage.input_tokens / output_tokens | Token usage, the main cost driver; cache-read and reasoning token attributes were added in v1.40 and v1.41 |
gen_ai.response.finish_reasons | Why generation stopped; an array, not a string |
gen_ai.conversation.id | Groups spans of a multi-turn session or agent loop |
gen_ai.agent.name / .id / .version | Agent identity |
gen_ai.tool.name / gen_ai.tool.call.id | Tool name and call ID (to pair a call with its result) |
error.type | Failure category; from the core conventions and one of the few Stable attributes (along with server.address and server.port, per Dash0) |
gen_ai.client.token.usage:按类型、操作、模型统计 token(直方图);配上单价就是实时成本视图。gen_ai.client.operation.duration:调用端到端耗时(秒)。gen_ai.invoke_agent.duration、.tool_calls、.inference_calls 等 agent 级指标:工具调用数与推理调用数的比例,可以帮助区分「空转循环」与「反复重试」。gen_ai.client.inference.operation.details 承载完整输入/输出消息(需主动开启);gen_ai.evaluation.result 承载评测分数。gen_ai.client.token.usage: tokens by type, operation and model (histogram); pair it with pricing for a live cost view.gen_ai.client.operation.duration: end-to-end call latency in seconds.gen_ai.invoke_agent.duration, .tool_calls and .inference_calls; the ratio of tool calls to inference calls helps tell looping without action from repeated retries.gen_ai.client.inference.operation.details carries full input/output messages (opt-in); gen_ai.evaluation.result carries evaluation scores.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.
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.
据 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.
execute_tool 与 chat 的耗时找慢点,用 finish_reasons 找被截断的调用。gen_ai.conversation.id 才能把循环里的 span 串起来;没有它,失控循环只是一堆互不相连的 span。execute_tool vs chat durations for slow spots, finish_reasons to find truncated calls.gen_ai.conversation.id can loop spans be tied together; without it a runaway loop is just disconnected spans.gen_ai.system 正被 gen_ai.provider.name 取代,有的库两个都发——查询要兼容。gen_ai.system is being superseded by gen_ai.provider.name, and some libraries emit both; make queries tolerant.| 术语 | 人话解释 |
|---|---|
| span | trace 里的一段操作记录,有起止时间和属性 |
| trace | 由 span 组成的一棵树,代表一次完整请求/运行 |
| attribute | 挂在 span 上的键值对,如模型名、token 数 |
| semantic conventions | 规定名字和含义的「命名词典」 |
| OTLP | OpenTelemetry 的数据传输协议 |
| Development(稳定度) | 最早的稳定度级别,名称可能随时变 |
| Term | Plain meaning |
|---|---|
| span | One recorded operation in a trace, with start/end time and attributes |
| trace | A tree of spans representing one complete request or run |
| attribute | A key-value pair on a span, e.g. model name or token count |
| semantic conventions | A naming dictionary that fixes names and meanings |
| OTLP | OpenTelemetry's wire protocol for sending data |
| Development (stability) | The earliest stability level; names may change at any time |