没事找事 發表於 2026-4-2 10:35:00

aiops初体验:让 AI 接管告警分析,这个小 Agent 到底能干啥?

<h2 id="前言">前言</h2>
<p>最近这段时间,AIOps 这个词在技术圈里越来越常见,很多朋友都在聊:AI 到底能不能真正帮线上排障?<br>
笔者最近抓耳挠腮的想要将运维的实际场景结合ai,做了一个小的demo,代码量不大,但把一个 AIOps Agent 的最小闭环已经串起来了。本文就和大家一起拆一拆这个项目:它的代码结构是什么、每个文件负责什么、整个执行链路怎 么跑,以及这套思路放到真实线上场景里还有哪些坑。</p>
<h2 id="先看代码结构">先看代码结构</h2>
<p>先把目录结构贴出来,朋友们有个整体感知。</p>
<pre><code class="language-bash">monitor_agent
├── agent.py
├── llm.py
├── main.py
├── tools.py
</code></pre>
<p>这个结构非常小,但麻雀虽小,五脏俱全,它已经包含了一个 AIOps 场景最核心的四层:</p>
<ul>
<li>(1)入口层:<code>main.py</code></li>
<li>(2)编排层:<code>agent.py</code></li>
<li>(3)模型调用层:<code>llm.py</code></li>
<li>(4)外部数据/工具层:<code>tools.py</code></li>
</ul>
<p>如果用一句人话来解释这套结构,那就是:<br>
<strong>用户提问题 → Agent 判断是不是线上问题 → 去告警系统和日志系统拿事实 → 把事实喂给大模型 → 大模型输出分析结论。</strong></p>
<p>这就是一个非常典型的 AIOps 雏形。</p>
<h2 id="程序入口mainpy">程序入口:<code>main.py</code></h2>
<p>先看入口文件。</p>
<p>这段代码的作用,就是定义一个问题,然后把问题交给 <code>ai_agent()</code> 去处理,最后把结果打印出来。</p>
<pre><code class="language-python">from agent import ai_agent

if __name__ == "__main__":
    question = "现在线上出现了什么问题吗?"
    answer = ai_agent(question)
    print("AI 分析结果:\n")
    print(answer)
</code></pre>
<p>这个文件的职责非常单纯,核心只有两件事:</p>
<ul>
<li>(1)构造用户输入</li>
<li>(2)调用 Agent,并输出结果</li>
</ul>
<p>入口层不应该掺杂太多业务逻辑,它只负责启动流程。真正的分析、工具调用、模型推理,都应该下沉到其他模块里。</p>
<h2 id="核心大脑agentpy">核心大脑:<code>agent.py</code></h2>
<p>这个项目里最关键的文件,就是 <code>agent.py</code>。</p>
<p>这段代码的作用,是把“意图识别、告警查询、日志查询、Prompt 构造、LLM 推理”串成一个完整流程。</p>
<pre><code class="language-python">from tools import (
    get_active_alerts,
    query_nginx_error_log,
    query_nginx_access_log
)
from llm import llm

def ai_agent(question: str) -&gt; str:
    # 1. 判断用户意图
    if "线上" not in question:
      return "我只能回答线上运行状态相关问题"

    # 2. 查询告警
    alerts = get_active_alerts()
    if not alerts:
      return "当前无告警,线上运行正常"

    # 3. 查询日志
    error_log = query_nginx_error_log(alerts["service"])
    access_log = query_nginx_access_log(alerts["service"])

    # 4. 构造推理 Prompt
    prompt = f"""
你是一个经验丰富的 SRE。

当前检测到告警:
{alerts}

Nginx error.log:
{error_log}

Nginx access.log:
{access_log}

请分析:
1. 当前是否存在真实故障
2. 故障发生在哪一层(nginx / upstream / network)
3. 根因是什么
4. 给出修复建议

请基于日志,不要编造不存在的事实。
"""

    # 5. 调用 LLM
    result = llm(prompt)
    return result
