这是提交给Kaggle 基准测试挑战赛的作品

我基准测试了什么

TL;DR。我测试了 17 个 AI 模型在编写、回忆和修复 OpenTelemetry 插桩方面的表现,并针对规范的 26 个版本进行了代码评分。

  • 17 个中有 16 个模型写出了已废弃的名称,并且83%的这些名称已被废弃超过一年。
  • 13 个中有 12 个模型在被直接询问时,写出了它们本已正确替换的名称。
  • 17 个中有 7 个通过更改指标的单位并保留其已废弃的名称来“修复”指标,这会在两方面都破坏它。
  • 用一句话指明规范版本,可将废弃名称减少36%,并让模型编造出更多名称。

基准测试:Kaggle 上的 Semconv Drift

我问 Claude Sonnet 5 什么取代了 OpenTelemetry 属性db.system。它正确回答:db.system.name,这是规范自 2025 年 1 月起使用的名称。

在同一基准测试中,我让它为一次 go-redis 调用添加追踪。它写下了:

attribute。String("db.system", "redis"),
attribute。String("db.operation", cmdName),
attribute。String("db.statement", statement),

这三个名称都已废弃。代码能编译,span 能导出,后端能存储。没有任何失败。几周后,一个按db.system.name过滤的仪表盘显示没有 Redis 流量,而没有人会把空面板与一行生成的代码联系起来。

今年我有 14 个拉取请求被合并进 OpenTelemetry 的 Go 编译期插桩项目,而这正是我在审查中会放行的那类 bug。代码看起来是对的。它只是相对于某个规范版本是错的,而没有人会对照规范版本进行审查。所以我构建了一个基准测试来衡量这种情况发生的频率。

任务

OpenTelemetry 的语义约定是遥测的共享词汇:哪个键保存 HTTP 方法,数据库 span 如何称呼其查询,时长指标使用哪个单位。它们是有版本的,而许多人最初学到的名称已被重命名。http.method在 2023 年变为http.request.method。db.statement在 2024 年变为db.query.text。rpc.client.duration,以毫秒为单位,在 2026 年 1 月变为rpc.client.call.duration,以秒为单位。

Semconv Drift在 Kaggle Benchmarks 上有四个任务:

任务 用例数 模型做什么
编写 12 为日常代码添加插桩:Flask 和 Express 服务器、HTTP 客户端、psycopg、go-redis、kafkajs、gRPC、指标和资源,使用 Python、Go 和 TypeScript
知道 22 说出取代了某个已退役名称的名称。包含 span-kind 陷阱和两个正确答案为“unchanged”的对照项
修复 8 现代化旧代码片段,包括来自 redis/go-redis 的真实代码,在单位发生变化时转换数值
带版本提示编写 12 Write 请求,外加一句话说明当前规范版本

每个 Write 提示都已经写明“遵循当前的 OpenTelemetry 语义约定。”模型已经被告知了。问题在于“当前”对它们意味着什么。

评分靠代码,而不是裁判。评分器会从答案中提取每一个语义约定名称(字符串键、指标名、四种语言中的 SDK 常量、枚举值),并在 1,563 个名称中逐一查找,这些名称来自规范的 26 个版本,从 v1.21.0 到 v1.44.0,另外对最旧的名称还补充了 v1.0.0 到 v1.20.0 的全部名称。每个已退役名称都附带将其退役的版本和日期。推理文本会先被剥离,因此模型是按其写出的代码来评判的。答案键也会被测试:如果任何标准答案不是基准真值中的当前名称,构建就会失败。

基准真值来自流失,这是一个数据集,包含open-telemetry/semantic-conventions的每一个带标签版本,是我为 DEV 的Sanity 挑战构建的。

测试的模型

通过 Kaggle 的模型代理测试了 17 个模型,挑选它们是为了回答三个问题:

  • 更新的世代能修复它吗?三对同系列模型:Claude Sonnet 4.5 和 5、GPT-5.4 和 5.5、Gemini 2.5 Pro 和 3.1 Pro。
  • 花更多钱能修复它吗?前沿模型(GPT-6 Astra、Claude Opus 5、GPT-5.5、Gemini 3.1 Pro)与小而便宜的模型(GPT-5.4 mini、Claude Haiku 4.5、Gemini 3.7 和 3.8 Flash)并列。
  • 开源权重模型有差异吗?Qwen 3 235B、DeepSeek-R1、GLM-5、Gemma 4 31B 和 gpt-oss-120b。

