AIOps 入门

2025-11-03T14:11:02+08:00 | 24分钟阅读 | 更新于 2025-11-03T14:11:02+08:00

@

学习目标

学完本章你应该能够:

  1. 用一句话解释 AIOps 是什么,并讲清 Gartner 五阶段(Observe → Analyze → Engage → Act → Evolve)各自解决什么问题、为什么多数公司卡在 2-3 阶段。
  2. 写出一个"角色 + 上下文 + 约束“三段式 Prompt 模板,说清为什么 Context 段的有无直接决定诊断准确率。
  3. 区分 Few-shot / CoT / 结构化输出 在运维场景的用处,并讲清 ReActPlan-and-Execute 的差异与各自适用场景。
  4. 画出 LLMOps 从数据 → 训练 → 评测 → 部署 → 监控的完整生命周期,说清反馈如何回流到数据准备。
  5. 在面试里把 Agent(感知/推理/执行)、Function Calling、Embedding/RAG 讲成一套落地方案,并点出"危险动作必须人工确认"这条红线。

前置知识

  • 基本的大模型使用经验(用过 ChatGPT 类对话工具即可)。
  • 了解 Prometheus / K8s 等运维概念更好,但不强制;文中的运维例子都能当背景故事读。
  • 能看懂简单的 Python 代码(不要求会写)。

本章你会动手做的事

  • 用文中的三段式 Prompt 模板,填一个真实故障现象,观察模型输出质量的变化。
  • 给"日志分类"的 Few-shot 模板补几条你自己业务的样例,看分类准不准。
  • 用 LangChain 跑最小运维 Agent,故意让它"建议重启数据库”,验证你加的红线约束是否拦得住。

AIOps 的定义与演进

AIOps 是将人工智能技术应用于 IT 运维领域的统称。Gartner 提出 AIOps 平台应能够摄取多源数据(指标、日志、链路、事件),利用机器学习和大数据分析实现异常检测、根因分析、容量预测和自动化修复。

随着大语言模型(LLM)的兴起,AIOps 正在从传统的"基于规则的自动化"和"基于统计的机器学习",演进到"具备理解、推理和执行能力的智能体(Agent)“阶段。

Gartner 五阶段:你在哪一级

Gartner 把 AIOps 演进划成五个阶段,我自己给每阶段加了个"人话版"描述:

阶段含义人话版
1. Observe采集数据,做可视化监控大屏好看但没用,告警靠人盯
2. Analyze规则/统计做异常检测阈值告警,5xx > 1% 报警,但噪声巨大
3. Engage自动聚类、关联、根因推荐同一故障的多个告警合并,给出"可能根因 top 3”
4. Act自动化响应、自愈检测到 OOM 自动重启 Pod,磁盘满自动清理
5. Evolve闭环学习、持续优化每次处置后回流数据,模型/规则自动迭代

白话:这五个阶段其实就是运维从"人盯屏幕"到"机器自治"的进化史。绝大多数公司停在 2-3,不是因为 4-5 做不到,而是自动执行动作风险太高——你敢让 AI 半夜自动重启数据库吗?所以现实里大家先把"告警降噪、根因推荐"做扎实,离"全自动闭环"还远。

下面把五个阶段画成一条递进的能力阶梯,注意它是一条"越往上越自动、也越危险"的路:

flowchart LR
    S1[1 Observe
采集可视化] --> S2[2 Analyze
规则统计检测] S2 --> S3[3 Engage
聚类关联根因] S3 --> S4[4 Act
自动响应自愈] S4 --> S5[5 Evolve
闭环学习]

说实话大部分公司卡在 2-3 之间。第 4 阶段 Act 真正能跑起来的场景很少——主要是运维动作风险高,自动执行出错可能比故障本身还致命。我见过一个"自动重启"策略把数据库主节点重启了,业务直接挂 30 分钟。

实际落地场景