</code></pre>
<h4 id="1意图识别">1)意图识别</h4>
<p>第一步是这句:</p>
<pre><code class="language-python">if "线上" not in question:
    return "我只能回答线上运行状态相关问题"
</code></pre>
<p>这其实是一个非常粗糙但有效的路由逻辑。<br>
它的意思是:只有当用户的问题里包含“线上”两个字,Agent 才继续走后面的排障流程。</p>
<p>这个实现当然比较 demo,但它表达了一个重要设计思想:<br>
<strong>Agent 在调用昂贵工具和大模型之前,先做任务分类。</strong></p>
<p>否则的话,随手问一句“帮我写个 SQL”,它也去查告警、捞日志、调 LLM 分析线上故障,那 token 和接口费就属于原地升天。</p>
<h4 id="2查询告警">2)查询告警</h4>
<p>接下来是:</p>
<pre><code class="language-python">alerts = get_active_alerts()
if not alerts:
    return "当前无告警,线上运行正常"
</code></pre>
<p>这一步做了第一个事实收集。<br>
在真实生产环境里,这里通常会接:</p>
<ul>
<li>Prometheus Alertmanager</li>
<li>Grafana Alerting</li>
<li>Zabbix</li>
<li>飞书/钉钉告警聚合接口</li>
</ul>
<p>而这个 demo 里,返回的是一条模拟告警:</p>
<pre><code class="language-python">{
    "alertname": "nginx_5xx_high",
    "service": "backend-service",
    "since": "2026-03-02 09:41",
    "severity": "critical"
}
</code></pre>
<p>它给 Agent 提供了最基础的排障上下文,包括:</p>
<ul>
<li>告警名称</li>
<li>受影响服务</li>
<li>发生时间</li>
<li>严重级别</li>
</ul>
<h4 id="3查询日志">3)查询日志</h4>
<p>接着是日志部分:</p>
<pre><code class="language-python">error_log = query_nginx_error_log(alerts["service"])
access_log = query_nginx_access_log(alerts["service"])
</code></pre>
<p>获取nginx的日志,包括access.log与error.log,获取现场的第一手记录</p>
<h4 id="4构造-prompt">4)构造 Prompt</h4>
<p>再往后,就是这套 AIOps 方案的灵魂地带:Prompt 编排。</p>
<p>这里把告警、Nginx error 日志、access 日志统一拼成了一段结构化输入,并明确要求模型回答四件事:</p>
<ul>
<li>(1)是否是真实故障</li>
<li>(2)故障位于哪一层</li>
<li>(3)根因是什么</li>
<li>(4)修复建议是什么</li>
</ul>
<p>而且最后还加了一句:</p>
<pre><code class="language-text">请基于日志,不要编造不存在的事实。
</code></pre>
<p>这句非常重要。<br>
因为排障场景和普通问答不一样,<strong>胡说八道的成本很高</strong>。<br>
模型在创作场景里会发散,这是优点;<br>
但在 SRE 场景里发散,就是事故二次伤害。</p>
<h4 id="5调用-llm">5)调用 LLM</h4>
<p>最后才是模型调用:</p>
<pre><code class="language-python">result = llm(prompt)
return result
</code></pre>
<p>注意这个顺序很关键:<br>
<strong>先拿事实,再让模型做归纳。</strong><br>
而不是上来就把用户问题扔给大模型,让它空口分析。</p>
<h2 id="模型封装层llmpy">模型封装层:<code>llm.py</code></h2>
<p>接着看 <code>llm.py</code>。</p>
<p>这段代码的作用,是把大模型调用封装成一个统一函数,Agent 不用关心底层 API 细节。</p>
<pre><code class="language-python">import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("API_BASE_URL")
)

MODEL = os.getenv("DEFAULT_MODEL")

def llm(prompt: str) -&gt; str:
    response = client.chat.completions.create(
      model=MODEL,
      messages=[
            {
                "role": "system",
                "content": "你是一个严谨的 SRE,只能基于给定事实进行分析。"
            },
            {
                "role": "user",
                "content": prompt
            }
      ],
      temperature=0.2# ⚠️ 排障一定要低温度
    )

    return response.choices.message.content
