
1. 从告警风暴到自愈闭环AIOPS 系统架构到底要解决什么AIOPS 系统架构这个词听起来很宏大但落到日常运维里它要解决的核心问题其实很朴素凌晨三点告警群炸了二十条告警指向同一个故障值班同学要花四十分钟翻日志、查指标、对变更最后发现是某个服务的内存泄漏。这套流程里人做的判断大部分是可以被结构化的而 AIOPS 系统架构要做的就是把这套判断链路沉淀成可复用的编排逻辑。我理解的 AIOPS 系统架构本质上是三层能力的叠加。第一层是感知层负责把告警、日志、指标、变更记录这些异构数据统一采集进来第二层是认知层用 RAG 检索增强把历史故障案例、运维手册、SOP 文档变成可检索的知识第三层是执行层通过 MCP 工具协议把 K8s、Prometheus、日志系统这些外部工具标准化注册让 Agent 能真正动手操作而不只是给建议。Hermes Agent 在这套架构里扮演的是调度中枢的角色。它不直接干活而是负责 Plan-Execute-Replan 的循环先根据用户意图生成执行计划再并行调度多个 Skill 去采集证据最后根据置信度决定是否需要重新规划。这个循环的价值在于它把「一次问答」变成了「一轮诊断」Agent 会自己判断证据够不够、要不要再查一轮。适合谁看这篇如果你正在做运维平台建设或者想把现有的告警系统升级成能自动根因分析的闭环那这套架构可以直接参考。如果你只是想了解 Agent 编排的基本套路里面的配置片段和排障思路也能用得上。接下来我会按「问题场景 → 前置准备 → 可复制配置 → 验证请求 → 常见报错 → 接入入口」的顺序展开每一步都给到能直接跑的配置。2. TaoToken 前置准备Hermes Agent 接入大模型与 MCP 服务注册在搭 AIOPS 系统架构之前得先把模型调用这条链路打通。Hermes Agent 本身是个编排框架它需要一个大模型来做意图理解和计划生成这里我用 TaoToken 作为模型接入层原因是它的 API 兼容 OpenAI 格式配置成本低而且支持在同一个 Key 下切换不同模型做对比测试。第一步是拿到 API Key。访问 https://taotoken.net/api-keys 创建密钥注意这个 Key 只在创建时显示一次复制后存到环境变量里别硬编码进配置文件。我习惯用.env文件管理配合dotenv加载# .env TAOTOKEN_API_KEYsk-xxxxxxxxxxxxxxxx TAOTOKEN_BASE_URLhttps://taotoken.net/api HERMES_MODELclaude-sonnet-4-20250514第二步是确认模型 ID。不同模型在计划生成和工具调用上的表现差异很大做 AIOPS 这种需要多轮工具调用的场景建议选支持 function calling 的模型。你可以先在 https://taotoken.net/models 看可用列表或者直接用模型对话页面 https://taotoken.net/chat 试一轮确认模型能正确返回结构化输出再写进配置。第三步是 MCP 服务注册。MCP 是 Model Context Protocol 的缩写它定义了一套标准接口让 Agent 能用统一的方式调用外部工具。在 Hermes Agent 里MCP 服务通过配置文件注册每个服务声明自己的传输方式stdio 或 HTTP、启动命令和工具列表。这里有个坑stdio 类型的 MCP 服务需要 Agent 进程能直接拉起子进程如果你把 Hermes 跑在容器里要确保容器内有对应的运行时环境。前置准备做完后你的目录结构大概是这样aiops-hermes/ ├── .env ├── config/ │ ├── agent.yaml │ ├── mcp-servers.json │ └── rag.yaml ├── skills/ │ ├── aiops-k8s-inspect/ │ ├── aiops-log-analyze/ │ └── aiops-alert-analyze/ └── knowledge/ └── docs/这个结构不是强制的但把配置、技能、知识库分开管理后面排查问题会清晰很多。特别是当你有十几个 Skill 的时候混在一起找起来很痛苦。3. 可复制配置Hermes Agent 编排 RAG 知识库 MCP 服务注册这一节是整篇的核心我会给出三份可直接复制的配置文件。先说明一下这些配置的路径和字段名要和你实际部署的环境对齐我用的路径是config/目录下的相对路径。3.1 Hermes Agent 编排配置 agent.yaml这份配置定义了 Agent 的 Plan-Execute-Replan 循环参数、模型接入信息和 Skill 注册表# config/agent.yaml agent: name: aiops-hermes mode: plan-execute-replan max_replan_rounds: 3 confidence_threshold: 0.75 parallel_execution: true max_parallel_skills: 4 model: provider: openai-compatible base_url: ${TAOTOKEN_BASE_URL} api_key: ${TAOTOKEN_API_KEY} model_id: ${HERMES_MODEL} temperature: 0.2 max_tokens: 4096 skills: - name: aiops-k8s-inspect path: skills/aiops-k8s-inspect description: 检查 K8s 集群 Pod 状态、事件、资源配额 timeout: 60 - name: aiops-log-analyze path: skills/aiops-log-analyze description: 聚合 Loki 日志并提取异常模式 timeout: 90 - name: aiops-alert-analyze path: skills/aiops-alert-analyze description: 告警去重、关联、优先级排序 timeout: 30 - name: aiops-prometheus-daily path: skills/aiops-prometheus-daily description: 查询 Prometheus 指标并做同比环比 timeout: 60 - name: aiops-safety-gate path: skills/aiops-safety-gate description: 自愈动作执行前的安全检查与审批 timeout: 30 rag: enabled: true config_path: config/rag.yaml mcp: config_path: config/mcp-servers.json这里有几个参数值得展开说。confidence_threshold设成 0.75 是我实测下来比较平衡的值太低会导致 Agent 在证据不足时就下结论太高会陷入无限重规划。max_parallel_skills设成 4 是因为大部分故障诊断场景下并行查 K8s 状态、日志、指标、告警这四路证据就够了再多会拖慢整体响应。3.2 RAG 知识库接入配置 rag.yamlRAG 这块我用 Qdrant 做向量存储Ollama 做 embedding。配置里要写清楚分块策略、检索参数和知识库路径# config/rag.yaml vector_store: type: qdrant host: localhost port: 6333 collection: aiops_knowledge vector_size: 768 distance: cosine embedding: provider: ollama base_url: http://localhost:11434 model: nomic-embed-text batch_size: 32 chunking: strategy: recursive chunk_size: 512 chunk_overlap: 64 separators: - \n## - \n### - \n\n - \n retrieval: top_k: 5 score_threshold: 0.6 rerank: false knowledge_base: paths: - knowledge/docs/sop - knowledge/docs/postmortem - knowledge/docs/runbook file_types: - .md - .txt - .yaml分块策略这里我选的是按标题层级切分因为运维文档通常有清晰的章节结构按##和###切能保证每个 chunk 语义完整。chunk_size设 512 是配合 768 维 embedding 模型的常见做法太大检索精度会下降太小会丢上下文。3.3 MCP 服务注册 mcp-servers.jsonMCP 服务注册决定了 Agent 能调用哪些外部工具。这份配置里我注册了 K8s、Prometheus、Loki 三个核心服务{ mcpServers: { kubernetes: { transport: stdio, command: npx, args: [-y, modelcontextprotocol/server-kubernetes], env: { KUBECONFIG: /root/.kube/config }, tools: [get_pods, describe_pod, get_events, get_nodes] }, prometheus: { transport: http, url: http://101.201.239.56:31183/mcp, headers: { Authorization: Bearer ${PROMETHEUS_TOKEN} }, tools: [query, query_range, list_alerts] }, loki: { transport: http, url: http://10.200.200.105:8353/mcp, headers: { X-Scope-OrgID: aiops }, tools: [query_logs, tail_logs] } } }注意 stdio 类型的服务需要command和argsHTTP 类型的只需要url和headers。如果你用的是 Cline MCP 或者 Claude Code 这类客户端配置格式基本一致只是文件路径不同。Claude Code 的配置在~/.claude/claude_desktop_config.jsonCline 的在 VS Code 设置里。三件套对齐检查Base URL 用https://taotoken.net/apiKey 用你在 api-keys 页面创建的Model ID 用claude-sonnet-4-20250514或你确认可用的其他模型。这三个字段在 agent.yaml 的 model 段里都能找到对应位置。4. 验证请求一轮故障注入确认闭环链路真实可用配置写完不代表能用得做一轮真实的故障注入来验证。我设计的验证场景是在测试命名空间里部署一个会 OOM 的 Pod然后手动触发告警看 Agent 能不能走完「告警接收 → 证据采集 → 根因分析 → 自愈建议」的完整链路。4.1 注入故障先创建一个会持续吃内存的 Pod# fault-injection.yaml apiVersion: v1 kind: Pod metadata: name: memory-hog namespace: aiops-test labels: app: memory-hog spec: containers: - name: hog image: polinux/stress command: [stress] args: [--vm, 1, --vm-bytes, 256M, --vm-hang, 1] resources: limits: memory: 128Mi requests: memory: 64Mi应用这个配置后Pod 会因为内存超限被 OOMKilled反复重启。这时候 K8s 会产生OOMKilling事件Prometheus 会采集到容器重启指标Loki 里会有对应的日志。kubectl apply -f fault-injection.yaml kubectl get pods -n aiops-test -w4.2 触发 Agent 诊断通过 Hermes Agent 的 API 发起一轮诊断请求curl -X POST http://localhost:8080/api/diagnose \ -H Content-Type: application/json \ -d { query: aiops-test 命名空间有 Pod 反复重启请分析根因并给出处理建议, context: { namespace: aiops-test, time_range: 15m }, enable_rag: true, enable_mcp: true }4.3 预期结果正常情况下Agent 会返回一份 9 段式诊断报告包含告警摘要、影响范围、证据链、根因判断、置信度、自愈建议、风险提示、执行命令、回滚方案。关键看几个点证据链里是否引用了 K8s 事件和 Prometheus 指标根因判断是否指向内存限制配置不当置信度是否高于 0.75。如果 Agent 返回的置信度低于阈值它会自动进入 Replan 阶段调整查询策略再查一轮。你可以在日志里看到replan_round1这样的标记。实测下来OOM 这种场景通常一轮就能定位但如果是网络抖动导致的间歇性故障可能需要两到三轮。验证通过的标准是Agent 给出的自愈建议里包含具体的kubectl patch命令并且这条命令经过aiops-safety-gate检查后标记为「低风险可自动执行」。如果安全门控标记为「需人工审批」说明你的风险规则配置得比较严格这在生产环境是好事。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth配置和验证过程中最容易踩的坑集中在认证和网络这两块。我把几个高频报错和对应的排查思路列出来你遇到时可以对照着看。5.1 401 Unauthorized这个报错通常出现在模型调用环节。先检查.env里的TAOTOKEN_API_KEY是否被正确加载可以在启动脚本里加一行echo $TAOTOKEN_API_KEY | head -c 10确认前几位。如果 Key 没问题再看base_url是否写成了https://taotoken.net/api注意末尾不要多加斜杠有些 HTTP 客户端会把//当成路径分隔符处理。还有一种情况是 Key 的权限范围不对。如果你在 api-keys 页面创建时限制了模型访问范围而 agent.yaml 里配的模型不在范围内也会返回 401。解决办法是重新创建一个不限制模型的 Key或者把模型 ID 改成权限范围内的。5.2 local proxy failed这个报错一般出现在 MCP 服务注册环节特别是 stdio 类型的服务。local proxy failed的意思是 Agent 尝试拉起子进程失败了。排查步骤先确认command字段里的可执行文件在 PATH 里比如npx需要 Node.js 环境再确认args里的包名拼写正确modelcontextprotocol/server-kubernetes这种包名很容易打错。如果是在容器里跑还要检查容器的securityContext是否允许 fork 子进程。有些安全策略会禁止容器内启动新进程这种情况下要么改用 HTTP 类型的 MCP 服务要么调整安全策略。5.3 reading choices 相关报错这个报错通常长这样error reading choices: unexpected end of JSON input。原因是模型返回的响应不是合法的 JSON常见于模型输出被截断或者返回了非结构化内容。排查方向先看max_tokens是不是设得太小4096 对于复杂的计划生成可能不够可以临时调到 8192 试试再看temperature是不是太高做结构化输出时建议设 0.2 以下。如果调整参数后还是报错可以在 Agent 配置里开启response_format: json_object如果模型支持强制模型返回 JSON。另外检查一下你的 prompt 模板确保明确要求了输出格式。5.4 OAuth 相关报错如果你用的是 Claude Code 或者 Cline 这类客户端可能会遇到 OAuth 认证失败。这类客户端通常有自己的认证流程和 API Key 是两套机制。排查时先确认你用的是 API Key 模式而不是 OAuth 模式在客户端的设置里找「使用 API Key」或「自定义 Base URL」的选项把https://taotoken.net/api填进去。如果客户端强制走 OAuth可以看它的文档是否支持自定义认证端点。Claude Code 的配置在~/.claude/settings.jsonCline 的在 VS Code 的settings.json里搜cline.apiProvider。配置时记得三件套对齐Base URL、Key、Model ID 一个都不能少。5.5 排障通用思路遇到报错时先看 Agent 的日志级别是不是 DEBUG如果不是就临时调高。日志里会打印每次模型调用的请求体和响应体对照着看能快速定位是配置问题还是模型输出问题。另外MCP 服务的日志是独立的stdio 类型的服务日志会混在 Agent 日志里HTTP 类型的需要去对应的服务端看。6. 接入入口与后续扩展整套 AIOPS 系统架构跑通之后你可以按自己的环境做扩展。比如把 RAG 知识库从本地文档扩展到 Confluence 或语雀的 API 拉取把 MCP 服务从 K8s 扩展到云厂商的 OpenAPI把自愈动作从建议扩展到自动执行记得保留安全门控。模型接入这块如果你需要长期跑编码类或 Agent 类任务可以看下 Coding Plan 方案 https://taotoken.net/coding-plan 它在多轮工具调用场景下的额度策略更适合生产环境。日常调试和验证模型输出用模型对话页面 https://taotoken.net/chat 就够了。API Key 管理在 https://taotoken.net/api-keys 接入文档在 https://taotoken.net/doc 里面有各语言 SDK 的示例代码。最后说一个我踩过的坑MCP 服务的超时时间要设得比 Skill 的 timeout 短否则 Skill 已经超时返回了MCP 服务还在跑会留下僵尸进程。我一般把 MCP 超时设成 Skill 超时的 80%给 Agent 留出处理超时结果的时间。这个细节在文档里没写但生产环境跑久了就会遇到。