我亲手做过或者近距离看过的几个 AIOps 落地场景,按 ROI 排序:

  1. 告警降噪与合并:基于规则 + LLM 把同一故障的几十条告警合成 1 条工单,研发不再被飞书轰炸。ROI 最高。
  2. 日志摘要:故障发生时 LLM 自动读取近 10 分钟相关 Pod 日志,给出"问题摘要 + 可能原因"。值班同学处理速度提升 30%+。
  3. NL2Query:业务同学用自然语言查 PromQL / SQL,不用再求 SRE 写查询。
  4. 故障知识库 RAG:把历史复盘文档、SOP 入向量库,出问题时直接问"订单服务 500 怎么处理",召回相似故障的处置步骤。
  5. 自动扩缩容决策:LLM 不直接执行,而是给出"建议扩容到 N 副本"的方案,人工点确认后执行。这个不敢全自动,风险太高。

大模型基础与运维场景落地

大模型(如 GPT、Claude、Llama、Qwen 等)具备强大的语言理解、代码生成和推理能力。在运维场景中,其落地方式主要包括:

  • 自然语言转查询(NL2Query):将运维人员的自然语言问题转换为 PromQL、SQL、KQL 等查询语句。
  • 日志与事件摘要:对海量日志进行压缩、聚类,提取关键异常信息。
  • 故障根因推理:结合可观测数据与知识库,辅助定位问题根因。
  • 脚本与配置生成:自动生成 Shell、Python、YAML 等运维脚本。
  • 智能问答与知识库:基于 RAG 技术构建运维知识助手。

运维 Prompt 模板:角色 + 上下文 + 约束

LLM 用得好不好,70% 看提示词。下面是我线上在用的一个"故障诊断助手"prompt 模板,拆成三段:

# 角色(Role)
你是一名有 10 年经验的资深 SRE,擅长 Kubernetes、Prometheus、Go 后端排障。
你的回答风格:直接、简洁、给可执行的命令,不要复述用户问题。

# 上下文(Context)
## 故障信息
- 服务:order-service(Go 1.22,K8s 集群 prod)
- 现象:5xx 错误率从 0.1% 涨到 15%,持续 8 分钟
- 告警时间:2025-11-01 14:32:00

## 相关指标(最近 10 分钟)
- CPU 使用率:85%(常态 40%)
- 内存使用率:92%,Pod OOMKilled 3 次
- P99 延迟:从 200ms 涨到 3.2s
- 错误日志样本:
  "context deadline exceeded"  x 432
  "connection refused (db:3306)" x 128

## 架构信息
- order-service → MySQL(主从)+ Redis(哨兵)
- 上游:api-gateway,下游:payment-service

# 约束(Constraint)
1. 优先级最高的根因放第一条,不要列超过 3 条
2. 每个根因配 1 个验证命令(kubectl / mysql / redis-cli)
3. 不要建议重启数据库,这是生产主库
4. 如果信息不足,明确说"需要补充 XX 指标",不要瞎猜

这个模板我用了一个月,比之前那种"你是 SRE,请帮我分析故障"的弱 prompt 准确率高一截。关键是 Context 段——把告警、指标、日志样本全塞进去,模型不用猜,直接推理。

踩坑提示:约束段一定要写"不要建议重启数据库"这种红线。我有次没写,LLM 给的方案是"建议重启 MySQL 主库",差点被值班同学照做。生产库里任何"重启"动作都得人工审批。

提示词工程与任务规划

Prompt Engineering

提示词工程(Prompt Engineering)是引导大模型产生高质量输出的关键技术。常用技巧包括:

  1. 角色设定:让模型扮演"资深 SRE"或"K8s 专家"。
  2. 上下文示例(Few-shot):提供输入输出示例,提升输出稳定性。
  3. Chain-of-Thought(CoT):要求模型分步思考,提高复杂推理准确率。
  4. 结构化输出:指定 JSON、Markdown 等输出格式,便于下游系统解析。
  5. 约束与边界:明确限制回答范围,避免幻觉。

Few-shot 在运维的例子:日志分类

下面是个日志分类的 few-shot 示例,给 3 个正反例之后,模型对新日志的分类准确率从 60% 涨到 90%+。

# 任务
对下面的运维日志进行分类,从以下 4 类中选一个:
- NETWORK:网络相关(连接超时、拒绝、DNS 失败)
- RESOURCE:资源相关(CPU/内存/磁盘/文件句柄)
- DEPENDENCY:下游依赖故障(DB/Redis/MQ)
- APPLICATION:应用逻辑错误(panic、空指针、业务异常)

