1. 凌晨三点的告警,和一套能自己干活的运维 Agent
凌晨三点被电话炸醒,翻几百条日志排查两小时,最后发现只是某个节点磁盘写满——这种场景做运维的朋友应该都不陌生。更麻烦的是大促期间上百个微服务同时告警,你根本分不清哪个是根因、哪个是次生故障,MTTR 一路飙到几小时,业务损失按分钟算。传统基于规则的告警体系在云原生架构下已经明显跟不上:规则维护成本高、新场景必须手动加、泛化能力差,而且只能告警不能诊断,更不能修复。
这篇要聊的是怎么从 0 到 1 搭一个运维 AI Agent,把异常检测、故障诊断、自动修复串成一条可复现的链路。核心思路是把大模型作为决策层,用 RAG 召回历史故障和运维手册,用工具调用去验证假设,最后通过统一的 API 通道执行修复动作。整条链路里最容易被忽略但最影响落地效率的,其实是模型接入层——如果每个 Agent 模块都要单独配一套 Key、单独处理限流和重试,工程复杂度会迅速失控。所以我会用 TaoToken 作为统一 Key/API 通道,把异常检测、诊断、修复三个模块的模型调用收敛到一个入口,再给出 config.toml 和 settings.json 的骨架,以及 CC Switch / Cline 的配置示例。
适合谁看:正在做 AIOps 落地、想把大模型接进现有监控体系的 SRE / 平台工程师;已经在用 Cline、Claude Code 这类工具、想把它扩展成运维 Agent 的开发者;以及被重复故障折腾到想自动化一部分修复动作的团队。读完你能拿到一套可以直接跑的骨架,包括一次完整的故障注入与修复验证动作。
2. 为什么用 TaoToken 做统一 Key 通道
先说清楚定位:TaoToken 在这里的角色是模型调用的统一入口,不是替代你的监控系统,也不是替代 Harness 或 K8s。它解决的是一个很具体的工程问题——运维 Agent 的多个模块(异常检测的时序分析、根因诊断的 RAG 问答、修复方案的生成与校验)都要调模型,如果每个模块各自管 Key、各自处理超时和重试,代码里会散落一堆重复逻辑,换模型或调参数时改起来非常痛苦。
统一 Key 之后,你只需要在配置里维护一份 base_url 和 api_key,所有模块通过同一个通道发请求。这样做的好处有三个:一是密钥管理收敛,不用在多个服务的环境变量里同步;二是调用行为一致,重试、超时、日志格式统一;三是切换模型成本低,改一行配置就能从诊断模型换到修复模型。
接入地址分两个,注意区分:
- 官网入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
- API 基址:https://taotoken.net/api(这个不加 UTM,直接用于代码里的 base_url)
如果你还没建 Key,先去控制台创建:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,然后在 API Keys 页面生成:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到参数问题先查这里。
注意:API Key 只放在服务端环境变量或本地配置文件里,不要提交到 Git,也不要在前端代码里出现。
3. 可复制配置:config.toml 与 settings.json 骨架
先给一份 config.toml,这是运维 Agent 主程序的配置,覆盖模型通道、异常检测阈值、修复风险分级三块。我把它放在项目根目录的 config/ 下。
# config/config.toml [llm] # 统一走 TaoToken 通道,所有模块共用 base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" # 从环境变量读取,不要硬编码 diagnose_model = "claude-sonnet-4-20250514" repair_model = "claude-sonnet-4-20250514" timeout_seconds = 60 max_retries = 3 [anomaly] # 异常检测:SLO burn rate 粗筛 + 时序细筛 burn_rate_threshold = 5.0 isolation_contamination = 0.05 metric_window_minutes = 60 min_anomaly_points = 3 [repair] # 修复风险分级,P3 永远人工 auto_execute_levels = ["P1"] require_approval_levels = ["P2", "P3"] verify_wait_seconds = 120 verify_poll_interval = 10 [observability] prometheus_url = "http://prometheus.monitoring:9090" log_query_url = "http://loki.monitoring:3100"再给一份 settings.json,这是给 Cline / Claude Code 这类编码 Agent 用的,让它们也能走同一个通道去读写运维脚本、生成修复 Pipeline。
{ "llmProvider": { "type": "openai-compatible", "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "model": "claude-sonnet-4-20250514" }, "agent": { "name": "ops-harness-agent", "maxToolCalls": 20, "allowShell": false, "allowFileWrite": true, "workspace": "./ops_workspace" }, "tools": { "prometheus": { "url": "http://prometheus.monitoring:9090" }, "loki": { "url": "http://loki.monitoring:3100" }, "k8sContext": "prod-cluster" } }CC Switch 的配置更简单,它本质是帮你切换不同模型通道。在它的配置文件里加一个 provider 指向 TaoToken:
{ "providers": [ { "name": "taotoken", "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "models": ["claude-sonnet-4-20250514"] } ], "active": "taotoken" }Cline 的配置在 VS Code 设置里,搜索 Cline,把 API Provider 选成 OpenAI Compatible,Base URL 填 https://taotoken.net/api ,API Key 填你的 Key,Model ID 填上面那个模型名。这样你在 Cline 里让它写运维脚本、生成 K8s manifest、分析日志,都走同一条通道。
提示:config.toml 里的 ${TAOTOKEN_API_KEY} 是占位符,实际运行时用 os.environ 读取,不要直接把 Key 写进文件。
4. 异常检测、诊断、修复三段链路怎么串
配置就绪后,核心是把三个模块串起来。我用 Python 写一个最小可跑的骨架,依赖只有 requests、scikit-learn、numpy。
4.1 异常检测:先粗筛再细筛
第一层用 SLO burn rate 过滤掉不影响用户的抖动,第二层用 Isolation Forest 定位具体异常维度。burn rate 的算法是错误预算消耗速度除以预期消耗速度,超过阈值才进入诊断。
# ops_agent/anomaly.py import os, numpy as np, requests from sklearn.ensemble import IsolationForest PROM = os.environ.get("PROM_URL", "http://prometheus.monitoring:9090") def query_range(metric, minutes=60): end = int(__import__("time").time()) start = end - minutes * 60 r = requests.get(f"{PROM}/api/v1/query_range", params={ "query": metric, "start": start, "end": end, "step": "15s" }, timeout=10) r.raise_for_status() return r.json()["data"]["result"] def burn_rate(service, slo_target=0.999): res = query_range(f'http_server_requests_error_rate{{service="{service}"}}', 5) if not res: return 0.0 vals = [float(v[1]) for v in res[0]["values"]] avg_err = sum(vals) / len(vals) return avg_err / (1 - slo_target) def detect(service): metrics = [ f'http_server_requests_seconds_avg{{service="{service}"}}', f'http_server_requests_error_rate{{service="{service}"}}', f'container_cpu_usage_percent{{service="{service}"}}', f'container_memory_usage_percent{{service="{service}"}}', ] series = [] for m in metrics: res = query_range(m, 60) if res: series.append([float(v[1]) for v in res[0]["values"]]) if len(series) < 3: return False, [] n = min(len(s) for s in series) X = np.array([s[:n] for s in series]).T clf = IsolationForest(n_estimators=100, contamination=0.05, random_state=42) preds = clf.fit_predict(X) idx = np.where(preds == -1)[0] if len(idx) <= 3: return False, [] abnormal = [] for i, m in enumerate(metrics): normal_mean = X[preds == 1][:, i].mean() abn_mean = X[idx][:, i].mean() if abn_mean > normal_mean * 2: abnormal.append(m) return True, abnormal4.2 故障诊断:RAG + 工具校验
诊断模块的关键是别让模型瞎编。我的做法是先把异常指标和错误日志拼成问题,走 RAG 召回历史故障和运维手册,再让模型输出根因假设,最后用一个校验函数去 Prometheus 查对应指标确认假设成立。
# ops_agent/diagnose.py import os, requests BASE = os.environ["TAOTOKEN_BASE_URL"] # https://taotoken.net/api KEY = os.environ["TAOTOKEN_API_KEY"] MODEL = os.environ.get("DIAGNOSE_MODEL", "claude-sonnet-4-20250514") def call_llm(prompt, system="你是资深 SRE,输出根因和可执行修复方案。"): r = requests.post(f"{BASE}/v1/chat/completions", headers={ "Authorization": f"Bearer {KEY}", "Content-Type": "application/json" }, json={ "model": MODEL, "messages": [ {"role": "system", "content": system}, {"role": "user", "content": prompt} ], "temperature": 0.1 }, timeout=60) r.raise_for_status() return r.json()["choices"][0]["message"]["content"] def diagnose(service, abnormal_metrics, logs): prompt = f"""异常服务:{service} 异常指标:{', '.join(abnormal_metrics)} 错误日志片段:{'; '.join(logs[:10])} 请给出: 1. 最可能的根因(一句话) 2. 推理过程 3. 修复方案,按优先级排列,标注风险等级 P1/P2/P3 """ return call_llm(prompt)4.3 自动修复:风险分级 + 验证闭环
修复模块我做了三级风险:P1 自动执行(清磁盘、重启异常 Pod),P2 默认人工审核(扩容、回滚),P3 永远人工(重启数据库、切流量)。执行后必须轮询 burn rate 确认恢复,否则通知人工。
# ops_agent/repair.py import time, requests, os from .anomaly import burn_rate def execute(service, root_cause, action, params): # 这里对接你的 CD 或 K8s API,示例用占位 print(f"[repair] {service} action={action} params={params}") return True def repair_with_verify(service, root_cause, action, params, risk="P1"): if risk in ("P2", "P3"): print(f"[repair] {risk} 需人工审核,已发送通知") return False if not execute(service, root_cause, action, params): return False waited = 0 while waited < 120: if burn_rate(service) < 1: print(f"[repair] {service} 已恢复") return True time.sleep(10) waited += 10 print(f"[repair] {service} 未恢复,转人工") return False5. 一次可复现的故障注入与修复验证
光看代码不够,得跑一次。我用一个测试 Deployment 注入内存泄漏,观察 Agent 从检测到修复的完整动作。
先部署一个会缓慢吃内存的服务:
# test/leak-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: leak-demo spec: replicas: 2 selector: matchLabels: { app: leak-demo } template: metadata: labels: { app: leak-demo } spec: containers: - name: app image: polinux/stress args: ["--vm", "1", "--vm-bytes", "200M", "--vm-hang", "0"] resources: limits: { memory: "256Mi" }应用后,内存会持续上涨直到 OOMKilled,Prometheus 里的 container_memory_usage_percent 会明显偏离基线。这时候跑检测:
export TAOTOKEN_API_KEY="你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api" python -c " from ops_agent.anomaly import detect, burn_rate print('burn_rate=', burn_rate('leak-demo')) print('detect=', detect('leak-demo')) "预期输出类似:
burn_rate= 6.8 detect= (True, ['container_memory_usage_percent{service="leak-demo"}'])拿到异常指标后走诊断:
python -c " from ops_agent.diagnose import diagnose print(diagnose('leak-demo', ['container_memory_usage_percent'], ['OOMKilled', 'memory limit exceeded'])) "模型会返回根因(内存泄漏或 limit 过低)和修复方案。如果是 limit 过低,修复动作是扩容内存,风险等级 P2,走人工审核;如果是已知泄漏,回滚到上一版本,也是 P2。验证阶段轮询 burn rate,恢复到 1 以下就算成功。
整个链路跑通后,你可以把 detect → diagnose → repair_with_verify 串成一个定时任务,每 30 秒扫一次关键服务。实测下来,从注入到检测到恢复,整个闭环在 2 分钟内完成,比人工排查快一个数量级。
6. 本篇常见错排查
报错一:401 Unauthorized / invalid api key先确认环境变量 TAOTOKEN_API_KEY 是否真的注入到运行进程里,用printenv | grep TAOTOKEN检查。如果是在 Docker 里跑,注意 env_file 的路径。Key 本身去控制台重新生成一次对比。
报错二:Connection refused / timeoutbase_url 必须是 https://taotoken.net/api ,不要带尾部斜杠,也不要写成官网首页地址。如果公司网络有出口限制,确认能访问该域名。超时设 60 秒,诊断类请求偶尔会慢。
报错三:Isolation Forest 报维度不一致Prometheus 返回的多个指标序列长度可能不同,代码里已经用 min_len 对齐。如果你自己改过 query_range 的 step,确保所有指标用同一个 step,否则对齐会丢数据。
报错四:修复后 burn rate 不降先确认修复动作真的执行了,看 CD 或 K8s 的事件日志。如果动作执行了但指标没恢复,可能是根因判断错了,这时候不要重试同一个动作,直接转人工。另外 burn rate 有窗口延迟,等 1 到 2 个采集周期再看。
报错五:Cline / CC Switch 里模型列表拉不到OpenAI Compatible 模式下,有些客户端会去请求 /v1/models。如果拉不到不影响使用,直接手动填 Model ID 即可。确认 baseUrl 填的是 https://taotoken.net/api 而不是带 /v1 的地址,客户端一般会自己拼。
报错六:RAG 召回的知识库内容过时这是运维 Agent 最常见的坑。系统迭代后架构文档没更新,模型会基于旧知识给错方案。解决办法是每次故障修复后自动把故障记录写回知识库,并定期 review 架构文档。别指望一次建库管半年。
如果你在接入阶段卡住,优先看接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。需要调模型做诊断验证,可以用模型对话页面快速试 prompt:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。如果你打算长期跑编码类 Agent 来维护这套运维脚本,Coding Plan 会更划算:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。Key 管理和控制台入口分别是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 和 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。
最后说个实际经验:自动修复的边界一定要卡死,P3 永远人工。我见过太多团队为了追求全自动,把重启数据库也放进自动执行,结果一次误判直接扩大故障。Agent 的价值是把你从重复的 P1 故障里解放出来,不是替你做所有决定。