总计 830 个已评分答案,另有来自重复运行的 84 个。四个推理模型(DeepSeek-R1、GLM-5、Gemma 4 和 gpt-oss-120b)没有 Know 分数:在一些简短的事实性问题上,它们把整个答案预算都花在思考上,从未作答。Grok 4.5 和 4.6 对我的账户返回 404,因此不在阵容中。

发现

1. 这种漂移是旧的,不是新的

Age of each retired name at the time of the run

17 个模型中有 16 个在 Write 中至少写了一个已弃用的名称,共使用 357 次。如果这是关于训练截止时间的问题,那么已弃用的名称应该是模型从未见过的新近名称。但事实并非如此:

  • 357 次中的 297 次(83%)在我运行基准测试时已经弃用超过一年。
  • 238 次(67%)已经弃用超过两年,也就是在 2024 年 10 月之前。而阵容中的每个模型都是在那之后发布的。
  • 已弃用名称的中位弃用时间为2.4 年更早。

这些模型并非不了解新闻。它们读过变更日志,也读过在此之前的多年教程,而教程胜出了。db.system是最明显的案例:在改名近两年后,仍有 12 个模型使用了 24 次。

Most frequent retired names in generated code

训练截止时间唯一能解释的名称是 2026 年 1 月的rpc.*改名。有 16 个模型写了这些名称。GPT-6 Astra 是唯一的例外,而且它也避开了所有更早的已弃用名称,因此仅凭较晚的截止时间并不能解释它完美的 Write 得分。

2. 它告诉了我新名称,然后写了旧名称

Retired names a model wrote although it named the replacement in Know

因为 Know 和 Write 询问的是相同的名称,我可以将每个模型与自身进行对照。对于模型在 Write 中写出的每个已弃用名称,同一个模型在 Know 中是否给出了正确的替代名称?

13 个模型中有 12 个至少写出了一个已弃用名称,而它们在直接被问及时曾正确替换过该名称,总共 58 次。Claude Haiku 4.5 说http.method变成了http.request.method,然后写了http.method五次。Sonnet 5 也这样做了,例如在开头部分。只有 GPT-6 Astra 从未这样做过。db.system, as in the opening. Only GPT-6 Astra never did it.

这不是知识缺口。被问到一个问题时,模型会检索变更日志。被要求写代码时,它会检索最常见的代码,而最常见的代码是旧的。

3. 半吊子修复

Outcomes of the rpc.client.duration fix

一个 Fix 案例把这段 Go 代码片段交给模型,要求它迁移到 v1.44.0,如果单位发生变化则转换数值:

dur, _ := meter。Float64Histogram("rpc.client.duration", metric。WithUnit("ms"))
start := time。Now()
err := invoker(ctx, method, req, reply, cc, opts...)
dur。Record(ctx, float64(time。Since(start)。Milliseconds())

答案是rpc.client.call.duration,单位s,数值以秒为单位。只有 GPT-6 Astra 全部做对了。

17 个模型中有 7 个将单位改为秒、转换了数值,但保留了已弃用的名称。这比不动代码还要糟糕。未改动的代码至少与旧规范保持一致。只修了一半的指标会以新的单位输出旧名称,因此在两个方向上都会出问题:按旧名称查询得到的值比预期小 1,000 倍,而按新名称查询则什么都找不到。这份 diff 看起来像是一次修复,所以它能通过评审。

另外两个来自不同厂商的模型做出了更奇怪的事。GPT-5.5 和 Gemini 3.7 Flash 都把该指标重命名为rpc.client.request.duration。没有任何一版规范定义过这个名称。它是基于真实的http.client.request.duration做出的一个看似合理的猜测,而且两个模型做出了相同的猜测。

4. 为什么这个领域会漂移,而其他领域不会

这项挑战中的另一个条目测试了已被移除的 pandas 和 Express API,发现模型使用的是当前版本。我认为差异在于每种变更的失败方式。

被移除的函数会大声报错。在 pandas 2 上调用DataFrame.append你会得到一个错误、一个 Stack Overflow 提问和一个回答,而这个回答最终进入了训练数据。被废弃的属性名则会静默失败。什么都不会抛出,没有人提问,旧教程也永远不会被更正。OpenTelemetry 项目深知这一点:它的埋点库提供了OTEL_SEMCONV_STABILITY_OPT_IN=http/dup,它会在迁移期间同时输出旧的和新的 HTTP 名称,因为重命名不会自行传播。

这是一个假设,而非实测结果。但它能预测该去哪里寻找漂移:任何旧形式仍然有效的地方。

5. 一句话的上下文有帮助,但还不够

Retired names written with and without a one-sentence version hint

提示任务重复了那 12 个 Write 请求,并额外加了一句话:“目标为 OpenTelemetry 语义约定 v1.44.0(2026 年 8 月发布)。2023 年至 2026 年间,许多属性和指标名称被重命名或移除,因此不要依赖旧名称。”

在相信任何差异之前,我需要一个噪声基线。Kaggle 的基准测试库接受 temperature 参数,但除非模型被标记为支持该参数,否则会将其丢弃,因此同一个提示可能两次给出不同的答案。我在七个模型上第二次运行了普通的 Write 任务。它们的废弃名称总数从 156 变为 166,变化约 6%,而实际上什么都没改。提示让同样的七个模型从 166 降到 94,下降了 43%。

在所有 17 个模型中:

  • 废弃名称减少了 36%,从 357 降至 230。Write 平均分从 39% 升至 48%。
  • 只有一个模型达到了零,而它就是原本就在那里的那个。
  • 编造的名字从 21 个增加到 31 个。被告知名字已更改后,一些模型不再去取旧名字,而是开始猜测新名字。Claude Haiku 4.5 从 1 个编造名字增加到 7 个。

这项挑战中的另一条记录发现,一句规则就能把干净答案的比例从 64% 提升到 96%。而在这里,一句话消除了约三分之一的漂移,并用猜测替换了其中一部分。版本号告诉模型名字已经变了,但并没有告诉它变成了什么。

6. 排行榜

Leaderboard: overall score per model

Overall 是模型各项任务得分的平均值,与 Kaggle 排行榜使用的规则相同。

模型 Write Know Fix Write + 提示 Overall 写出的已弃用名字数
GPT-6 Astra 100% 100% 100% 92% 98% 0
Claude Opus 5 67% 95% 88% 75% 81% 6
Claude Sonnet 5 67% 82% 75% 83% 77% 9
GPT-5.4 67% 77% 75% 83% 76% 8
GPT-5.5 67% 91% 75% 67% 75% 5
Gemini 3.7 Flash 58% 91% 75% 58% 71% 9
Gemini 3.8 Flash 58% 91% 75% 58% 71% 8
Claude Sonnet 4.5 42% 68% 50% 50% 52% 21
Gemini 3.1 Pro 25% 82% 63% 33% 51% 17
GPT-5.4 mini 33% 64% 38% 58% 48% 19
GLM-5 17% n/a 75% 42% 44% 17
Gemini 2.5 Pro 17% 50% 13% 25% 26% 27
Gemma 4 31B 33% n/a 13% 25% 24% 24
Claude Haiku 4.5 0% 45% 13% 25% 21% 40
Qwen 3 235B 0% 23% 13% 25% 15% 49
DeepSeek-R1 8% n/a 0% 8% 6% 46
gpt-oss-120b 0% n/a 0% 0% 0% 52

有两种模式弱于上述发现。三组同系列模型中,有两组明显提升(Sonnet 4.5 到 5:52% 到 77%;Gemini 2.5 Pro 到 3.1 Pro:26% 到 51%),而 GPT 这一组打平(GPT-5.4 76%,GPT-5.5 75%)。价格并不是好的参考:GPT-5.4 以不到十分之一的成本($0.10 对 $1.36)与 GPT-5.5 持平。

让我意外的地方

我原本以为会是一个知识截止时间的故事:新的改名没被掌握,旧的改名被掌握。结果恰恰相反。模型知道这些改名,却仍然写出它们读得最多的教程里的名字。那个只修一半的情况更让我意外。我写那个案例是为了抓住忘记单位的模型。几乎没有模型忘记单位。它们忘记的是名字。

这改变了我审查 AI 代码的方式

我以前把“模型知道当前 API”当作要检查的东西。这是错误的检查。问模型发生了什么变化,并不能告诉你它会写出什么。对于遥测代码,我现在对照规范检查名称,而不是对照我的记忆,并且我把改变了单位但没有改变名称的 diff 视为 bug。

这对你意味着什么

  • 在 CI 中对遥测名称做 lint。规范的注册表标记了每个已弃用的名称及其替代项。对照该列表检查字符串字面量,会标记出本文中统计的每个已退役名称,db.system包括在内。
  • 把规范版本放进提示词,然后仍然做 lint。它在这里把漂移减少了三分之一,但也让模型编造名称。如果可以,粘贴你需要的当前名称,而不是版本号。
  • 优先使用固定到某个版本的生成常量。在 Go 中,semconv 版本在导入路径里。有意地升级它。
  • 一起审查单位和名称。单位变了但名称没变的直方图是最难发现的漂移,因为 diff 看起来像修复。
在你工作中使用的模型上试试

粘贴这个提示词:

Language: Python.
Wrap this psycopg query in an OpenTelemetry client span. Record which database system it is, the database name, the operation, the table and the query text.

def list_orders(conn, customer_id):
    with conn.cursor() as cur:
        cur.execute('SELECT * FROM orders WHERE customer_id = %s', (customer_id,))
        return cur.fetchall()

Follow the current OpenTelemetry semantic conventions. Write attribute keys and metric names as string literals rather than SDK constants. Return one complete code block and nothing else.

把答案保存为answer.py并运行:

grep -nE ["'](db\.system|db\.name|db\.operation|db\.statement|db\.sql\.table|net\.peer\.name)["']" answer.py

任何命中都是已退役的名称。当前的是db.system.name,db.namespace,db.operation.name,db.query.text,db.collection.name和server.address。在评论中告诉我你用了哪个模型以及它写了什么。

我接下来会测量什么

  • 更多重复。七个模型运行了两次 Write。每个模型都应该把每个任务运行多次,并报告离散程度。
  • 名称而不是版本。把当前名称粘贴到提示词中,是消除了漂移和猜测,还是只消除了漂移?
  • 时间之外的单位。评分器只检查ms对照s。字节和计数单位也可能漂移。
  • GenAI 约定。它们搬到了自己的仓库,并且变化很快,这使它们成为下一个要查看的地方。

局限性

  • 案例数少。Write 有 12 个案例,Know 22 个,Fix 8 个。Claude Sonnet 5 在 Write 上的 67% 的 95% Wilson 区间为 39% 到 86%。重复运行使一个模型最多翻转了 12 个 Write 案例中的 3 个,所以我不会声称表格中间有任何顺序。
  • 四个推理模型缺少 Know,它们在思考时用尽了答案预算。
  • 缺少 Grok。Grok 4.5 和 4.6 通过 Kaggle 的模型代理返回了 404。
  • 一次严格的调用。Claude Opus 5 只丢了一个 Write 用例,原因是为一个自定义键命名app.ledger.entry_count。规范自其移动端约定以来就拥有该app.*命名空间,因此评分器将其视为臆造,且该规则对每个模型一视同仁。
  • 一个移动的目标。每次 semconv 发布都会淘汰更多名称。在下一次发布后重新运行只需一份新的基准真值导出,这也正是让该基准测试自身不会过时的原因。

我的基准测试

Kaggle 基准测试: https://www.kaggle.com/benchmarks/applesone/semconv-drift

The public Semconv Drift benchmark on Kaggle: 4 tasks, 17 models, GPT-6 Astra on top

四个任务,每个都有自己的排行榜和完整任务代码:

交互式结果:一个可排序的排行榜,包含置信区间和所有图表,见https://vignesh2027.github.io/semconv-drift/

The interactive results site

代码、评分器和基准真值:

GitHub logo vignesh2027/semconv-drift

AI 模型编写的 OpenTelemetry 代码会使用规范已淘汰的名称吗?一个在代码中针对 26 个规范版本的 1,563 个名称进行评分的 Kaggle 基准测试。

Semconv Drift

AI 模型编写的 OpenTelemetry 代码会使用规范已淘汰的名称吗?

OpenTelemetry 的语义约定为遥测记录的每一项命名:http.request.method,db.system.name,http.server.request.duration。这些名称在版本之间会变化。基于旧教程训练的模型会不断写出旧名称,而且不会有任何明显的失败:数据仍在流动,而仪表盘和告警却悄然不再匹配。

网站·Kaggle 基准测试· 任务:Write·Know·Fix·带版本提示的 Write·结果

Semconv Drift 在 Kaggle Benchmarks 上衡量这一点,包含四个任务且没有 AI 评判。每个答案都在代码中针对规范 26 个版本(v1.21.0 至 v1.44.0)中的 1,563 个属性、指标和事件名称进行评分。

任务 用例数 它要求什么 什么算正确
Write 12 用 Python、Go 和 TypeScript 为日常代码(HTTP 服务器和客户端、Postgres、Redis、Kafka、gRPC、指标、资源)添加埋点 只使用当前名称,不得在某个规范下臆造名称
…



analyze.py以及charts.py从 Kaggle 运行中重新生成本文中的每一个数字和图表。如果你维护 OpenTelemetry 埋点并希望添加用例,请在仓库中提交 issue。