# 示例
日志:dial tcp 10.0.1.5:3306: connect: connection refused
分类:DEPENDENCY

日志:OOMKilled (exit code 137)
分类:RESOURCE

日志:panic: runtime error: invalid memory address or nil pointer dereference
分类:APPLICATION

日志:i/o timeout
分类:NETWORK

# 待分类
日志:{input_log}
分类:

CoT 在运维的例子:根因推理

简单一问"为啥 Pod 起不来",模型容易瞎猜。加一句"请按以下步骤分析"就靠谱很多:

# 任务
分析 Pod `order-service-abc123` 为什么起不来。请按以下步骤推理:

Step 1:列出可能的原因类别(镜像/资源/配置/依赖/权限)
Step 2:针对每个类别,给出对应的事件/指标验证方法
Step 3:根据下面提供的实际事件,排除不可能的类别
Step 4:得出最可能的根因,并给出修复命令

# 实际事件
Events:
  - FailedScheduling      3m   0/3 nodes available: 3 Insufficient memory
  - FailedScheduling      3m   0/3 nodes available: 3 Insufficient memory

模型输出大概会是这样:

Step 1:可能原因
- 资源:节点内存不足,无法满足 Pod requests
- 配置:resources.requests.memory 设得过大
- 调度:节点数太少

Step 2:验证方法
- kubectl describe node | grep -A5 Allocated resources  # 看节点内存分配
- kubectl get pod -o yaml | grep -A3 resources          # 看 Pod 资源请求

Step 3:根据事件排除
- 事件明确写 "3 Insufficient memory",所以是资源问题
- 不是镜像拉取失败(没有 ImagePullBackOff)
- 不是配置错误(资源配置是合法值,只是节点装不下)

Step 4:根因与修复
根因:3 个节点剩余内存都不够,Pod 一直 Pending
修复:
  # 方案 A:临时扩节点
  kubectl scale nodegroup prod-ng --size 5
  # 方案 B:降低 Pod 资源请求(如果业务允许)
  kubectl patch deployment order-service --type=json \
    -p='[{"op":"replace","path":"/spec/template/spec/containers/0/resources/requests/memory","value":"256Mi"}]'

踩坑提示:CoT 推理的输出会很长,记得在 prompt 末尾加"只输出 Step 4 的最终结论给值班同学看,Step 1-3 放到 details 字段",否则飞书消息会刷屏。

Planning 在运维自动化中的应用

复杂运维任务往往需要多步执行。任务规划(Planning)模块负责将高层目标拆解为可执行的子任务。例如"自动扩容"可拆解为:

  1. 采集当前 CPU/内存/QPS 指标。
  2. 判断是否需要扩容。
  3. 调用 K8s API 修改 Deployment 副本数。
  4. 持续观察扩容效果。
  5. 若异常则回滚并告警。

规划能力可以通过 LLM 直接生成计划,也可以结合 ReAct、Reflexion 等 Agent 框架实现。

ReAct vs Plan-and-Execute

这两个是 Agent 规划的主流范式,我对比一下:

维度ReActPlan-and-Execute
核心思想思考→行动→观察,循环往复先生成完整计划,再逐步执行
计划生成每一步动态决策,没有全局计划一次性生成所有步骤
错误恢复自然,每步都能根据观察调整需要 Re-plan,复杂
Token 消耗高(每步都要重新思考)低(计划只生成一次)
适合场景探索性任务、信息不确定步骤明确、需要严格审计
运维例子故障根因排查(每步结果决定下一步)标准化发布流程(步骤已知)

白话:ReAct 像侦探办案——看到线索(Observation)就推理一步(Thought),推理出该查什么就去查(Action),查到新线索再推理,循环到能下定论。Plan-and-Execute 则像按 SOP 办事——先把所有步骤列好,再一步步执行,中途不灵活但好审计。

下面把 ReAct 的"思考→行动→观察"循环画成图:

flowchart TD
    T[Thought 思考] --> A[Action 调用工具]
    A --> O[Observation 观察结果]
    O --> T
    O -->|得出答案| F[Final Answer]

举个故障排查的 ReAct 例子:

Thought: 用户报告 order-service 500 错误。先看 Pod 状态。
Action: kubectl get pods -n prod | grep order-service
Observation: 3/4 Running,1 个 CrashLoopBackOff

