OpsPilot 项目实践:构建 PromQL 生成能力 Benchmark,并完成大模型选型

这篇博客记录的是我们在 OpsPilot 创新实训项目中的一次阶段性工作:围绕“让大模型自动生成 PromQL”这个能力,搭建了一套 benchmark,扩充测试集,设计 prompt,完成自动评分,并基于真实评测结果做了一轮模型选型。

这不是一篇单纯的 PromQL 教程,而是一次比较完整的工程实践记录。我们并不是简单地“调用一个大模型写 PromQL”,而是尝试把 PromQL 生成这件事做成一个可评测、可复现、可接入后端的模块。


1. 项目背景:OpsPilot 为什么需要 PromQL 生成能力

OpsPilot 是一个面向智能运维场景的 Agent 平台。它的目标不是只回答“哪里可能有问题”,而是能够结合告警、指标、日志、服务状态等上下文,辅助用户完成故障排查。

在真实运维流程中,Prometheus 是非常常见的指标系统,而 PromQL 是查询指标的核心语言。例如:

  • 服务是否存活?
  • 最近 5 分钟 QPS 是否升高?
  • 5xx 错误率是多少?
  • 哪个接口 P95 / P99 延迟最高?
  • 数据库是否不可用?
  • 服务是否刚刚重启?
  • 是否存在日志风暴?

这些问题都可以通过 PromQL 查询 Prometheus 得到答案。

但是 PromQL 对普通用户并不友好。写对一个查询,需要知道指标名是什么、label 有哪些、counter 类型指标是否应该用 rateincrease、histogram 分位数是否应该用 histogram_quantile、聚合时是否保留了正确 label、错误率分母是否需要保护除零等。

因此,我们希望 OpsPilot 能够根据用户问题、告警场景和可用指标上下文,自动生成可靠的 PromQL 查询。


2. 为什么要专门评测 PromQL 生成能力

一开始很容易有一个误区:既然大模型看起来会写 PromQL,那是不是直接接进去就行?

实际测试后发现,不能这么简单。

PromQL 生成和普通文本生成不一样,它有很强的工程约束。一个查询看起来像是对的,但可能存在很多隐蔽问题:

  • 使用了当前系统里不存在的指标名;
  • 使用了 metric context 中没有声明的 label;
  • 对 counter 指标直接求平均,没有使用 rateincrease
  • 错误率分母没有使用 clamp_min 保护,可能出现除零;
  • 使用 histogram 计算 P95 / P99 时没有保留 le label;
  • 用户问题里没有相关指标时,模型却编造了一个指标;
  • 输出中混入 Markdown、解释文字或推理过程,导致后端无法稳定解析。

所以我们决定不只“凭感觉”选模型,而是先构建一套 PromQL 生成能力 benchmark,用统一测试集、统一 prompt、统一评分逻辑去比较不同模型。


3. Benchmark 模块设计

本次新增的模块位于:

benchmarks/promql_llm_eval/

核心结构如下:

benchmarks/promql_llm_eval/
  README.md
  .env.example
  requirements.txt
  config/
    models.yaml
  data/
    promql_cases.yaml
    metric_catalog.yaml
  prompts/
    zero_shot.md
    few_shot.md
    structured_output.md
    structured_fewshot.md
  src/
    dataset.py
    llm_client.py
    run_benchmark.py
    evaluate.py
    scoring.py
    prometheus_validator.py
    report.py
  docs/
    promql_llm_eval_final_summary.md
    promql_integration_recommendation.md

几个关键文件的作用如下:

  • promql_cases.yaml:PromQL 测试集,目前包含 50 条 case;
  • metric_catalog.yaml:指标目录,记录指标名、类型、label、用途和常见 PromQL 模式;
  • structured_fewshot.md:当前推荐的默认 prompt;
  • run_benchmark.py:批量调用不同大模型;
  • scoring.py:自动评分逻辑;
  • prometheus_validator.py:后续可用于连接 Prometheus 做实际查询验证;
  • docs/:保存可提交、可复用的最终报告和接入建议。

这套结构的目标是让 PromQL 生成能力不只是一个临时测试脚本,而是后续可以继续维护和扩展的子模块。


4. 测试集设计:从简单查询到边界反例

本次我们将 PromQL 测试集扩展到了 50 条 case,覆盖了 OpsPilot 后续可能遇到的主要运维场景。

