这是提交给Kaggle 基准测试挑战赛的作品
我基准测试了什么
TL;DR。我测试了 17 个 AI 模型在编写、回忆和修复 OpenTelemetry 插桩方面的表现,并针对规范的 26 个版本进行了代码评分。
- 17 个中有 16 个模型写出了已废弃的名称,并且83%的这些名称已被废弃超过一年。
- 13 个中有 12 个模型在被直接询问时,写出了它们本已正确替换的名称。
- 17 个中有 7 个通过更改指标的单位并保留其已废弃的名称来“修复”指标,这会在两方面都破坏它。
- 用一句话指明规范版本,可将废弃名称减少36%,并让模型编造出更多名称。
我问 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. 这种漂移是旧的,不是新的
17 个模型中有 16 个在 Write 中至少写了一个已弃用的名称,共使用 357 次。如果这是关于训练截止时间的问题,那么已弃用的名称应该是模型从未见过的新近名称。但事实并非如此:
- 357 次中的 297 次(83%)在我运行基准测试时已经弃用超过一年。
- 238 次(67%)已经弃用超过两年,也就是在 2024 年 10 月之前。而阵容中的每个模型都是在那之后发布的。
- 已弃用名称的中位弃用时间为2.4 年更早。
这些模型并非不了解新闻。它们读过变更日志,也读过在此之前的多年教程,而教程胜出了。db.system是最明显的案例:在改名近两年后,仍有 12 个模型使用了 24 次。
训练截止时间唯一能解释的名称是 2026 年 1 月的rpc.*改名。有 16 个模型写了这些名称。GPT-6 Astra 是唯一的例外,而且它也避开了所有更早的已弃用名称,因此仅凭较晚的截止时间并不能解释它完美的 Write 得分。
2. 它告诉了我新名称,然后写了旧名称
因为 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. 半吊子修复
一个 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. 一句话的上下文有帮助,但还不够
提示任务重复了那 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. 排行榜
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
四个任务,每个都有自己的排行榜和完整任务代码:
| 任务 | 链接 |
|---|---|
| Write | semconv-drift-write |
| Know | semconv-drift-know |
| Fix | semconv-drift-fix |
| 带版本提示的 Write | semconv-drift-write-with-version-hint |
交互式结果:一个可排序的排行榜,包含置信区间和所有图表,见https://vignesh2027.github.io/semconv-drift/
代码、评分器和基准真值:
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。