Thought: 有 Pod 在崩溃。看崩溃原因。
Action: kubectl logs <crashed-pod> -n prod --tail=100
Observation: panic: redis: connection refused

Thought: Redis 连不上。确认 Redis 是否正常。
Action: kubectl get pods -n infra | grep redis
Observation: redis-master-0 Running,但 READY 0/1

Thought: Redis 起来了但没就绪。看 Redis 事件。
Action: kubectl describe pod redis-master-0 -n infra
Observation: Liveness probe failed: NOAUTH Authentication required

Thought: 找到根因——Redis 密码变了但 order-service 没更新配置
Final Answer: 根因是 Redis 密码被修改,order-service 仍用旧密码连接。
修复:更新 order-service 的 Secret。

Plan-and-Execute 适合发布流程:

Plan:
1. 拉取最新镜像 v1.5.0
2. 在 staging 部署,跑冒烟测试
3. 生产灰度 10% 流量,观察 10 分钟
4. 全量发布
5. 监控 SLO 1 小时,无异常则完成

Execute step 1: ...
Execute step 2: ...

踩坑提示:ReAct 在运维场景里要小心"无限循环"——模型一直思考但永远给不出结论。要么在 prompt 里写"最多 5 步,超过则停止并给出当前推断",要么在代码层加 max_iterations=10 的硬限制。

LLMOps 完整流程体系

LLMOps 是指大模型应用从开发到运维的全生命周期管理。说白了就是把 DevOps 那套搬到 LLM 应用上,但比传统应用复杂——因为模型本身是个"黑盒",输出不确定性高。

完整流程:数据 → 训练 → 评测 → 部署 → 监控

┌────────────────────────────────────────────────────────────────┐
│ 1. 数据准备                                                    │
│    - 原始数据采集(日志/告警/SOP/文档)                          │
│    - 清洗、去重、脱敏(密钥、PII 必须处理)                      │
│    - 标注:人工标注金标问答对                                    │
│    - 向量化:embedding 模型把文档转成向量                        │
│    工具:DVC / LakeFS / Unstructured / LangChain loaders        │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 2. 模型选择与训练                                               │
│    - 基座选型:GPT-4 / Claude / Qwen / Llama(看预算和合规)     │
│    - Prompt 工程:写 system / few-shot                          │
│    - 微调(可选):SFT 监督微调、DPO 偏好优化                    │
│    工具:OpenAI SDK / vLLM / LLaMA-Factory / Axolotl            │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 3. 评测(Evaluation)                                          │
│    - 离线评测:准确率 / 召回率 / BLEU / ROUGE                   │
│    - 业务评测:是否解决工单、是否被人工接管                      │
│    - 红队测试:prompt 注入、越狱、敏感问题                      │
│    工具:RAGAS / DeepEval / Promptfoo / 自建 benchmark          │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 4. 部署推理                                                    │
│    - 模型服务:vLLM / TGI / Triton / SGLang                    │
│    - 接入层:FastAPI + 限流 + 缓存                              │
│    - 流量灰度:1% → 10% → 100%                                  │
│    工具:BentoML / Ray Serve / KServe / LiteLLM                 │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 5. 监控与反馈                                                  │
│    - 性能:延迟 P50/P99、吞吐、错误率                           │
│    - 质量:用户点赞/踩、人工接管率、幻觉率                       │
│    - 成本:token 消耗、API 费用                                 │
│    - 安全:prompt 注入次数、敏感输出                             │
│    工具:LangSmith / Phoenix / Langfuse / OpenLLMetry           │
└────────────────────────────────────────────────────────────────┘
                    反馈回流到数据准备阶段

白话:LLMOps 就是把 DevOps 那套"开发→测试→上线→监控"搬到 LLM 应用上,只是多了个绕不开的环节——评测。因为模型是黑盒、输出会飘,你不评测就不知道它退化了。上面那张 ASCII 图里的箭头最后"回流到数据准备",就是闭环学习的意思。

下面用更紧凑的流程图再画一遍,方便你记面试要点:

flowchart TD
    D1[数据准备
采集/清洗/标注/向量化] --> D2[模型与训练
选型/Prompt/微调] D2 --> D3[评测
离线/业务/红队] D3 --> D4[部署推理
vLLM/灰度] D4 --> D5[监控反馈
延迟/质量/成本/安全] D5 -->|回流| D1