覆盖类别包括:

  1. 基础查询

    • 服务存活 up
    • jobinstanceservice 过滤;
    • 当前 gauge 值查询;
    • 故障开关状态查询。
  2. QPS / Counter 类查询

    • rate
    • increase
    • counter 不能直接 avg
    • 过去 5 分钟每秒速率;
    • 过去 10 分钟新增请求数;
    • pathmethodstatus 聚合请求量。
  3. 错误率查询

    • 全局 5xx 错误率;
    • 按接口计算 5xx 错误率;
    • 按服务计算错误率;
    • 按状态码聚合;
    • 使用 clamp_min(..., 1e-9) 保护分母;
    • 区分 4xx 和 5xx;
    • success rate 成功率。
  4. 延迟查询

    • P50 / P95 / P99;
    • histogram_quantile
    • 按 path 计算 P95;
    • 按 service 计算 P99;
    • histogram 聚合时必须保留 le label;
    • 缺少 bucket 指标时拒绝编造查询。
  5. 时间窗口与对比

    • offset 10m
    • 当前 QPS 与 10 分钟前对比;
    • avg_over_time
    • max_over_time
    • min_over_time
    • 最近 30 分钟最大错误率。
  6. 故障场景

    • 数据库不可用;
    • 数据库错误率升高;
    • 日志风暴;
    • 日志文件过大;
    • 磁盘使用率升高;
    • 接口高延迟告警;
    • 接口 5xx 告警;
    • 服务重启检测 changes(process_start_time_seconds)
  7. 资源类指标

    • CPU 使用率;
    • 内存使用率;
    • 磁盘使用率;
    • 容器 CPU;
    • 容器内存;
    • Node Exporter 风格指标;
    • cAdvisor 风格指标。
  8. 边界与反例

    • 用户要求查询不存在 CPU 指标,但上下文中没有,应返回空 PromQL;
    • 用户要求使用不存在 label,应避免使用该 label;
    • 用户要求“平均 counter”,应改写为 rateincrease
    • 用户要求 histogram 延迟,但没有 bucket 指标,应返回空 PromQL;
    • metric context 中有多个相似指标时,选择最合适的指标;
    • 不得编造指标或 label。

这一步很重要。只有测试集中包含“容易出错”的场景,才能真正区分模型能力,而不是只测几个简单查询。


5. Prompt 演进:从 zero-shot 到 structured_fewshot

在这次实验中,我们尝试了多种 prompt 策略。

5.1 zero-shot

zero-shot 的方式很直接:给模型自然语言问题和指标上下文,让它直接输出 PromQL。

优点是输入短、token 少、速度快。缺点是复杂 PromQL 不够稳定,例如错误率分母保护、increaserate 的区分、histogram 聚合等细节容易漏掉。

5.2 few-shot

few-shot 会在 prompt 中加入几个 PromQL 示例,例如:

  • counter 查询速率用 rate
  • 查询一段时间新增数量用 increase
  • 错误率分母使用 clamp_min
  • P95 / P99 延迟用 histogram_quantile

few-shot 的正确率明显提升,但它通常只输出 PromQL 字符串,不方便后端拿到 used_metricsconfidence 等结构化字段。

5.3 structured

structured prompt 要求模型输出 JSON,例如:

{"promql":"...","used_metrics":["..."],"confidence":0.0}

这种方式对后端非常友好,但早期测试中,纯 structured prompt 在复杂 PromQL 上仍有一些扣分点,例如缺少 clamp_min 或错误使用 rate/increase

5.4 structured_fewshot

最后我们把 few-shot 示例和 structured JSON 输出结合起来,形成 structured_fewshot

它要求模型最终只输出一行 JSON:

{"promql":"...","used_metrics":["..."],"confidence":0.0}

同时在 prompt 中加入关键规则:

  • 只能使用 metric_context 中出现的指标;
  • 只能使用声明过的 label;
  • 没有合适指标时返回空 PromQL;
  • counter 查询速率使用 rate
  • 查询时间段内新增数量使用 increase
  • 错误率分母使用 clamp_min(..., 1e-9)
  • histogram_quantile 必须使用 *_bucket 指标;
  • histogram 聚合时必须保留 le
  • 不输出 Markdown、代码块、推理过程或多余字段。

