首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >DMXAPI 与 Prometheus MCP Tool:一篇尽量不空谈 AI 的监控分析实践

DMXAPI 与 Prometheus MCP Tool:一篇尽量不空谈 AI 的监控分析实践

原创
作者头像
用户11852488
发布2026-04-01 20:58:13
发布2026-04-01 20:58:13
70
举报

过去我一直觉得,监控系统和大模型之间存在一种天然错位。

一边是 Prometheus 这类系统,它输出的是非常硬的事实:时间序列、标签、抓取间隔、查询结果、告警状态。另一边是大模型,它擅长语言、归纳、补全上下文、从零散线索中组织解释。问题在于,线上排障最忌讳“说得像”,而是要“证据链完整”。如果只是把一张 Grafana 截图扔给模型,让它判断为什么 RT 上升、为什么错误率升高,那大概率只是换了一种方式猜。

后来我开始认真看 MCP 生态里和运维、可观测性相关的工具,Prometheus MCP Tool 是其中一个非常有意思的切口。它的价值不在于“让模型会 Prometheus”,而在于把模型从“瞎看图”推进到“可以主动取数、解释查询、比较多个指标结果、形成有约束的分析过程”。这两者差别非常大。前者适合演示,后者才接近生产环境里值得信任的辅助系统。

这篇文章想写的不是“某个平台多厉害”,而是围绕一个具体主题展开:如何把 Prometheus MCP Tool 接进一个真实的监控分析工作流,让大模型在 CPU 飙高、延迟异常、错误率波动这类问题上,给出更像工程师而不是旁观者的辅助判断。过程中我会尽量保留命令、关键语句、PromQL、接口调用和一次真实风格的小 bug 排查,因为这些细节往往比“方案概述”更能说明问题。

先说一个非常朴素的判断:监控接入大模型后,最重要的不是模型本身,而是“模型拿到的数据形状”。

如果给它的是下面这种描述:

“最近接口变慢了,帮我分析一下可能原因。”

那它只能给出模板化答案,比如数据库慢查询、缓存击穿、外部依赖波动、线程池打满。这类回答不能说错,但也几乎没有信息增量。真正有价值的,是让它能按步骤拿到以下几类事实:

  1. 当前异常对应哪些指标。
  2. 这些指标的时间窗口是什么。
  3. 指标之间是否存在同步变化。
  4. 异常是在所有实例同时出现,还是只发生在某个标签子集。
  5. 当前查询结果里,有没有明显的“误读风险”,比如抓取抖动、counter reset、标签爆炸带来的聚合偏差。

Prometheus MCP Tool 的优势,恰恰是把这些“取事实”的步骤暴露成模型可以调用的工具,而不是让模型直接自由发挥。你可以把它理解成:给大模型一副手套,它不是替你修机器,但它终于可以碰到机器。

我做原型时,先搭了一个最小场景。服务是一个普通的 HTTP API,暴露 Prometheus 指标,Prometheus 定时抓取,MCP Tool 提供查询能力,大模型只负责分析和组织结论。为了尽量贴近真实情况,我没有用特别花哨的指标,只保留几个足够经典的信号:

代码语言:txt
复制
http_requests_total
http_request_duration_seconds_bucket
process_cpu_seconds_total
process_resident_memory_bytes
go_goroutines
up

如果是 Java 服务,也可以替换成 JVM 相关指标,比如:

代码语言:txt
复制
jvm_gc_pause_seconds_count
jvm_memory_used_bytes
tomcat_threads_busy_threads
hikaricp_connections_active

我比较推荐的接入顺序不是一上来就做“自动诊断”,而是先做“可控查询”。也就是说,先验证模型能不能稳定地从 Prometheus 里取出你想要的结果,再谈总结。这个顺序看起来慢,实际上节省很多时间,因为一旦取数阶段有问题,后面所有“分析”都会变成建立在错误事实之上的二次加工。

例如,先在本地把 PromQL 手工跑通:

代码语言:bash
复制
curl -G <PROMETHEUS_URL>/api/v1/query \
  --data-urlencode 'query=sum(rate(http_requests_total[5m])) by (method, status)'

再验证延迟分位数:

代码语言:bash
复制
curl -G <PROMETHEUS_URL>/api/v1/query \
  --data-urlencode 'query=histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, route))'

接着看 CPU 是否和请求量同步抬升:

代码语言:bash
复制
curl -G <PROMETHEUS_URL>/api/v1/query \
  --data-urlencode 'query=sum(rate(process_cpu_seconds_total[5m])) by (instance)'

这一步很机械,但非常关键。因为很多“AI 诊断失败”的根因,根本不是模型不行,而是你的查询语义自己就不清楚。例如你到底要的是“整体 QPS”,还是“按 route 聚合后的热点接口分布”;你到底在看“某一时刻结果”,还是“过去 30 分钟的变化趋势”;你要排除 5xx,还是专门盯 5xx。这些问题如果人自己都没说清楚,模型更不可能替你神奇补全。

Prometheus MCP Tool 真正顺手的地方,是它让上面这些动作可以进入一个连续会话中。比如一个较理想的对话不是:

“帮我分析为什么服务变慢了。”

而是:

“请先检查过去 15 分钟该服务的 QPS、P95 延迟、5xx 比例和 CPU 使用率。如果 P95 与 QPS 同时升高,再按 route 维度展开;如果只有单实例异常,再按 instance 聚合,并检查是否存在 goroutine 异常增长。最后只输出带证据的结论,不要给泛泛建议。”

这类提示词听起来很“规矩”,但监控场景里,规矩比聪明更重要。因为你不是在写一篇风格化文章,而是在逼近真实故障原因。模型最怕没有边界,监控最怕没有证据,这两者放在一起,唯一合理的方式就是把推理过程收窄。

我在实践里总结过一个简单原则:对 Prometheus MCP Tool 的使用,不要追求“模型自己想到什么就查什么”,而是要让它在一个半开放流程里工作。

所谓半开放,大概是这样的:

  1. 固定第一层查询维度,比如总量、错误率、延迟、资源使用。
  2. 允许第二层根据结果分叉,比如按 instance、route、status、pod 拆分。
  3. 限制最终输出格式,例如“现象、证据、怀疑点、下一步验证项”。

这样做的好处,是模型既有探索空间,又不会跑偏到“我猜也许是网络抖动”这种无法立刻验证的话术里。

为了让调用方式尽量贴近工程代码,而不是伪代码,我当时还写了一个最简单的 OpenAI 兼容接口调用。笔者在国内需要中转使用部分国际模型,在开发初期,快速低成本上原型,有时还有学校财务报销发票等需求,用的是 DMXAPI 做中转。当然,除了这种大模型中转平台,如果对于价格不敏感或者不需要开发票的开发者朋友,也可以考虑直连 Claude / Codex 等。如果使用的不是直连模型厂商官方的 API,要注意修改 base_url,而不能只修改 OPENAI_API_KEY。代码类似这样:

代码语言:python
复制
from openai import OpenAI

client = OpenAI(
    api_key="<LLM API KEY>",
    base_url="<LLM API BASE URL>"
)

messages = [
    {
        "role": "system",
        "content": (
            "你是一个偏 SRE 视角的分析助手。"
            "当拿到 Prometheus 查询结果时,只基于结果给出结论。"
            "不要编造不存在的指标,不要跳过证据链。"
        )
    },
    {
        "role": "user",
        "content": (
            "请结合 Prometheus MCP Tool 返回的结果,"
            "分析订单服务最近 15 分钟的异常,"
            "输出格式为:现象、证据、可能原因、下一步查询。"
        )
    }
]

resp = client.chat.completions.create(
    model="gpt-4.1",
    messages=messages,
    temperature=0.2
)

print(resp.choices[0].message.content)

这里有个细节,我强烈建议把 temperature 降低。写创意文案时你可以给它更大发挥空间,但做监控分析时,输出稳定性比语言表现更重要。尤其是多个工程师会反复复用同一套提示词时,越稳定越方便比较差异,也越容易回放问题。

除了模型参数,真正影响结果质量的,还有一个经常被忽略的问题:PromQL 结果本身不等于“事实解释”。这听起来像废话,但很多人会在这里踩坑。

比如下面这个查询:

代码语言:promql
复制
sum(rate(http_requests_total{job="order-service",status=~"5.."}[5m]))
/
sum(rate(http_requests_total{job="order-service"}[5m]))

它告诉你 5xx 比例,但不会告诉你 5xx 是不是集中在某个 route,也不会告诉你是否只有某一台实例在抖,更不会告诉你错误高峰是否和 CPU、内存、GC 同步变化。如果模型只拿到这一个数值,再聪明也只能从非常抽象的因果图谱里找说法。