LLMOps 工具链速查

阶段主流工具我用过的
数据版本DVC、LakeFS、Hugging Face DatasetsDVC(跟 git 配合,能 track 大文件)
文档处理Unstructured、LangChain Loaders、LlamaIndexUnstructured(PDF 解析最稳)
Embeddingbge-large-zh、text-embedding-3-small、Coherebge(中文场景首选,自部署免费)
向量库Milvus、Qdrant、Weaviate、Chroma、pgvectorMilvus(大规模)、pgvector(小项目快)
微调LLaMA-Factory、Axolotl、UnslothLLaMA-Factory(Qwen 微调最方便)
推理服务vLLM、TGI、SGLang、TritonvLLM(吞吐最高,Qwen/Llama 通吃)
评测RAGAS、DeepEval、PromptfooRAGAS(专门评 RAG)
可观测LangSmith、Langfuse、Phoenix、OpenLLMetryLangfuse(开源自部署,省费用)
网关LiteLLM、PortkeyLiteLLM(多模型统一接口)

踩坑提示:评测阶段很多人跳过,直接看 demo 效果就上线,结果线上效果一塌糊涂。最低限度也得建个 50-100 条金标问答的 benchmark,每次改 prompt 都跑一遍,看准确率有没有倒退。我团队就这么干的,省了好几次回滚。

Agent、Function Calling、Embedding 运维落地原理

Agent

Agent 是具备感知、推理和行动能力的智能体。运维 Agent 通常包含:

  • 感知层:读取指标、日志、事件、告警。
  • 推理层:LLM 进行理解、规划、决策。
  • 执行层:调用工具或 API 完成实际操作。

类比:运维 Agent 就像一个"带对讲机的抢修小组"。感知层是小组的眼睛耳朵(看监控、读日志);推理层是大脑(LLM 判断哪里坏了、下一步干啥);执行层是手(真去敲 K8s 命令、调 API)。三者形成一个"看→想→做→再看"的闭环。

下面把这三层的关系画出来:

flowchart LR
    P[感知层
指标/日志/事件/告警] --> R[推理层
LLM 理解规划决策] R --> X[执行层
工具/API 实际操作] X -->|结果| P

下面是个最小可用的运维 Agent 架构(Python + LangChain):

# ops_agent.py —— 最小运维 Agent
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
from langchain.tools import Tool
from kubernetes import client, config

# 加载 K8s 配置
config.load_kube_config()

def get_pod_status(namespace: str) -> str:
    """查询指定 namespace 下 Pod 状态"""
    v1 = client.CoreV1Api()
    pods = v1.list_namespaced_pod(namespace)
    lines = []
    for p in pods.items:
        lines.append(f"{p.metadata.name}: {p.status.phase}")
    return "\n".join(lines)

def scale_deployment(input_str: str) -> str:
    """扩容 Deployment,输入格式:namespace/dep_name:replicas"""
    # 关键:解析参数要严格校验,防止 LLM 传奇怪值
    try:
        target, replicas = input_str.split(":")
        namespace, dep_name = target.split("/")
        replicas = int(replicas)
        if replicas < 1 or replicas > 20:
            return f"非法副本数 {replicas},允许范围 1-20"  # 硬限制,防止 LLM 扩到 100
    except Exception as e:
        return f"参数解析失败: {e}"

    apps = client.AppsV1Api()
    body = {"spec": {"replicas": replicas}}
    apps.patch_namespaced_deployment_scale(dep_name, namespace, body)
    return f"已将 {dep_name} 扩容到 {replicas} 副本"

# 定义工具
tools = [
    Tool(
        name="get_pod_status",
        func=get_pod_status,
        description="查询 K8s Pod 状态,输入 namespace 名"
    ),
    Tool(
        name="scale_deployment",
        func=scale_deployment,
        description="扩容 Deployment,输入格式 namespace/dep_name:replicas"
    ),
]

# 初始化 Agent
llm = ChatOpenAI(model="gpt-4o", temperature=0)  # temperature=0 保证稳定
agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    max_iterations=5,         # 硬限制,防止无限循环
    early_stopping_method="generate"
)