从实验结果看,structured_fewshot 同时兼顾了 PromQL 正确性和后端解析稳定性,因此成为当前默认 prompt。


6. API 调试和工程问题

这次工作中也遇到了一些典型工程问题。

6.1 API Key 预算问题

一开始真实调用 API 时,平台返回了类似 “Budget has been exceeded” 的错误。后来确认是 API Key 预算为 0,而不是请求格式问题。重新创建并分配额度后,请求才正常进入模型调用。

这个问题提醒我们:调用大模型 API 时,需要区分几类错误:

  • Key 无效;
  • 权限不足;
  • 预算不足;
  • 模型不存在;
  • 请求格式错误;
  • 平台限流;
  • 模型响应超时。

不同错误不能简单混为“模型不可用”。

6.2 平台响应较慢

测试中发现,有些请求本地等待超时,但平台后台可能仍然继续生成并计费。因此我们加入了几个安全策略:

  • timeout-seconds=300,给慢模型足够等待时间;
  • retries=0,避免本地超时后自动重试造成重复扣费;
  • 每条结果写入 JSONL 后立即 flush,避免中途中断导致结果丢失;
  • 单模型连续 2 条 timeout 后跳过该模型后续 case。

这样做以后,benchmark 的稳定性明显提高。

6.3 GLM-5 的输出格式问题

GLM-5 在前期测试中容易输出较长 reasoning、Markdown code fence 或非标准 JSON,并且响应较慢。这不一定说明它不会 PromQL,但对自动化系统来说,格式不稳定和延迟过高本身就是问题。

因此在最终推荐中,我们没有把 GLM-5 作为默认模型候选。


7. 全模型评测结果

最终,我们在 structured_fewshot 条件下,对平台上的 15 个模型、50 条 case 进行了完整评测。

理论请求数为:

15 个模型 × 50 条 case = 750 次请求

实际写入记录数为 542 条。原因是部分模型连续 timeout 或 API error 后按照规则被跳过,避免无限等待。

完整跑完 50 条 case 的模型包括:

  • Ali-dashscope/DeepSeek-V3.2
  • Ali-dashscope/Kimi-K2.5
  • Ali-dashscope/Qwen3-Coder-Next
  • Ali-dashscope/Qwen3-Max
  • ByteDance-volcengine/Doubao-Seed-2.0-Code
  • ByteDance-volcengine/Doubao-Seed-2.0-lite
  • SDU-AI/DeepSeek-V4-Flash
  • SDU-AI/Qwen3-235B-A22B-Instruct-2507
  • SDU-AI/Qwen3-Coder-30B-A3B-Instruct
  • SDU-AI/Qwen3-Coder-Next

被跳过的模型主要包括:

  • Ali-dashscope/MiniMax-M2.5:连续 timeout;
  • Ali-dashscope/Qwen3.5-Flash:连续 timeout;
  • Ali-dashscope/Qwen3.5-Plus:连续 timeout;
  • SDU-AI/GLM-5:连续 timeout;
  • Ali-dashscope/Qwen3.6-Plus:HTTP 429 quota / concurrency error。

Top 5 结果如下:

排名 模型 平均分 JSON 可解析率 备注
1 SDU-AI/Qwen3-235B-A22B-Instruct-2507 99.24 50/50 高分,适合作高精度备用
2 ByteDance-volcengine/Doubao-Seed-2.0-Code 99.24 50/50 高分,代码类任务能力强
3 Ali-dashscope/Kimi-K2.5 99.16 50/50 质量稳定
4 Ali-dashscope/Qwen3-Max 99.10 50/50 综合能力较强
5 Ali-dashscope/Qwen3-Coder-Next 99.00 50/50 平均耗时约 3424ms,综合最均衡

从结果上看,最高分模型不一定就是默认模型。在线系统还需要考虑延迟、稳定性、输出格式、token 成本和后端接入复杂度。


8. 模型选型结论

最终我们给出当前阶段的模型选型建议。

默认模型

Ali-dashscope/Qwen3-Coder-Next

选择它的原因是:

  • 完整跑完 50 条 case;
  • 平均分 99.00,已经足够高;
  • JSON 可解析率 50/50;
  • 平均耗时约 3424ms;
  • 没有 timeout 或 API error;
  • 在准确性和响应速度之间最均衡。