</code></pre>
<h4 id="1环境变量解耦">1)环境变量解耦</h4>
<p>先看客户端初始化:</p>
<pre><code class="language-python">client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("API_BASE_URL")
)
</code></pre>
<p>这里做得比较灵活。<br>
通过环境变量传入 <code>api_key</code> 和 <code>base_url</code>,说明它并不强绑定某一家模型平台。<br>
只要兼容 OpenAI SDK 协议,不管后面接的是:</p>
<ul>
<li>OpenAI</li>
<li>阿里百炼</li>
<li>DeepSeek 兼容网关</li>
<li>LiteLLM</li>
<li>自建代理</li>
</ul>
<p>都可以复用这一层。</p>
<h4 id="2system-prompt-约束">2)System Prompt 约束</h4>
<p>模型调用里有一段很值得注意:</p>
<pre><code class="language-python">"content": "你是一个严谨的 SRE,只能基于给定事实进行分析。"
</code></pre>
<p>这属于给模型戴“安全头盔”。虽然不能 100% 防幻觉,但至少明确了角色和边界。</p>
<p>对 AIOps 来说,这种约束最好再继续加强,比如补充:</p>
<ul>
<li>不允许猜测未提供的数据</li>
<li>结论必须引用对应日志证据</li>
<li>证据不足时要明确说“不足以判断”</li>
<li>建议按置信度输出</li>
</ul>
<h4 id="3低温度设置">3)低温度设置</h4>
<p>最后这句,是整份代码里笔者最喜欢的一句注释:</p>
<pre><code class="language-python">temperature=0.2# ⚠️ 排障一定要低温度
</code></pre>
<p>写文案、起标题、搞创意,温度高一点没问题;<br>
但线上故障分析要的是稳定、克制、少脑补。</p>
<p>否则模型一兴奋,上一秒还是 upstream timeout,下一秒就能给你联想到数据库雪崩、交换机抖动、机房断电、宇宙射线翻转 bit 位,属实太会整活。</p>
<p>所以排障、审计、风控、配置审查这类任务,低温度是基本操作。</p>
<h2 id="工具层toolspy">工具层:<code>tools.py</code></h2>
<p>这段代码的作用,是模拟告警平台和日志系统的查询接口。</p>
<pre><code class="language-python">
def get_active_alerts():
    """
    模拟:从告警平台获取当前告警
    """
    return {
      "alertname": "nginx_5xx_high",
      "service": "backend-service",
      "since": "2026-03-02 09:41",
      "severity": "critical"
    }

def query_nginx_error_log(service: str):
    """
    模拟:查询 Nginx error.log
    """
    return """
    2026/03/02 09:41:12 1234#1234: *5678 upstream timed out
    (110: Connection timed out) while reading response header from upstream,
    upstream: "http://10.244.0.73:10000/test"
    """

def query_nginx_access_log(service: str):
    """
    模拟:查询 access.log 中的 5xx
    """
    return """
    10.0.0.1 - - "GET /test HTTP/1.1" 504
    10.0.0.2 - - "GET /test HTTP/1.1" 504
    """