# 跑起来
result = agent.run("查看 prod 命名空间 Pod 状态,如果有 Pod 不健康就扩容到 5 副本")
print(result)

踩坑提示:Agent 自动扩容这种危险动作,绝对不能直接执行。我生产里的做法是 Agent 给出建议,推到飞书让值班同学点"确认"按钮,回调之后才真正调 K8s API。全自动执行只在 staging 环境放开。

Function Calling

Function Calling 允许 LLM 根据用户意图生成结构化函数调用参数。例如模型可以输出:

{
  "name": "scale_deployment",
  "arguments": {
    "namespace": "prod",
    "deployment": "api-gateway",
    "replicas": 5
  }
}

系统解析后调用真实函数,并将结果返回给模型继续推理。

完整 JSON 工具定义

下面是一份完整的 OpenAI Function Calling 工具定义,运维场景常用:

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "query_prometheus",
        "description": "查询 Prometheus 指标。仅支持已知的安全 PromQL,禁止使用子查询。",
        "parameters": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "description": "PromQL 表达式,例如 rate(http_requests_total[5m])"
            },
            "start": {
              "type": "string",
              "description": "起始时间,ISO 8601 格式"
            },
            "end": {
              "type": "string",
              "description": "结束时间,ISO 8601 格式"
            }
          },
          "required": ["query"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "scale_deployment",
        "description": "扩缩容 K8s Deployment。需要人工确认后才真正执行。",
        "parameters": {
          "type": "object",
          "properties": {
            "namespace": {
              "type": "string",
              "description": "命名空间"
            },
            "deployment": {
              "type": "string",
              "description": "Deployment 名称"
            },
            "replicas": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "description": "目标副本数,范围 1-20"
            }
          },
          "required": ["namespace", "deployment", "replicas"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "restart_pod",
        "description": "重启指定 Pod。仅用于非数据库 Pod。",
        "parameters": {
          "type": "object",
          "properties": {
            "namespace": {
              "type": "string"
            },
            "pod_name": {
              "type": "string"
            },
            "reason": {
              "type": "string",
              "description": "重启原因,会记录到审计日志"
            }
          },
          "required": ["namespace", "pod_name", "reason"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_knowledge_base",
        "description": "搜索运维知识库,返回历史故障复盘、SOP 文档。",
        "parameters": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "description": "搜索关键词"
            },
            "top_k": {
              "type": "integer",
              "default": 3,
              "minimum": 1,
              "maximum": 10
            }
          },
          "required": ["query"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

Python 侧调用示例:

# function_calling.py —— OpenAI Function Calling 示例
import json
from openai import OpenAI

client = OpenAI()

# 可用工具映射
AVAILABLE_FUNCTIONS = {
    "query_prometheus": query_prometheus,
    "scale_deployment": scale_deployment,
    "restart_pod": restart_pod,
    "search_knowledge_base": search_knowledge_base,
}

def run_agent(user_query: str):
    messages = [
        {"role": "system", "content": "你是运维助手,能调用工具处理 K8s/Prometheus 相关任务。"},
        {"role": "user", "content": user_query}
    ]

    # 第一轮:模型决定调哪个函数
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=TOOLS,            # 上面那份 JSON
        tool_choice="auto"
    )
    msg = response.choices[0].message

    # 如果模型决定调用工具
    if msg.tool_calls:
        messages.append(msg)
        for call in msg.tool_calls:
            func_name = call.function.name
            args = json.loads(call.function.arguments)

            # 关键:执行前校验权限和参数
            if func_name in ("scale_deployment", "restart_pod"):
                # 危险动作,必须人工确认
                approved = ask_human_approval(func_name, args)
                if not approved:
                    result = "用户拒绝执行该操作"
                else:
                    result = AVAILABLE_FUNCTIONS[func_name](**args)
            else:
                result = AVAILABLE_FUNCTIONS[func_name](**args)

            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": str(result)
            })

        # 第二轮:模型基于工具结果生成最终回答
        final = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=TOOLS
        )
        return final.choices[0].message.content

    return msg.content

def ask_human_approval(action: str, args: dict) -> bool:
    """推飞书消息给值班同学,等点确认按钮"""
    # 实际实现省略,返回 True/False
    return True