虽然 SDU-AI/Qwen3-235B-A22B-Instruct-2507Doubao-Seed-2.0-Code 分数略高,但它们不一定比 Qwen3-Coder-Next 更适合作为在线默认模型。OpsPilot 是运维场景,响应速度和稳定性非常重要。

备用模型

备用模型建议选择:

  • SDU-AI/Qwen3-Coder-Next
  • SDU-AI/Qwen3-235B-A22B-Instruct-2507
  • Ali-dashscope/Kimi-K2.5

它们可以用于默认模型失败、复杂场景复核或后续多模型投票。

暂不推荐默认使用

暂不推荐作为默认模型的有:

  • SDU-AI/GLM-5
  • Ali-dashscope/MiniMax-M2.5
  • Ali-dashscope/Qwen3.5-Flash
  • Ali-dashscope/Qwen3.5-Plus
  • Ali-dashscope/Qwen3.6-Plus

主要原因是 timeout、API error、输出 reasoning / Markdown 或格式不稳定风险较高。


9. 对 OpsPilot 后续接入的意义

这次工作之后,PromQL 生成模块已经有了比较清晰的接入方案。

后续 OpsPilot 可以按下面的流程接入:

  1. 生成 metric context

    • metric_catalog.yaml、Prometheus metadata、告警规则和当前故障上下文中整理可用指标;
    • 只把必要的指标名、label、类型和说明传给模型。
  2. 调用默认模型和默认 prompt

    • 默认模型:Ali-dashscope/Qwen3-Coder-Next
    • 默认 prompt:structured_fewshot
  3. 解析 JSON 输出

    • 读取 promqlused_metricsconfidence
    • 如果 JSON 解析失败,最多要求模型修复一次;
    • 如果仍失败,交给人工确认。
  4. 做安全校验

    • used_metrics 必须都来自 metric_context
    • PromQL 中不能出现未声明指标或 label;
    • confidence 过低时不自动查询;
    • promql 为空时直接返回“当前上下文没有合适指标”。
  5. 查询 Prometheus

    • PromQL 查询是只读操作;
    • 调用 /api/v1/query
    • 查询失败时把错误结构化返回给 Agent。
  6. 交给 Agent 做根因分析

    • Agent 根据查询结果、日志线索、告警信息和知识库内容继续判断故障原因。

这个流程比“让大模型自由发挥”要安全很多,也更容易解释和调试。


10. 本次工作的收获

这次工作让我对“大模型接入工程系统”有了更具体的认识。

之前我可能会觉得,只要模型会写 PromQL,就可以直接接入 OpsPilot。但实际做下来发现,真正重要的是一整套工程闭环:

  • 要有测试集,不能只凭几个例子判断;
  • 要有指标目录,不能让模型乱猜指标;
  • 要有 prompt 约束,不能让模型自由输出;
  • 要有自动评分,才能比较不同模型;
  • 要有 timeout 和错误处理,否则 benchmark 本身不稳定;
  • 要有后端校验,不能完全相信模型输出;
  • 要有最终报告和接入建议,实验结果才不会停留在临时文件里。

这次我们最终沉淀出了:

  • 50 条 PromQL benchmark case;
  • 一份 metric catalog;
  • 一个默认 prompt:structured_fewshot
  • 一套批量评测、评分和报告生成脚本;
  • 一轮 15 模型横向评测结果;
  • 一份 OpsPilot PromQL 生成模块接入建议。

这些内容后续可以直接服务于 OpsPilot 的智能运维工作流。


11. 总结

本次工作不是简单地“测试哪个模型会写 PromQL”,而是围绕 OpsPilot 的实际需求,构建了一套可复用的 PromQL 生成能力评测和选型流程。

当前阶段结论如下:

  • 默认 prompt:structured_fewshot
  • 默认模型:Ali-dashscope/Qwen3-Coder-Next
  • 备用模型:SDU-AI/Qwen3-Coder-NextSDU-AI/Qwen3-235B-A22B-Instruct-2507Ali-dashscope/Kimi-K2.5
  • 暂不推荐默认使用:SDU-AI/GLM-5MiniMax-M2.5Qwen3.5-FlashQwen3.5-PlusQwen3.6-Plus

接下来,OpsPilot 可以在这个基础上继续推进 PromQL 生成服务的后端接入,把“自然语言问题 → PromQL 查询 → Prometheus 指标结果 → Agent 根因分析”这条链路真正打通。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