</code></pre>
<h4 id="1get_active_alerts">1)get_active_alerts()</h4>
<p>这个函数负责返回当前活动告警。<br>
虽然现在是写死的模拟数据,但它对应的真实职责很明确:</p>
<ul>
<li>从告警平台拉取当前触发中的告警</li>
<li>返回可用于后续分析的结构化数据</li>
</ul>
<p>如果未来要接生产系统,这里可以对接 Prometheus Alertmanager API 或内部告警中心。</p>
<h4 id="2query_nginx_error_logservice">2)query_nginx_error_log(service)</h4>
<p>这个函数负责拿 Nginx 错误日志。<br>
返回的关键日志是:</p>
<pre><code class="language-text">upstream timed out
(110: Connection timed out) while reading response header from upstream
</code></pre>
<p>这个信息其实已经非常关键了。<br>
它说明:</p>
<ul>
<li>Nginx 已经把请求转发给 upstream 了</li>
<li>问题不是客户端没连上 Nginx</li>
<li>问题也不是 Nginx 自己语法错误或者进程挂了</li>
<li>而是上游服务在规定时间内没有返回响应头</li>
</ul>
<p>这类故障在线上特别常见,本质上就是:<br>
<strong>网关层看到 504,但锅大概率不在网关本身,而在上游处理慢、阻塞、卡死、网络超时或线程池耗尽。</strong></p>
<p>如果未来要接生产系统,这里可以对接 日志中心。</p>
<h4 id="3query_nginx_access_logservice">3)query_nginx_access_log(service)</h4>
<p>这个函数负责返回访问日志里的 5xx 样本。<br>
日志里连续出现两个 504:</p>
<pre><code class="language-text">"GET /test HTTP/1.1" 504
</code></pre>
<p>如果未来要接生产系统,这里可以对接 日志中心。</p>
<h2 id="这套代码的执行链路到底是怎么跑起来的">这套代码的执行链路,到底是怎么跑起来的?</h2>
<p>很多朋友第一次看这种 Agent 代码,会觉得文件很少,但脑子里流程有点绕。这里笔者用人话串一遍。</p>
<h4 id="第一步用户发起问题">第一步:用户发起问题</h4>
<p>入口是:</p>
<pre><code class="language-python">question = "现在线上出现了什么问题吗?"
</code></pre>
<p>程序启动后,用户问题被传给 <code>ai_agent(question)</code>。</p>
<h4 id="第二步agent-判断是否受理">第二步:Agent 判断是否受理</h4>
<p><code>agent.py</code> 会先检查问题里是否包含“线上”。<br>
如果没有,就拒绝受理。</p>
<p>这一步相当于一个非常简陋的 Intent Router。</p>
<h4 id="第三步拉告警">第三步:拉告警</h4>
<p>如果问题命中线上场景,Agent 就调用:</p>
<pre><code class="language-python">alerts = get_active_alerts()
</code></pre>
<p>拿到当前活动告警。</p>
<h4 id="第四步按服务维度查日志">第四步:按服务维度查日志</h4>
<p>拿到告警里 <code>service=backend-service</code> 之后,再继续查:</p>
<pre><code class="language-python">query_nginx_error_log(alerts["service"])
query_nginx_access_log(alerts["service"])
</code></pre>
<p>这一步把日志事实补齐。</p>
<h4 id="第五步把所有事实拼成-prompt">第五步:把所有事实拼成 Prompt</h4>
<p>Agent 会把“告警 + error.log + access.log”统一喂给大模型。</p>
<h4 id="第六步模型输出故障分析">第六步:模型输出故障分析</h4>
<p>最后由 <code>llm.py</code> 调用模型,产出一段排障结论。</p>
<p>整个链路可以用一张简化图表示:</p>
<pre><code class="language-text">用户问题
   ↓
main.py
   ↓
agent.py(意图识别 + 编排)
   ↓
tools.py(告警 + 日志)
   ↓
llm.py(模型推理)
   ↓