踩坑提示:Function Calling 的 description 字段千万别省略,模型靠它判断该不该调这个函数。我有次只写 "scale_deployment",结果模型该扩容时不扩、不该扩时瞎扩。把 description 写成"扩缩容 K8s Deployment,需要人工确认"之后,调用准确率立刻上来。

Embedding

Embedding 将文本、日志、文档等转换为高维向量,用于语义检索。结合向量数据库(如 Milvus、Weaviate、Chroma),可实现运维知识库的语义搜索与 RAG。

RAG 完整架构

                    ┌─────────────────────────────────┐
   用户问题          │  Query Rewriting(查询改写)    │
   "订单 500"  ────→ │  改成检索友好的关键词            │
                    │  "订单服务 500 错误 故障排查"     │
                    └──────────────┬──────────────────┘
                    ┌──────────────────────────────────┐
                    │  Embedding Model(bge-large-zh) │
                    │  把 query 转成 1024 维向量        │
                    └──────────────┬──────────────────┘
              ┌────────────────────┴────────────────────┐
              ↓                                          ↓
   ┌────────────────────┐                    ┌──────────────────────┐
   │ 向量检索(语义)    │                    │ BM25 检索(关键词)   │
   │ Milvus / pgvector  │                    │ Elasticsearch         │
   │ Top-K = 10         │                    │ Top-K = 10            │
   └─────────┬──────────┘                    └──────────┬────────────┘
             └────────────────────┬─────────────────────┘
                    ┌──────────────────────────────────┐
                    │ Reranker(bge-reranker-base)    │
                    │ 精排,取 Top 3                    │
                    └──────────────┬──────────────────┘
                    ┌──────────────────────────────────┐
                    │ LLM 生成回答                      │
                    │ 上下文:召回文档 + 告警信息        │
                    │ 输出:根因 + 处置步骤 + 引用来源   │
                    └──────────────────────────────────┘

白话:RAG 就是给 LLM 配一个"开卷考试"的资料包。用户提问先改写成好检索的关键词,转成向量去资料库里找最像的几段,再用 Reranker 精排,最后把"问题 + 召回资料"一起喂给 LLM 生成答案,并附上引用来源。没有这个资料包,LLM 只能凭记忆瞎编(幻觉)。

下面把 RAG 的检索链路画成流程图:

flowchart TD
    Q[用户问题] --> QW[Query 改写]
    QW --> E[Embedding 向量化]
    E --> V[向量检索 + BM25 混合]
    V --> RR[Reranker 精排 Top3]
    RR --> L[LLM 生成回答
根因+步骤+来源]

文档入库流程:

# index_docs.py —— 文档入库
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain_milvus import Milvus

# 1. 加载文档(复盘 markdown、SOP、Confluence 导出)
from langchain.document_loaders import DirectoryLoader
loader = DirectoryLoader("./docs", glob="**/*.md")
docs = loader.load()

# 2. 切块:每块 500 字符,重叠 50,保证上下文不断
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n## ", "\n### ", "\n\n", "\n", "。", " "]
)
chunks = splitter.split_documents(docs)

# 3. Embedding:bge-large-zh,中文场景最稳
embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-large-zh-v1.5",
    model_kwargs={"device": "cpu"}     # 没 GPU 就 CPU,慢点但能跑
)

# 4. 存 Milvus
vectorstore = Milvus.from_documents(
    documents=chunks,
    embedding=embeddings,
    connection_args={"host": "milvus", "port": "19530"},
    collection_name="ops_knowledge"
)

向量库选型对比

向量库部署方式性能易用性适合场景
Milvus集群部署高(亿级)大规模生产,千万级以上向量
Qdrant单机/集群高(Rust)中等规模,重视过滤查询
Weaviate集群部署中高需要 GraphQL 接口
Chroma嵌入式低(万级)极高原型、本地 demo
pgvectorPG 插件高(SQL)已有 Postgres,向量量小(百万级以下)
Elasticsearch集群部署已经在用 ES,不想引新组件

我自己的选型经验:

  • 原型阶段:Chroma,几行代码就能跑,啥都不用配。
  • 小规模生产(百万级向量):pgvector,跟业务库共用一套 Postgres,运维成本最低。
  • 大规模生产(千万级以上):Milvus 集群,性能最稳但要配运维。