所以我后来改成让工具按固定顺序查询,并把每一步结果显式地喂给模型,例如:

代码语言:txt
复制
步骤 A:整体 QPS、P95、5xx ratio
步骤 B:按 route 的 P95 和 5xx
步骤 C:按 instance 的 CPU、goroutine、memory
步骤 D:检查 up 和 scrape 结果,避免误把采集异常当服务异常

最后让模型只做一件事:组织和比对,而不是替代整个观测过程。

讲一个我印象很深的小插曲。那次我在接 Prometheus MCP Tool 的查询封装层时,写了一个很不起眼的 bug,导致模型一开始总是给出很奇怪的判断。我最初甚至以为是提示词写得不够严谨,后来才发现问题出在查询字符串拼装。

当时为了图省事,我写了这样一段代码:

代码语言:python
复制
def build_query(metric: str, job: str, window: str = "5m") -> str:
    return f'sum(rate({metric}{{job="{job}"}}[{window}])) by (instance)'

看起来没什么问题,查询结果也能返回值。但我的真实需求其实分两类:

  1. 有些指标需要按 instance 聚合。
  2. 有些指标本身就是直方图桶或者已经包含 route 维度,需要按别的标签聚合,甚至不能直接这样包一层 sum(rate(...)) by (instance)

例如延迟分位数的正确写法应该更接近:

代码语言:promql
复制
histogram_quantile(
  0.95,
  sum(rate(http_request_duration_seconds_bucket{job="order-service"}[5m])) by (le, route)
)

但我那个统一模板函数会把所有查询都强行格式化成同一种样子。更糟糕的是,我当时为了快速跑通流程,在上层调用里又偷懒写了:

代码语言:python
复制
query = build_query("http_request_duration_seconds_bucket", "order-service")

结果就是,模型拿到的根本不是 P95,而是桶计数的某种按实例聚合速率。数值看起来“像真的”,变化趋势也“有点道理”,这类错误最危险,因为它不会直接报错,只会把你往一个似是而非的方向上带。

我最早怀疑这个问题,是因为模型连续两次都把“高延迟”解释成“请求量上升导致 CPU 紧张”,但我手工去看面板时发现 CPU 其实很平稳,而延迟主要集中在两个特定 route 上。这里出现了第一处违和感:如果是整体流量上升,为什么 route 分布不扩散,而是集中在少数接口?

于是我开始回查工具日志,把每次实际发给 Prometheus 的查询打印出来:

代码语言:python
复制
print("DEBUG query:", query)

结果日志里出现的是:

代码语言:txt
复制
DEBUG query: sum(rate(http_request_duration_seconds_bucket{job="order-service"}[5m])) by (instance)

当时看到这一行,我脑子里第一反应不是“终于找到 bug 了”,而是有一点尴尬。因为这不是复杂系统里那种难以捉摸的竞态问题,而是非常典型的“为了统一接口,过度抽象,把语义抽坏了”。这种错误很多工程师都会犯,包括我自己。写封装时总想优雅一点、通用一点,结果把监控查询里最重要的部分,也就是“每个指标到底该怎么读”,给压平了。

后面的修复方式其实并不复杂,核心是不要假装所有指标都能走统一模板,而是把查询定义成显式的、可枚举的分析单元:

代码语言:python
复制
QUERIES = {
    "qps_by_status": '''
        sum(rate(http_requests_total{job="order-service"}[5m])) by (status)
    ''',
    "p95_by_route": '''
        histogram_quantile(
          0.95,
          sum(rate(http_request_duration_seconds_bucket{job="order-service"}[5m])) by (le, route)
        )
    ''',
    "cpu_by_instance": '''
        sum(rate(process_cpu_seconds_total{job="order-service"}[5m])) by (instance)
    ''',
    "goroutines_by_instance": '''
        go_goroutines{job="order-service"}
    '''
}

然后上层不是传“指标名”,而是传“分析意图”:

代码语言:python
复制
def get_query(name: str) -> str:
    if name not in QUERIES:
        raise ValueError(f"unknown query: {name}")
    return QUERIES[name]

这种改法看似笨,扩展性也不如“万能模板”好看,但它更符合监控场景的事实:监控分析天然就是领域化的。QPS、错误率、分位数延迟、CPU、GC,本来就不是同一种指标,没必要为了接口统一而硬压成同一个函数签名。你以为你在抽象,其实你在消灭语义。

