如何让 AI 代理访问运行时跟踪

发布: (2025年12月30日 GMT+8 22:00)
12 min read
原文: Dev.to

Source: Dev.to

谁适合阅读?

本文面向使用 AI 编码助手(Claude、Cursor 等)进行本地真实应用调试的开发者,帮助他们获得比静态代码分析更快、更具体的答案。

AI 编码助手非常擅长阅读代码。只要指向一个代码仓库,它就能几乎瞬间解释控制流、追踪依赖、发现模式并提出修改建议。

但当你在本地调试时,一切却变慢了:

  • “在测试中很快,点几下就卡住了。”
  • “这个请求大约每 20 次运行就会挂一次。”
  • “重启服务器后才正常。”
  • “代码没有改动,却突然超时。”

这些并不是代码理解上的问题,而是 代码实际执行方式 的问题。

目前,助手大多只处理静态输入。它们知道代码写了什么,却看不到代码运行时的表现。因此,你不得不去做那段不那么光鲜的工作:复现问题、检查追踪或日志、找出慢点或失败点,然后再把这些信息翻译成文字给助手。

正是这一步的翻译耗费了大部分时间。

本文展示了如何通过 OpenTelemetry 追踪和我编写的一个小工具 otel‑mcp,在 本地调试 时省去这一步。

当前 AI 调试工作流(以及为何它慢)

如果你曾使用 AI 代理调试除语法错误之外的任何问题,这个循环可能会让你感到熟悉。

之前

You:    The /users endpoint is slow locally.
Agent: I see two DB queries and an external call. Which part is slow?
You:    (spends 10 minutes checking logs / traces / console output)
You:    The external API averages ~600 ms.
Agent: Add caching. Here’s how.

代理的建议甚至可能是正确的,但请注意时间都花在哪里了:

  • 没有编写代码
  • 没有理解逻辑

大量时间被用于 寻找证据解释证据。你充当了运行系统与模型之间的人类适配器。

问题不在于推理;问题在于 可见性

阅读代码并不能告诉你它的行为

这里有一个完全正常的端点:

app.get('/api/users/:id', async (req, res) => {
  const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
  const posts = await db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]);
  const enriched = await enrichUserData(user, posts);
  res.json(enriched);
});

仅凭源码,代理就可以说出一些合理的话:

  • 有两个数据库查询。
  • enrichUserData 可能会进行一些 I/O。
  • await 是顺序执行的。
  • 可能存在慢速依赖或缺失索引。

这些都是真的,但不足以进行调试。当你真正要解决本地问题时,你关心的是:

  • 哪一步 现在这台 机器上很慢?
  • 它是一直慢还是偶尔慢?
  • 是否涉及重试或超时?
  • 工作是否在池或锁后排队?
  • 是否有错误发生且被吞掉了?

你无法仅靠阅读代码得到如下答案:

“这个查询大约耗时 430 ms,因为它在没有索引的情况下返回了约 50 行。”

“HTTP 调用本身没问题,但重启后连接复用会卡住。”

这些答案只有在代码实际运行时才会出现。

跟踪:AI 实际可用的执行数据

分布式跟踪为你提供了请求执行的结构化记录。

跟踪(trace) 是由 跨度(span) 构成的树。每个跨度代表一次计时操作——数据库查询、HTTP 调用、缓存访问——并带有持续时间、状态以及可选的元数据等属性。

使用 OpenTelemetry 自动仪表化时,你通常会得到恰好对应本地延迟主要来源的跨度。

同一个端点可能会产生如下的跟踪:

Trace: GET /api/users/123   (total: 892 ms)

  db.query users_by_id                 6 ms
  db.query posts_by_user_id          438 ms   rows=52
  enrichUserData                     440 ms
    http.client GET /user-metadata   411 ms   status=200
    cache.set                          9 ms

这是一组具体的、计时的、层级化的数据。它告诉你执行了什么、执行顺序以及每一步耗时——正是手动调试时你所寻找的信息。

如果代理能够直接检查这些数据会怎样?

otel‑mcp:AI 代理的追踪

“MCP(模型上下文协议)是一种让 AI 代理在会话期间调用外部工具的方式。”

otel‑mcp 是一个小型 MCP 服务器,可在本地开发时向 AI 代理提供运行时追踪。它实现了三件简单的事:

  1. 运行一个 本地 OTLP HTTP 收集器(仅限 localhost)。
  2. 最近的追踪存储在内存中(临时的,面向开发)。
  3. 暴露一小套 查询工具,供代理通过 MCP 调用。

不是 APM——没有 UI、没有仪表盘、没有保留策略。它专为 使用 AI 代理进行本地调试 设计。