踩坑提示:Embedding 模型选型一定要看语言。一开始我用 text-embedding-ada-002 处理中文复盘文档,召回率惨不忍睹——英文模型对中文分词和语义理解都不行。换成 bge-large-zh-v1.5 之后立刻好转。中文场景 bge 系列真的是首选。

另一个坑:chunk_size 不是越小越好。我试过 200 字符的小块,召回很准但每块信息太少,LLM 拼不出完整答案。500 字符 + 50 重叠是我反复试出来的甜点值,你的数据可能不一样,多试几个。

AIOps 四大核心价值

  1. 运维自动化:将重复性、规则明确的操作交给智能体执行,降低 Toil。
  2. 排障预测:通过时序预测与异常检测,提前发现潜在故障。
  3. 资源优化:基于负载预测自动扩缩容,提升资源利用率。
  4. 业务创新:释放运维人力,支持更快速的业务迭代与实验。

总结

AIOps 不是简单的"AI + 运维工具",而是数据、算法、工程与组织流程的深度融合。掌握 LLM、Prompt Engineering、LLMOps、Agent 与 Function Calling 等知识栈,是后续开发智能运维系统的基础。

说真的学到这里你会发现一个矛盾:AIOps 想做的事情(自动决策、自动执行)和运维的本质诉求(稳定、可控)天然冲突。我现在的看法是——AIOps 在很长一段时间内都不会是"全自动",而是"人机协同":LLM 负责"想",人负责"批",工具负责"做"。能做到这一步就已经比纯人工强太多了。后面真正做 Operator、做 Agent 的时候,再回头品这章,你会发现每个设计都在回答同一个问题:怎么让 AI 帮你干活,但不让它闯祸。


自测题与动手练习

自测题(合上书能答出来,才算懂)

  1. Gartner 把 AIOps 分成哪五个阶段?为什么多数公司卡在 2-3,而上不到 4-5?
  2. “角色 + 上下文 + 约束"三段式 Prompt 里,哪一段对故障诊断准确率影响最大?约束段为什么要写"不要重启数据库"这类红线?
  3. Few-shot、CoT、结构化输出分别治大模型的什么毛病?ReAct 和 Plan-and-Execute 各自适合什么场景?
  4. LLMOps 的完整生命周期包含哪几步?监控反馈是怎么"回流"的?
  5. 运维 Agent 的感知层 / 推理层 / 执行层各做什么?为什么"自动扩容、重启 Pod"这类危险动作绝不能全自动执行?

动手练习(建议真做一遍)

  1. 用三段式模板,把文中 order-service 5xx 的例子填进去;再去掉 Context 段跑一次,对比两次输出准确率的差异。
  2. 给"日志分类"的 Few-shot 模板补 2 条你自己业务的日志样例,观察分类是否更稳。
  3. 跑最小运维 Agent,把用户问题设成"重启 mysql 主库”,验证你加的红线约束是否拦下这个危险建议。

本章小结

  • AIOps 是什么:AI + 运维的深度融合;Gartner 五阶段从 Observe 到 Evolve,多数公司卡在 2-3,因为自动执行风险太高。
  • Prompt 工程:角色 + 上下文 + 约束三段式;Context 段决定准确率,约束段写红线(如禁止重启生产库)。
  • 任务规划:Few-shot / CoT / 结构化输出提升稳定性;ReAct 适合探索性排查,Plan-and-Execute 适合步骤明确的审计场景。
  • LLMOps:数据 → 训练 → 评测 → 部署 → 监控的完整生命周期,反馈回流形成闭环。
  • 落地三件套:Agent(感知/推理/执行)= 让 AI 会想会做;Function Calling = 让模型调真实工具;Embedding + RAG = 给模型配开卷资料。核心红线:危险动作必须人工确认

下一章可以深入"如何把 Agent 接进真实的告警与工单系统",以及"评测体系怎么搭",把这一章的知识栈真正跑成生产可用的智能运维。

About Me

没什么想介绍的,一个很大众的码农…

喜欢代码,车,马,真的是 🐎

讨厌别人让我给自己的代码写注释 最厌烦别人的程序没有写注释

目标

学AI,加油!加油!