sarveshkb21/aiops-incident-response-assistant
GitHub: sarveshkb21/aiops-incident-response-assistant
基于多 agent 路由和领域隔离检索的 RAG 聊天机器人,帮助 IT 值班工程师快速从运维手册中定位事件故障排查步骤。
Stars: 0 | Forks: 0
# AIOps 事件响应助手
这是一个基于 RAG 的聊天机器人,旨在帮助 IT 值班工程师在事件发生时,利用 LangChain、ChromaDB、Gemini 和 Streamlit 即时找到
故障排查步骤。它使用了一个轻量级的 **多 agent 路由器**:每个查询首先被分类到一个
特定领域(kubernetes、database、infrastructure、network、security、cicd),然后由专门负责该领域的 agent 进行回答,且只从该领域的 runbook 中进行检索。
## 技术栈
| 组件 | 工具 |
|-----------------|-----------------------------|
| LLM | Google Gemini 2.5 Flash |
| Embeddings | Google gemini-embedding-2 |
| 框架 | LangChain 1.x |
| 向量数据库 | ChromaDB (本地) |
| UI | Streamlit |
| 编程语言 | Python 3.12+ |
## 工作原理(多 Agent 路由)
```
flowchart TD
Q["🧑💻 Engineer query"] --> R["🧭 Router
(router.classify_query · Gemini)"] R -->|kubernetes| K["☸️ Kubernetes Agent"] R -->|database| D["🗄️ Database Agent"] R -->|infrastructure| I["🖥️ Infrastructure Agent"] R -->|network| N["🌐 Network Agent"] R -->|security| S["🔒 Security Agent"] R -->|cicd| P["🚀 CI/CD Agent"] R -->|general / fallback| G["🧭 General Agent"] K & D & I & N & S & P & G --> C[("🗃️ ChromaDB
filtered by domain")] C --> A["💬 Answer + agent badge + sources"] ``` 每个专门的 agent 由 `get_agent_chain()` 构建,并且只从其所在领域的 runbook 中进行检索。这些 agent 在 `agents.py`
中作为一个注册表定义(包含 `ROUTER` 和 `AGENTS`),由 `app.py` 统一驱动。
每个查询都会经过以下三个步骤:
1. **路由** — `router.classify_query()` 会进行一次 Gemini 调用,将查询分类到特定的领域:`kubernetes`、`database`、`infrastructure`、`network`、
`security`、`cicd` 或 `general`。
2. **检索(领域隔离)** — `rag_chain.get_agent_chain(domain)` 会构建一个
RetrievalQA 链,其 ChromaDB 检索器会根据 `domain` 元数据进行过滤,因此专门的 agent 只能看到自己领域的 runbook。`general` 不应用任何过滤,会搜索所有内容。
3. **回答与徽章** — 应用程序会在响应上方显示一个彩色的 agent 徽章(☸️ Kubernetes、
🗄️ Database、🖥️ Infrastructure、🌐 Network、🔒 Security、🚀 CI/CD、🧭 General),
下方则会列出引用的 runbook 来源。
**错误路由回退:** 如果路由到的领域没有匹配到任何 runbook,应用程序会
自动进行未过滤的重试(`general`),这样错误的路由永远不会
隐藏正确的 runbook。请注意,这意味着一次路由后的查询最多可能会进行 **两次** Gemini
调用(路由 + 回答),如果触发了回退机制,则可能达到三次——请合理控制免费额度的使用频率。
这些领域与 `data/runbooks/` 下的子文件夹是一一对应的。`domain`
元数据由 `ingest.py` 写入(根据每个文件所在的子文件夹派生),并由检索器过滤器读取——因此,添加一个新领域只需要新建一个子文件夹并
重新导入(同时需要在 `router.py` 中的 `DOMAINS` 里将其添加进去)。
## 设置说明 (Windows)
### 第 1 步:克隆或创建项目文件夹
```
cd C:\Users\YourName\Documents
mkdir aiops-assistant
cd aiops-assistant
```
### 第 2 步:创建并激活虚拟环境
```
python -m venv venv
venv\Scripts\activate
```
### 第 3 步:安装依赖项
```
pip install -r requirements.txt
```
### 第 4 步:设置你的 API key
- 将 `.env.example` 复制为 `.env`
- 打开 `.env` 并将 `your_gemini_api_key_here` 替换为你的实际密钥
- 从以下地址获取你的 Gemini API key:https://aistudio.google.com/app/apikey
### 第 5 步:添加你的 runbook
- 将你的 `.txt` 或 `.pdf` runbook 文件放入 `data/runbooks//` 下
(每个领域对应一个子文件夹——子文件夹的名称即为路由的领域)
- 为了方便你快速入门,项目中已经包含了涵盖所有领域的示例 runbook
### 第 6 步:将文档导入向量数据库
```
python ingest.py
```
### 第 7 步:启动应用
```
streamlit run app.py
```
应用将在以下地址打开:http://localhost:8501
## 部署到 Streamlit Cloud
1. 将本项目推送到 GitHub 仓库(确保 `app.py` 位于仓库根目录)。
2. 在 [share.streamlit.io](https://share.streamlit.io) 上,创建一个指向
`app.py` 的应用。
3. 在 **Settings → Secrets** 下添加你的密钥(Streamlit 会将密钥作为
环境变量暴露出来,因此 `os.getenv("GOOGLE_API_KEY")` 可以正常工作):
GOOGLE_API_KEY = "your_key_here"
4. **发布向量数据库。** 本仓库有意 **提交了** 预先构建好的
`chroma_db/`,这样全新的部署从第一个请求开始就自带知识库。
如果你更改了 runbook,请在本地重新运行 `python ingest.py`,并提交更新后的
`chroma_db/`。(备选方案:在服务器启动时运行导入——
但这需要在运行时提供 API key,并且每次冷启动都会消耗 embedding 配额。)
## 项目结构
```
aiops-assistant/
├── app.py # Streamlit UI (router -> agent -> badge)
├── agents.py # Agent registry: ROUTER + 7 named agents
├── router.py # Classifies a query into a domain (Gemini)
├── rag_chain.py # RAG chain builder: get_agent_chain (domain-filtered)
├── ingest.py # Document ingestion pipeline (tags `domain`)
├── eval/ # Evaluation harness (see Evaluation Results)
│ ├── run_eval.py # python eval/run_eval.py
│ ├── test_queries.py # 20 labelled test queries
│ ├── results.json # per-query records from the last run
│ ├── summary.md # metrics summary from the last run
│ └── extensibility_test.md # new-domain (CI/CD) test report
├── docs/screenshots/ # annotated demo screenshots + capture guide
├── requirements.txt # Python dependencies
├── LICENSE # MIT license
├── CLAUDE.md # Guidance for Claude Code sessions
├── .env.example # API key template
├── .env # Your actual API key (do not commit)
├── .gitignore
├── data/
│ └── runbooks/ # One subfolder per domain
│ ├── kubernetes/
│ │ └── runbook_oom_kubernetes.txt
│ ├── database/
│ │ └── runbook_database.txt
│ ├── infrastructure/
│ │ ├── runbook_disk_space.txt
│ │ ├── runbook_high_cpu.txt
│ │ └── runbook_service_health.txt
│ ├── network/
│ │ ├── runbook_dns_failure.txt
│ │ └── runbook_high_latency.txt
│ ├── security/
│ │ ├── runbook_unauthorized_access.txt
│ │ └── runbook_ssl_cert_expiry.txt
│ └── cicd/
│ ├── runbook_failed_deployment.txt
│ ├── runbook_pipeline_stuck.txt
│ └── runbook_artifact_registry.txt
└── chroma_db/ # Prebuilt vector store (committed for Streamlit Cloud)
```
## 评估结果
本仓库包含一个可复现的评估工具(`python eval/run_eval.py`),它会驱动 **真实的生产路径** —— 路由器 → 专门的 agent →
领域过滤检索 → 回答(包括错误路由回退机制)——涵盖 20 个带标签的查询,覆盖所有六个专门的领域以及特意设计的
模糊/跨领域场景。它主要测量:
- **路由准确率** — 路由器是否选择了人类专家会选择的领域?
- **检索命中率** — 预期的 runbook 是否包含在检索到的来源中?
- **回退率** — 空检索的安全网触发的频率。
- **延迟** — 按阶段(路由 / 回答)和领域划分。
中期结果(评估正在进行中——该工具会根据 Gemini 免费层级每天 20 次请求的限制,在几天内控制调用频率,并使用
`--resume` 恢复进度;最终数据详见 [`eval/summary.md`](eval/summary.md)):
| 指标 | 结果(目前已完成 20 个查询中的 11 个) |
|---|---|
| 路由准确率 | **11/11 (100%)** — kubernetes、database、infrastructure、network 已完全覆盖 |
| 检索命中率 | **11/11 (100%)** — 预期的 runbook 始终包含在来源中 |
| 空检索回退 | 0(预期情况:每个领域都有 runbook) |
| 平均端到端延迟 | 10.46秒/查询(免费层级 API 往返时间) |
**可扩展性测试**([`eval/extensibility_test.md`](eval/extensibility_test.md)):
在 **不到 10 分钟** 的时间内添加了一个新的 **CI/CD** 专业领域(3 个 runbook),
只需修改数据和两个注册表条目(在 `router.py` 和
`agents.py` 中约 8 行代码)——对路由、检索或分发逻辑的改动为零。导入过程正确标记了全部 3 个文档,领域过滤检索排他性地返回了 `cicd` 块,并且所有三个探测查询都将正确的 runbook 作为首要来源。
## 用于测试的示例查询
- 如何解决 Kubernetes 中的 OOMKilled pod?
- 处理 Linux 服务器 CPU 高负载告警的步骤?
- 数据库连接池耗尽——该怎么办?
- 如何响应磁盘空间告警?
- 服务健康检查失败——有哪些故障排除步骤?
## 添加更多 Runbook
1. 将你的 `.txt` 或 `.pdf` 文件添加到 `data/runbooks/`
2. 重建向量数据库(参见下方的 **更新向量数据库 (ChromaDB)**)
3. 重启 Streamlit 应用
## 更新向量数据库 (ChromaDB)
`chroma_db/` 中的向量数据库是由 `ingest.py` 根据
`data/runbooks/` 中的文件构建的。每当你 **添加、编辑或删除** runbook 时,都需要重新构建它,以便应用程序能够感知到更改:
```
python ingest.py
```
`ingest.py` 会在重建之前自动删除任何现有的 `chroma_db/`,因此重新运行它永远不会导致文档重复。因为 `chroma_db/` 已被提交到代码库
(这样部署到 Streamlit Cloud 时就会自带预构建的知识库),请在重建后提交更新后的
数据库。如果删除操作失败并报出
“拒绝访问”错误,说明有程序正在占用该文件夹——请停止
Streamlit 应用(Ctrl+C),如果 OneDrive 正在同步该文件夹则暂停其同步,然后
重新运行。
成功重建后会打印出 `Loaded N document(s)` 和 `SUCCESS: N chunks
stored in ChromaDB`。请确认 `N` 与你预期的 runbook 数量是否一致。
### 何时必须重新构建
- 你在 `data/runbooks/` 中添加、编辑或删除了 runbook
- 你更改了 `rag_chain.py` 中的 `EMBEDDING_MODEL`(旧/新 embedding 是
不兼容的——过期的 `chroma_db/` 会导致错误的回答或维度错误)
- 应用程序提示 `Knowledge base not found`
重新构建后,**彻底重启 Streamlit**(按 Ctrl+C,然后执行 `streamlit run app.py`)。
领域链在进程内被缓存,而应用程序的 ⋮ 菜单 → Clear cache 并**不会**
重建它们——只有重启才能更新。
## 故障排除
| 症状 | 原因 | 解决方案 |
|---------|-------|-----|
| `GOOGLE_API_KEY is not set` | 没有 `.env` 文件或缺少密钥 | 将 `.env.example` 复制为 `.env` 并粘贴你的密钥 |
| `404 NOT_FOUND ... is not found for API version` | Gemini 模型名称已被弃用 | 更新 `rag_chain.py` 中的模型名称(参见上方的模型说明) |
| `429 RESOURCE_EXHAUSTED ... limit: 0` | 该模型仅限付费层级使用(例如 `gemini-2.5-pro`) | 切换到免费层级模型,如 `gemini-2.5-flash`,或启用计费功能 |
| `429 RESOURCE_EXHAUSTED ... retry in Ns` | 达到了免费层级的速率/每日限制 | 等待重试延迟结束;限制会随时间重置 |
| 在 `rag_chain.py` 中更改模型对正在运行的应用程序没有生效 | 链在进程内被缓存了(`lru_cache`) | 彻底重启应用程序(Ctrl+C,重新运行)。⋮ 菜单 → Clear cache **并不会** 重建它们 |
| `ModuleNotFoundError: No module named 'langchain...'` | 依赖项过期 | 重新运行 `pip install -r requirements.txt` |
| 回答似乎与你的 runbook 无关,或者查询时出现维度错误 | 向量数据库是使用不同的 embedding 模型构建的 | 删除 `chroma_db/` 文件夹并重新运行 `python ingest.py` |
| 应用程序中提示 `Knowledge base not found` | 从未运行过 `ingest.py` | 在启动应用程序之前运行 `python ingest.py` |
## 许可证
基于 [MIT License](LICENSE) 发布——可免费使用、修改和分发。
## 毕业项目
**作者:** Sarvesh Bedsur
提交给 [AI Agents: Intensive Vibe Coding Capstone Project](https://www.kaggle.com/competitions/vibecoding-agents-capstone-project/),
这是 **Google × Kaggle 5-Day AI Agents Intensive — Vibe Coding**
课程(2026 年 6 月)的毕业项目。本着该课程的精神,本项目是利用
AI 编程 agent (Claude Code) 进行“氛围编程”(vibe-coded) 完成的:多 agent 架构、导入
pipeline 以及部署修复,都是通过迭代式的 AI 结对工作构建的,其中 `CLAUDE.md` 作为该 agent 的持久化项目记忆库。
(router.classify_query · Gemini)"] R -->|kubernetes| K["☸️ Kubernetes Agent"] R -->|database| D["🗄️ Database Agent"] R -->|infrastructure| I["🖥️ Infrastructure Agent"] R -->|network| N["🌐 Network Agent"] R -->|security| S["🔒 Security Agent"] R -->|cicd| P["🚀 CI/CD Agent"] R -->|general / fallback| G["🧭 General Agent"] K & D & I & N & S & P & G --> C[("🗃️ ChromaDB
filtered by domain")] C --> A["💬 Answer + agent badge + sources"] ``` 每个专门的 agent 由 `get_agent_chain(
标签:AI, ChromaDB, Kubernetes, LangChain, Streamlit, 多智能体, 智能运维, 检索增强生成, 自动化代码审查, 访问控制, 轻量级, 逆向工具