这个功能适用于哪些代理?

otel‑mcp 可与 任何兼容 MCP 的 AI 编码助手 配合使用,包括:

  • Claude Code
  • Cursor
  • 任何其他支持 MCP 工具的工具

如果你的代理能够调用 MCP 工具,就可以通过 otel‑mcp 查询追踪。

当代理能够看到追踪时会有什么变化?

让我们重放相同的调试场景。

使用 otel‑mcp 后

You:    The /users endpoint is slow locally.
Agent: (lists slow traces from the last few minutes)
Agent: I found 23 slow requests. The posts query averages ~430 ms and
       returns ~50 rows without an index. The external API averages ~70 ms.
       Adding an index on posts(user_id) should fix this.

不再需要“你能检查一下追踪并告诉我吗”的来回——代理可以直接检查执行数据并给出可操作的建议。

TL;DR

  • 静态代码分析告诉你 代码做了什么,而不是它在运行时 如何 表现。
  • OpenTelemetry 跟踪提供了缺失的运行时可视化。
  • otel‑mcp 弥合了这一差距,将最新的跟踪暴露给任何 MCP‑compatible AI assistant,将缓慢的手动调试循环转变为快速的 AI‑驱动循环。

Source:

代理拥有的工具

otel‑mcp 提供了一组刻意保持精简且可预测的工具:

get_summary()

哪些服务在产生追踪?数量多少?最近有错误吗?

list_traces(filters)

显示慢速追踪、错误追踪,或特定服务的追踪。

get_trace(trace_id)

获取单个请求的完整 span 树。

query_spans(where)

查找符合条件的 span,例如:

duration > 100 AND status = error
http.status_code >= 500

示例

Agent calls:
query_spans({ where: "duration > 100 AND http.status_code >= 500" })

Result:
12 spans from the last 5 minutes showing slow, failed API calls

clear_traces()

在测试运行之间重置状态。

这些工具反映了人们实际调试的方式:先宽泛搜索,再逐步缩小范围,最后检查细节。

您需要的准备

在开始设置之前,请确保您拥有:

  • 一个已 OpenTelemetry 注入的应用程序(或愿意添加它)
  • 一个兼容 MCP 的 AI 代理(Claude Code、Cursor 等)
  • 一个支持 OpenTelemetry 的运行时环境(Node.js、Java、Go、Python,…)

您不需要生产环境的可观测性或托管的后端——全部在本地完成。

设置

如果您已经在使用 OpenTelemetry,设置通常非常简单——只需将导出器指向本地 collector 即可。

典型的 Node.js 配置

import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  serviceName: 'my-app',
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

自动仪器化通常能够捕获本地大部分重要信息:

  • HTTP 处理器
  • 数据库查询
  • 出站 HTTP 调用
  • 缓存

如果没有捕获到所需信息,在关键代码段手动添加一个 span 通常就足够了。

为什么它在本地调试时效果很好

  • In‑memory storage – 快速、简单,足以满足本地迭代的需求。
  • Constrained queries – 代理会提出有针对性的问题,而不是把所有内容都拉进上下文。
  • Local‑only by default – 默认仅在本地运行,避免意外泄露生产数据的风险。
  • Shared collector – 如果运行多个代理客户端,它们会共享同一批追踪信息。

目标不是构建完整的可观测性平台,而是消除调试过程中的摩擦。

常见问题

  • 跟踪未显示?
    检查您的应用是否导出到 http://localhost:4318/v1/traces

  • 代理未检测到工具?
    确保在 MCP 配置中包含 otel‑mcp

  • 使用多个代理?
    第一个会启动收集器;其他会自动连接。

  • 跟踪中没有有趣的内容?
    您可能需要在要调查的代码周围手动添加一个 span。

限制(以及它们在此为何可接受)

  • 不是生产级 APM – 没有仪表板、警报或长期存储。
  • 自动仪器化并不完美 – 某些库和异步边缘需要手动 span。
  • 跟踪可能包含敏感数据 – 将收集器保持在本地主机上,并在需要时对属性进行脱敏。
  • 存在开销 – 通常在本地可以接受;如果你的代码非常紧凑,请进行测量。

对于本地调试,这些权衡通常是可以接受的。

试一试

如果你在本地使用 AI 代理进行调试,并且发现自己不断需要解释日志或跟踪中看到的内容,那么值得一试。

👉 https://github.com/moondef/otel-mcp

  • 继续使用 OpenTelemetry。
  • 在开发期间将导出器指向 localhost
  • 让代理查询跟踪,而不是让你去总结它们。

一旦代理能够看到代码的实际运行情况,对话就会改变——调试速度也会明显加快。

Back to Blog

相关文章

阅读更多 »