输出分析结果
</code></pre>
<p>这就是一个最小可运行的 AIOps Agent 闭环。</p>
<h2 id="运行结果">运行结果</h2>
<p><img alt="aiops_1_1" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202604/1416773-20260401171233870-1329921031.jpg" class="lazyload"></p>
<h2 id="后续改进">后续改进</h2>
<p>如果把它放到真实线上,这份代码还差不少东西。</p>
<h4 id="1意图识别太粗糙">1)意图识别太粗糙</h4>
<p>只靠“线上”两个字判断,属于能跑,但不智能。<br>
真实场景里至少要支持:</p>
<ul>
<li>告警分析</li>
<li>服务状态查询</li>
<li>日志排查</li>
<li>错误率分析</li>
<li>变更影响判断</li>
</ul>
<p>最好做成分类器或者规则路由,而不是字符串 contains。</p>
<h4 id="2接入真实数据">2)接入真实数据</h4>
<p>需要接入真实的数据,比如</p>
<ul>
<li>Alertmanager</li>
<li>Loki / Elasticsearch / Kibana</li>
<li>Prometheus / VictoriaMetrics</li>
<li>链路追踪系统(Jaeger、Tempo、SkyWalking)</li>
<li>Kubernetes API</li>
</ul>
<h4 id="3缺少证据引用机制">3)缺少证据引用机制</h4>
<p>当前模型输出只是文本,没有强制要求:</p>
<ul>
<li>哪个结论对应哪条日志</li>
<li>哪个建议对应哪个告警事实</li>
<li>哪些地方只是推测</li>
</ul>
<p>真实生产里,最好把输出格式约束成结构化,比如:</p>
<pre><code class="language-json">{
"is_real_incident": true,
"layer": "upstream",
"evidence": [
    "error.log 中出现 upstream timed out",
    "access.log 中连续出现 504"
],
"root_cause_hypothesis": "上游服务响应超时",
"confidence": 0.82,
"suggestions": [
    "检查 backend-service 的响应耗时",
    "检查 upstream Pod CPU/线程池/依赖超时情况"
]
}
</code></pre>
<p>当然这个部分笔者还在探索中</p>
<h4 id="4补更多上下文">4)补更多上下文</h4>
<p>现在只查了 Nginx 日志,证据还是偏少,后面可以继续补:</p>
<ul>
<li>upstream 服务日志</li>
<li>Pod 重启事件</li>
<li>CPU/内存/QPS/错误率曲线</li>
<li>最近变更记录</li>
<li>数据库慢查询</li>
</ul>
<p>这样模型分析才不至于停留在“像是 upstream 慢了”这种半截结论。</p>
<h4 id="5引入置信度和不确定性表达">5)引入置信度和不确定性表达</h4>
<p>AIOps 最怕瞎自信,所以必须允许模型输出:</p>
<ul>
<li>高置信度结论</li>
<li>低置信度猜测</li>
<li>证据不足提醒</li>
</ul>
<p><strong>一个会说“我不知道”的故障分析 Agent,比一个满嘴跑火车的 Agent 可靠得多。</strong></p>
<h4 id="6数据脱敏">6)数据脱敏</h4>
<p>由于日志数据、监控数据等属于公司核心数据,在调用外部大模型的时候,还是要做好脱敏等工作,避免造成数据泄漏等安全事件</p>
<p>常见的需要脱敏的字段:username、password、IP、email、token、uuid、cookie、session等等,这要取决与业务的需求</p>
<h2 id="总结">总结</h2>
<p>这个项目 代码虽然小,但已经把一个 AIOps Agent 的基本骨架搭出来了:入口接问题、编排流程拉事实、工具层查询告警与日志、模型层做证据归纳。它最大的价值,是把方向走对了——先有观测事实,再让 AI 做分析,而不是让 AI 闭眼开猜。如果后面把告警、日志、指标、链路、变更这些上下文继续补进去,这类 Agent 在值班排障、告警摘要、故障初筛这些场景里,确实能够发挥作用</p>
<h2 id="联系我">联系我</h2>
<ul>
<li>联系我,做深入的交流</li>
</ul>
<p><img alt="" width="500" height="200" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202411/1416773-20241121135740959-1907948957.png#" class="lazyload"></p>
<p>至此,本文结束</p>
<p>在下才疏学浅,有撒汤漏水的,请各位不吝赐教...</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:it排球君,转载请注明原文链接:https://www.cnblogs.com/MrVolleyball/p/19807951</p>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。 </div><br><br>
来源:https://www.cnblogs.com/MrVolleyball/p/19807951
頁: [1]
查看完整版本: aiops初体验:让 AI 接管告警分析,这个小 Agent 到底能干啥?