修完这个 bug 之后,我又补了一层很有必要的保护:把每次模型发起的查询和查询目的同时记录下来。因为单看查询字符串,有时候你不容易理解它“本来想验证什么”。如果同时打印:

代码语言:txt
复制
intent=p95_by_route
query=histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="order-service"}[5m])) by (le, route))

那排查就会容易很多。尤其是多人协作时,下一位接手的人不需要先猜“这条 PromQL 是不是写错了”,而是能直接把查询和分析意图对应起来。

写到这里,我反而越来越觉得,Prometheus MCP Tool 的价值不只是“给 LLM 多一个工具”,而是在逼我们重新整理监控系统里的知识结构。过去很多排障经验都停留在脑子里,比如“如果 P95 升高但 QPS 没涨,就先看依赖或热点 route”“如果只有某个实例 CPU 飙高,优先排查线程卡死、热点循环或日志爆量”“如果 up 变成 0,不要急着怪业务,先确认采集链路”。这些经验以前是工程师手工执行的,现在因为要让模型参与,反而必须把这些隐性套路显性化。

这件事的副产品其实很珍贵:你会被迫区分哪些是事实,哪些是经验;哪些是可以查询得到的,哪些只是概率判断;哪些步骤适合自动化,哪些地方仍然需要人做最终裁决。很多团队一谈“AI + 运维”就容易直接跳到“自动根因分析”,但我现在更认同一种更保守、也更可落地的路线:先做查询代理,再做证据整理,最后才是诊断建议。这个顺序慢一点,却不容易把系统带进错误自信。

如果把主题再收束一点,围绕 Prometheus MCP Tool,我觉得最值得投入的不是花哨的 agent 流程,而是下面三件事。

第一,建立一组稳定的“诊断起手式查询”。

也就是无论什么告警进来,先统一拉哪些指标。比如 QPS、错误率、P95、CPU、内存、goroutine、实例存活状态。不要每次都从零开始猜要查什么。固定的起手式相当于把经验沉淀成流程,模型才有可能在一致输入上表现稳定。

第二,避免为了通用性牺牲监控语义。

直方图、counter、gauge、本身就不是一种东西;按 route 聚合和按 instance 聚合,也不是同一个问题。把这些差异保留下来,工具层反而更可靠。监控系统里过度抽象,往往不是高级设计,而是高级 bug 的温床。

第三,让模型输出“下一步验证项”,而不是只给“结论”。

一个成熟的监控分析结果,最好像这样收尾:“目前最可能的原因是订单创建接口对下游库存服务调用变慢,证据是该 route 的 P95 从 180ms 升至 1.8s,而整体 CPU 平稳,错误率未同步上升。下一步应查询库存服务客户端超时指标或上游依赖 RT。”这样的输出有两个好处,一是保留可执行性,二是承认它仍然只是阶段性判断,而不是终审结论。

我现在回头看这类原型,最大的感受不是“模型真聪明”,而是“终于有机会把监控经验写成机器可协作的形式”。Prometheus MCP Tool 在这里像一个接口层,它把 Prometheus 里的指标世界和大模型的语言世界接了起来,但真正决定效果的,依然是工程师是否愿意认真处理语义、查询、边界和证据链。

如果只是想做一个演示,随便查几条 PromQL,让模型总结两段话就够了;但如果目标是做一个能在团队里长期使用的小工具,那就必须承认监控分析不是文学创作,它更像法庭陈述。每一句“可能原因”都应该能回到一条查询、一个标签维度、一个时间窗口或者一个可继续验证的假设上。

也正因为如此,我对这类工具的期待一直比较克制。它不应该替代值班工程师,不应该在证据不足时给出过度肯定的结论,更不应该把“会说人话”误认为“真的懂系统”。但只要边界画得对,它确实能节省很多重复劳动:帮你把查询流程标准化,帮你把零散指标组织成更可读的分析文本,帮新人更快进入问题上下文,也帮老工程师少打一些重复字。

从这个角度看,围绕 Prometheus MCP Tool 的实践,最有意义的地方不在于“AI 味儿”有多浓,而在于它迫使我们把那些原本靠经验和感觉运转的排障动作,变成一组可以讨论、可以复盘、可以持续修正的工程对象。这件事本身,就已经很值了。

本文包含AI生成内容

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档