
前段时间,公司同事了解到我正在研究故障根因分析智能体,便给我推荐了一个开源 SRE Agent——HolmesGPT。最初只是粗略了解了一下,大致知道它是通过多轮 ReAct 的方式来做根因分析,但具体的实现逻辑一直没有深入拆解。于是这个周末专门抽时间系统地研究了这个项目,便有了这篇总结文章。
本文基于 HolmesGPT 源码分析、官方文档(holmesgpt.dev/0.28.0)及行业调研报告,对其架构设计、核心机制和关键工程决策进行系统梳理,希望对正在探索运维智能体方向的同学有所参考。
HolmesGPT 是由 Robusta 开源、目前已进入 CNCF Sandbox 的 SRE Agent 项目(2025 年 10 月入沙箱)。官方的定义是 "The CNCF SRE Agent"——一个面向生产事故调查、根因分析与云原生故障处理的自治智能体,而非简单的 AI 问答工具。
在运维领域的智能体分类中,SRE Agent 专注服务可用性这一核心命题,典型工作流是:收到告警 → 自动调查 → 定位根因 → 给出修复建议。根因分析(RCA)是其核心能力,但 RCA 并非 SRE 专属——NetOps、DBOps、SecOps 场景下同样需要,只是分析对象不同。目前市场上除 HolmesGPT 之外,还有 k8sGPT(偏静态扫描)、Datadog Bits AI、Dynatrace Davis AI、PagerDuty Copilot 等产品,独立开源产品灵活性高,平台内置产品数据集成更深。
HolmesGPT 的核心能力可以用一句话概括:把监控、日志、追踪、Kubernetes 资源状态、云 API、知识库与工单系统连接成一条可执行的调查链路。从版本演进看,0.26.0 引入了 Skills 扩展模型,标志着项目从早期"runbook + catalog.json"的旧形态,正式演化为"技能目录 + 工具调用 + 审批/审计"的新体系。
通过阅读源码(https://github.com/HolmesGPT/holmesgpt),HolmesGPT 的架构可以划分为五个层次,各层职责边界清晰:
┌──────────────────────────────────────────────────────┐
│ 入口层(Entry Points) │
│ server.py (FastAPI HTTP) holmes_cli.py (CLI) │
├──────────────────────────────────────────────────────┤
│ 编排层(Orchestration) │
│ Config → ToolCallingLLM → conversations.py │
├──────────────────────────────────────────────────────┤
│ 核心引擎(Core Engine) │
│ LLM ←→ ToolExecutor ←→ ToolsetManager │
├──────────────────────────────────────────────────────┤
│ 插件系统(Plugin System) │
│ Toolsets(50+) | Sources | Destinations │
│ Skills | MCP | Transformers │
├──────────────────────────────────────────────────────┤
│ 基础设施(Infrastructure) │
│ Context Window 管理 | OAuth | Safeguards │
└──────────────────────────────────────────────────────┘
入口层提供两种接入方式:server.py 基于 FastAPI 暴露 HTTP API(支持 SSE 流式输出),holmes_cli.py 提供命令行交互。两者共用同一套核心引擎,没有独立的逻辑分支。
编排层的核心是 ToolCallingLLM 类,实现 Agentic Loop 主控逻辑。
插件系统是可扩展性核心,涵盖 50+ 数据源的 Toolset、Source/Destination 插件接口、Skills 知识目录和 MCP 协议适配层。
基础设施层解决三个生产级问题:超长调查中的 Context Window 管理、工具调用安全护栏、OAuth 多租户认证。
ToolCallingLLM 是整个系统最核心的类,其 call_stream() 方法实现完整的 Agentic Loop:
def call_stream(self, msgs, max_steps=10, ...):
while num_llm_calls < max_steps:
compact_if_necessary(msgs) # 上下文压缩
response = self.llm.completion(msgs, tools=self._get_tools())
if response.has_tool_calls:
results = execute_tools_concurrently(response.tool_calls)
msgs = append_tool_results(msgs, results)
else:
yield ANSWER_END event
return
num_llm_calls += 1
call() 是 call_stream() 的同步包装器,这个设计使 CLI 终端实时渲染和 HTTP SSE 推流共用同一套引擎。
防死循环护栏(safeguards.py):检测到相同工具+相同参数被调用时,直接返回错误强制 LLM 换方向,五行代码解决了工程实践中的常见问题。
上下文压缩:单工具结果超大时写入磁盘(spill to disk);整体 Context 超限时调用 LLM 对历史消息做摘要压缩(compact_if_necessary)。两级策略保证长调查不中断。
任务外部记忆(TodoWriteTool):让 LLM 维护结构化任务列表作为外部工作记忆,每轮更新状态(pending/in_progress/completed/failed),解决长调查中"忘记"未验证假设的问题,同时提供可审计的调查轨迹。
人工审批门控:Toolset 中可配置 approval_required_tools,LLM 调用写操作前暂停等待人工确认,实现"读操作自动 → 写操作审批"的安全分级。
YAML Toolset 的核心思想是把 Shell 命令或 API 调用通过 YAML 声明包装成 LLM 可以调用的函数,无需编写任何 Python 代码。以 kubernetes.yaml 为例:
tools:
- name: "kubernetes_jq_query"
description: "Use kubectl to get json and filter with jq."
parameters:
kind: {type: string, required: true}
jq_expr: {type: string, required: true}
script: |
kubectl get {{ kind }} -o json | jq '{{ jq_expr }}'
transformers:
- type: llm_summarize
max_tokens: 2000
两类变量语法区分了 LLM 可见参数与系统配置:{{ variable }} 是 Jinja2 模板变量,由 LLM 填入;${VARIABLE} 是环境变量,LLM 不可见,用于存放 API Key、内网地址等敏感信息。
YAMLTool 类通过 get_openai_format() 将工具元数据转换为标准 OpenAI function calling 格式。LLM 完全不知道背后是 YAML 还是 Python,只看到标准的 function schema——这是 YAML Toolset 与 MCP Toolset 能无缝共存的根本原因。YAML 还支持 Transformer 链,内置的 LLMSummarize 在工具输出超过阈值时用快速模型摘要,减少主调查 LLM 的 token 消耗。
Skills 系统最重要的设计哲学只有一句话,来自源码 skills_fetcher.py 的注释:
"the above are DIRECTIONS not ACTUAL RESULTS. You must follow them by CALLING TOOLS YOURSELF."
Skills 不是自动化脚本,而是给 LLM 读的 SOP。LLM 读完 Skill 后,自行决定调哪些工具来执行每一个步骤。同一个 Skill 在不同环境、不同工具可用性下,会调用不同的工具,但遵循同一套诊断逻辑。
每个 Skill 是一个 SKILL.md 文件,格式为 YAML frontmatter + Markdown 正文,放入目录后自动扫描加载,零注册、零代码:
---
name: redis-memory-pressure
description: 诊断 Redis 内存压力、OOM 驱逐、maxmemory 配置问题
---
## Workflow
1. 执行 redis-cli INFO memory,采集 used_memory、maxmemory、mem_fragmentation_ratio
2. 执行 redis-cli INFO stats,查看 evicted_keys 累计值
3. 检查 maxmemory-policy 配置
4. 若 evicted_keys > 0,查询最近 1 小时 key 数量趋势
## Synthesize Findings
- used_memory > maxmemory * 0.9 且 evicted_keys 增长 → 确认内存压力
- mem_fragmentation_ratio > 1.5 → 内存碎片,建议执行 MEMORY PURGE
## Recommended Remediation
立即:CONFIG SET maxmemory 调整上限;永久:评估 key 增长趋势制定扩容策略
内置 Skills 覆盖了常见的 Kubernetes 故障类型,例如:
Pod 反复重启、CrashLoopBackOffskill_loader.py 实现三级来源合并,优先级从高到低:用户自定义目录 → 内置 Skills → 远程 Skills(URL 动态拉取)。用户自定义的同名 Skill 会覆盖内置版本,允许团队针对自身环境深度定制。
Skills 与 LLM 的交互分为五步:
第一步:目录注入 System Prompt。 启动时扫描所有 Skill,只提取 name + description(每条约 20 token)注入 System Prompt,Skill 正文按需获取,节省 90% token:
Available Skills:
* redis-memory-pressure | 诊断 Redis 内存压力、OOM 驱逐、maxmemory 配置问题
* pod-crashloop | 诊断 Kubernetes Pod 反复重启的根本原因
* high-memory-usage | 调查容器内存使用率持续升高的问题
* node-not-ready | 调查 K8s Node 进入 NotReady 状态的原因
第二步:LLM 语义匹配,调用 fetch_skill。 LLM 将用户问题与目录中每条 description 做语义比对。匹配时发起 fetch_skill("redis-memory-pressure") 工具调用。这是语义理解而非关键词匹配,"Redis 内存不够了"也能命中正确的 Skill。
第三步:SkillsFetcher 返回带指引的 Skill 正文。 工具结果以 role: tool 消息形式注入 messages,包裹在 <skill> 标签中,并附加明确指示:
<skill name="redis-memory-pressure">
[Skill 完整内容]
</skill>
IMPORTANT: the above are DIRECTIONS not ACTUAL RESULTS.
You must follow them by CALLING TOOLS YOURSELF.
第四步:LLM 按 Skill 步骤调用真实工具。 Skill 内容约束了搜索空间——LLM 不会漫无目的地尝试工具,而是按照 Workflow 顺序有条不紊地执行。官方案例表明,有 Skill 约束时无效工具调用从 16 次降到 2 次。
第五步:输出带执行状态的标准化报告:
我使用了技能【redis-memory-pressure】进行排查:
1. ✅ INFO memory — used_memory 3.62G / maxmemory 3.81G,使用率 95%
2. ✅ INFO stats — evicted_keys 累计 18,432 个,仍在增加
3. ✅ maxmemory-policy — allkeys-lru
4. ✅ key 数量趋势 — 过去 1 小时增长 18%(210 万 → 248 万)
5. ❌ 无法查询慢查询日志 — Redis Slowlog 工具集未启用
根本原因:key 数量异常增长超出 maxmemory 上限,触发 LRU 驱逐...
❌ 步骤不仅是诊断记录,更是工具链缺失的反馈,驱动持续完善 Agent 覆盖面。
官方交互模式文档展示了一个典型的多轮调查场景——payment-service 不响应请求:
holmes ask "why is the payment-service in production namespace not responding?"
Agent 依次执行:kubectl_find_resource(定位 deployment)→ kubectl_describe(查看状态)→ kubectl_get_by_kind(列出 Pod)→ fetch_pod_logs(拉取日志)→ kubectl_events(查看事件),初步判断是数据库连接失败。用户追问后,Agent 继续调查 PVC Pending 原因,最终定位到 StorageClass 不存在:
Root Cause: The PVC is pending because the requested StorageClass "fast-ssd" not found.
Available StorageClasses: gp2 (default), gp3, io1, standard
整个调查过程中,工程师可以随时用 /run 命令注入 Agent 无法直接访问的数据(如 SSH 到宿主机、查询 ALB 健康状态),Agent 将这些数据融入分析上下文继续推理。

当 KubePodCrashLooping 告警触发后,通过以下命令一键调查:
holmes investigate alertmanager \
--alertmanager-url http://localhost:9093 \
--alertmanager-alertname "KubePodCrashLooping"

也可以不加过滤,让 HolmesGPT 批量调查所有活跃告警,按严重程度输出结构化的 RCA 报告,并支持通过 --alertmanager-label "severity=critical" 精确过滤。

在 GitHub Actions 中,当 Kubernetes 部署超时失败时,自动触发 HolmesGPT 调查并将结果发送到 Slack:
- name: Deploy & Investigate on Failure
if: failure()
run: |
holmes ask "The deployment failed. Analyze why pods are not becoming ready.
Focus on: image pulls, resource limits, probes, configuration." \
--no-interactive \
--destination slack \
--slack-channel "#deploy-alerts"

Operator 模式将 Agent 作为 Kubernetes Controller 持续运行,支持定时巡检配置:
scheduledHealthChecks:
- name: daily-cluster-health
schedule: "0 9 * * *"
prompt: "扫描集群中所有异常 Pod,分析根因并生成日报"
destinations: [slack, jira]
集群中发现异常时,Operator 自动生成结构化报告并推送到指定渠道,无需任何人工干预。
SRE Agent 的评测有几个独特挑战,与一般 LLM 应用不同:
一套完整的评测体系需要覆盖:
维度 | 关键指标 |
|---|---|
诊断准确性 | Top-1/Top-3 根因准确率、影响范围判断、修复建议可执行性 |
调查过程质量 | 工具调用总次数、无效调用占比、重复调用率、并行执行率 |
场景覆盖深度 | L1(单组件故障)→ L5(间歇性隐性故障) |
安全性 | 高危操作是否正确拦截,是否因异常数据产生幻觉 |
HolmesGPT 的评测体系是上述理论的工程实现,值得直接参考。每个测试场景是一个独立目录,核心是 test_case.yaml:
user_prompt: "What is the issue with payment-processing-worker?"
expected_output:
- The `DEPLOY_ENV` environment variable is undefined or missing
before_test: |
kubectl create namespace app-09
# 部署一个故意缺少 DEPLOY_ENV 的 Pod,等待进入 CrashLoopBackOff
kubectl wait --for=jsonpath=...=CrashLoopBackOff pod ...
after_test: |
kubectl delete namespace app-09
tags: [easy, kubernetes, regression]
执行流程:before_test 向真实 K8s 集群注入已知故障 → HolmesGPT 调用真实工具调查 → 裁判 LLM 检查输出是否符合 expected_output → after_test 清理现场。这正是"故障注入测试环境 + LLM-as-Judge"的工程实现。
评分机制:使用 autoevals 库的 LLMClassifier,用独立的 CLASSIFIER_MODEL 作为裁判。expected_output 是语义要求列表,裁判判断 Agent 的回答是否覆盖了这些语义,而非逐字匹配。expected_output 对 Agent 永远不可见,只有裁判 LLM 能看到——这是防止 LLM 凭领域知识猜答案的反作弊设计。
过程指标采集:评测框架同步追踪 tool_call_count、num_llm_calls、holmes_duration、total_tokens、num_compactions 等指标,全部上传到 Braintrust 平台做跨版本、跨模型横向对比。


分层测试管理:通过 tags 字段管理测试集分层(easy、regression 等),CI 只跑核心回归集,全量测试按需触发。
方案 | 能评测的对象 | 成本 | 推荐用途 |
|---|---|---|---|
历史事故复盘集 | 结论准确性 | 高(人工标注) | 黄金基准,季度对比 |
故障注入测试环境 | 过程质量 + 准确性 | 高(专用集群) | 持续回归测试 |
Mock 工具回放 | 过程质量 + 准确性 | 中(前期积累录制) | 日常自动化评测 |
HolmesGPT 采用的正是故障注入方案。三种方案可以叠加:复盘集作为黄金基准,注入环境做持续回归,Mock 回放支撑日常自动化。建议从 L1-L2 难度的高质量样本起步,20-30 个精标案例的价值远高于 200 个粗糙样本。
HolmesGPT 对 SRE 智能体建设的最大参考价值,在于它提供了一套经过生产验证的设计决策集合:Agentic Loop 的工程化实现、Skills 把人类知识变成 Agent 能力的标准化路径、YAML 工具集的声明式扩展体系,以及一整套防止 Agent 失控的工程护栏。
在交互方式上,HolmesGPT 将其抽象为 Source(输入触发)→ 调查引擎 → Destination(输出回写)三层,支持 CLI、告警驱动、ChatOps、Operator 巡检、CI/CD 集成、API 嵌入等多种模式,核心引擎无需改动,只需替换插件。对于从零开始建设的团队,建议按顺序落地:先 CLI 验证能力 → 接告警驱动跑通主流程 → 建 ChatOps 提升协作可见性 → 嵌入运维平台。
HolmesGPT 更适合云原生环境下开箱即用的场景。笔者所在公司的环境较为复杂,Kubernetes 只是其中一小部分,暂时无法直接使用,但其设计理念完全值得借鉴。
研究 HolmesGPT 过程中,有一个点颠覆了我此前的一些认知:很多简单的 API 调用或支持 CLI 方式的工具(kubectl、PromQL 查询等),直接通过智能体进程内的 Bash 方式执行就能解决,不一定需要封装成 MCP Server,开发成本可以大幅降低。这个思路对于快速搭建原型和工具链扩展很有价值。
故障根因分析智能体确实是一块不好啃的骨头——不论是智能体的产品设计、与真实运维环境的适配,还是全链路可观测数据的接入,都存在相当大的挑战。但办法总比困难多,HolmesGPT 的设计思路给了我一些具体的方向性指引,希望对正在做类似方向的同学也有所帮助。
我的愿景是在运维领域做出一些有价值的贡献。一线运维同学在告警处理和故障排查上消耗了大量精力,这部分重复性工作应该要大部分被 AI 承接,让运维同学能把更多时间投入到有创造性价值的事情上——不是被 AI 替代,而是借助 AI 拓展自身的价值边界。
自勉,共勉。
参考资料:HolmesGPT 源码、官方文档(holmesgpt.dev/0.28.0)、CNCF 博客(2026-04)、ChatGPT 调研报告《HolmesGPT 在运维领域的使用情况与最佳实践调研报告》