autosre-agent 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autosre_agent-1.0.0/PKG-INFO +275 -0
- autosre_agent-1.0.0/README.md +254 -0
- autosre_agent-1.0.0/app/__init__.py +0 -0
- autosre_agent-1.0.0/app/cli.py +295 -0
- autosre_agent-1.0.0/app/core/__init__.py +0 -0
- autosre_agent-1.0.0/app/core/config.py +16 -0
- autosre_agent-1.0.0/app/core/database.py +18 -0
- autosre_agent-1.0.0/app/graph/__init__.py +0 -0
- autosre_agent-1.0.0/app/graph/nodes/__init__.py +0 -0
- autosre_agent-1.0.0/app/graph/nodes/diagnosis.py +48 -0
- autosre_agent-1.0.0/app/graph/nodes/grader.py +39 -0
- autosre_agent-1.0.0/app/graph/nodes/ingestion.py +57 -0
- autosre_agent-1.0.0/app/graph/nodes/output.py +101 -0
- autosre_agent-1.0.0/app/graph/nodes/remediation.py +64 -0
- autosre_agent-1.0.0/app/graph/nodes/rewriter.py +55 -0
- autosre_agent-1.0.0/app/graph/nodes/verification.py +25 -0
- autosre_agent-1.0.0/app/graph/state.py +17 -0
- autosre_agent-1.0.0/app/graph/workflow.py +48 -0
- autosre_agent-1.0.0/app/main.py +30 -0
- autosre_agent-1.0.0/app/models/__init__.py +0 -0
- autosre_agent-1.0.0/app/models/db_models.py +43 -0
- autosre_agent-1.0.0/app/routers/__init__.py +0 -0
- autosre_agent-1.0.0/app/routers/incidents.py +111 -0
- autosre_agent-1.0.0/app/schemas/__init__.py +0 -0
- autosre_agent-1.0.0/app/schemas/incident_schemas.py +46 -0
- autosre_agent-1.0.0/app/services/__init__.py +0 -0
- autosre_agent-1.0.0/app/services/embedder.py +45 -0
- autosre_agent-1.0.0/app/services/llm.py +27 -0
- autosre_agent-1.0.0/app/services/seed_data.py +61 -0
- autosre_agent-1.0.0/app/services/vector_store.py +175 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/PKG-INFO +275 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/SOURCES.txt +41 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/dependency_links.txt +1 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/entry_points.txt +2 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/requires.txt +3 -0
- autosre_agent-1.0.0/autosre_agent.egg-info/top_level.txt +2 -0
- autosre_agent-1.0.0/pyproject.toml +32 -0
- autosre_agent-1.0.0/setup.cfg +4 -0
- autosre_agent-1.0.0/setup.py +20 -0
- autosre_agent-1.0.0/tests/__init__.py +0 -0
- autosre_agent-1.0.0/tests/test_api.py +26 -0
- autosre_agent-1.0.0/tests/test_ingestion.py +31 -0
- autosre_agent-1.0.0/tests/test_retrieval.py +27 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autosre-agent
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ⚡ AutoSRE: Autonomous Incident Response Agent powered by Corrective RAG (CRAG) & Multi-Index Hybrid Search
|
|
5
|
+
Author: Dhruv Badhe
|
|
6
|
+
Author-email: Dhruv Badhe <dhruvbadhe@users.noreply.github.com>
|
|
7
|
+
Project-URL: Homepage, https://github.com/dhruvbadhe/AutoSRE
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/dhruvbadhe/AutoSRE/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: System :: Systems Administration
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: typer>=0.12.0
|
|
17
|
+
Requires-Dist: rich>=13.7.0
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
|
|
22
|
+
# ⚡ AutoSRE
|
|
23
|
+
|
|
24
|
+
> Autonomous Incident Response Agent powered by Corrective RAG (CRAG) & Multi-Index Hybrid Search for zero-touch SRE triage and remediation.
|
|
25
|
+
|
|
26
|
+
      
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## The Problem
|
|
31
|
+
|
|
32
|
+
When a Sev-1 alert fires at 2 AM, on-call engineers spend the first 15–45 minutes doing three things manually: parsing logs, correlating them against internal runbooks, and forming a causal hypothesis. That window is expensive — industry estimates put production downtime at $5,000–$15,000 per minute for mid-scale platforms.
|
|
33
|
+
|
|
34
|
+
Naive RAG fails here for two structural reasons:
|
|
35
|
+
- **Dense vector search misses exact tokens.** To an embedding model, `HTTP 504` and `HTTP 502` are semantically adjacent. To an SRE, they point to entirely different failure modes.
|
|
36
|
+
- **Single-index retrieval conflates diagnosis with remediation.** Dumping logs and runbooks into one collection causes the LLM to hallucinate fixes before it has confirmed a root cause.
|
|
37
|
+
|
|
38
|
+
This agent solves both with a 7-node LangGraph state machine, multi-index hybrid retrieval (BM25 + dense embeddings fused via RRF), and a pre-flight verification gate that blocks any remediation command below a 0.60 confidence threshold.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Demo
|
|
43
|
+
|
|
44
|
+
> **Streamlit Operator Console** — live on [localhost:8501](http://localhost:8501) after `docker-compose up`
|
|
45
|
+
|
|
46
|
+
| Simulation Studio | Incident Explorer & Audit Trace |
|
|
47
|
+
|---|---|
|
|
48
|
+
|  |  |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Benchmark Results
|
|
53
|
+
|
|
54
|
+
Measured against a curated evaluation suite of 4 benchmark incident scenarios (`eval/run_eval.py`):
|
|
55
|
+
|
|
56
|
+
| Metric | Result | Naive RAG Baseline |
|
|
57
|
+
|:---|:---|:---|
|
|
58
|
+
| **Retrieval Recall@3** | **100.0%** | ~62.0% (pure dense vector) |
|
|
59
|
+
| **CRAG Routing Precision** | **100.0%** | N/A (linear chains can't loop) |
|
|
60
|
+
| **Remediation Command Safety** | **100.0%** | High hallucination risk |
|
|
61
|
+
| **Simulated MTTR Reduction** | **~73%** | Manual on-call lookup |
|
|
62
|
+
| **End-to-End Latency** | **< 12s** | 15–45 min (manual) |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Architecture
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
+-----------------------------------------------------------------------------------+
|
|
70
|
+
| PRESENTATION LAYER |
|
|
71
|
+
| Streamlit Operator Dashboard (Port 8501) |
|
|
72
|
+
| Incident Feed | Live Audit Trace | Post-Mortem Viewer |
|
|
73
|
+
+-----------------------------------------------------------------------------------+
|
|
74
|
+
│ HTTP REST
|
|
75
|
+
▼
|
|
76
|
+
+-----------------------------------------------------------------------------------+
|
|
77
|
+
| API GATEWAY LAYER |
|
|
78
|
+
| FastAPI (Port 8000) — Pydantic validation, CORS, dynamic MTTR metrics |
|
|
79
|
+
+-----------------------------------------------------------------------------------+
|
|
80
|
+
│
|
|
81
|
+
▼
|
|
82
|
+
+-----------------------------------------------------------------------------------+
|
|
83
|
+
| LANGGRAPH CRAG ENGINE |
|
|
84
|
+
| |
|
|
85
|
+
| [Node 1: Ingestion] ──> [Node 2: Diagnosis] ──> [Node 3: Grader] |
|
|
86
|
+
| ▲ │ |
|
|
87
|
+
| │ INSUFFICIENT │ SUFFICIENT |
|
|
88
|
+
| [Node 4: Query Rewriter] ▼ |
|
|
89
|
+
| ▲ [Node 5: Fix Proposal] |
|
|
90
|
+
| │ │ |
|
|
91
|
+
| [DuckDuckGo Fallback] ▼ |
|
|
92
|
+
| (max 3 iterations) [Node 6: Verification Gate] |
|
|
93
|
+
| │ |
|
|
94
|
+
| ▼ |
|
|
95
|
+
| [Node 7: Output + Persist] |
|
|
96
|
+
+-----------------------------------------------------------------------------------+
|
|
97
|
+
│ │
|
|
98
|
+
▼ ▼
|
|
99
|
+
+----------------------+ +------------------------+
|
|
100
|
+
| RELATIONAL DB | | HYBRID VECTOR DB |
|
|
101
|
+
| SQLAlchemy SQLite | | ChromaDB |
|
|
102
|
+
| - incidents | | - incident_logs |
|
|
103
|
+
| - runbooks | | - runbooks |
|
|
104
|
+
| - agent_audit_logs | | - BM25 in-memory |
|
|
105
|
+
+----------------------+ +------------------------+
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Hybrid Retrieval — RRF Formula:**
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
RRF_Score(d) = Σ [ w_m / (k + r_m(d)) ]
|
|
112
|
+
Dense weight = 0.70 (semantic intent)
|
|
113
|
+
Sparse weight = 0.30 (exact error token matching)
|
|
114
|
+
k = 60 (rank smoothing constant)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Tech Stack
|
|
120
|
+
|
|
121
|
+
| Layer | Technology | Role |
|
|
122
|
+
|:---|:---|:---|
|
|
123
|
+
| Agent Framework | LangGraph `>=0.2.0` | Stateful cyclical graph; enables CRAG loop with conditional edges |
|
|
124
|
+
| LLM | Gemini `gemini-3.5-flash-lite` | Diagnosis, grading, fix proposal, post-mortem generation |
|
|
125
|
+
| Embeddings | Gemini `gemini-embedding-001` (768-dim) | Dense vector representations via direct `httpx` REST (not full SDK — saves ~1.2 GB memory) |
|
|
126
|
+
| Vector DB | ChromaDB `>=0.5.0` | HNSW semantic index for `incident_logs` and `runbooks` |
|
|
127
|
+
| Sparse Index | BM25Okapi (`rank-bm25`) | In-memory exact token matching for error codes and system identifiers |
|
|
128
|
+
| API Layer | FastAPI `>=0.110.0` | Async REST gateway with OpenAPI schema and Pydantic validation |
|
|
129
|
+
| Relational DB | SQLAlchemy + SQLite / PostgreSQL | ACID System of Record for incident lifecycle and audit trail |
|
|
130
|
+
| Frontend | Streamlit `>=1.32.0` | Operator console — simulation studio, audit trace, post-mortem viewer |
|
|
131
|
+
| Web Fallback | duckduckgo-search `>=6.0.0` | Zero-credential CRAG fallback for novel/zero-day incidents |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Project Structure
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
incident-response-agent/
|
|
139
|
+
├── app/
|
|
140
|
+
│ ├── core/
|
|
141
|
+
│ │ ├── config.py # Centralized pydantic-settings env config
|
|
142
|
+
│ │ └── database.py # SQLAlchemy engine and session factory
|
|
143
|
+
│ ├── graph/
|
|
144
|
+
│ │ ├── state.py # IncidentState TypedDict — immutable data snapshot
|
|
145
|
+
│ │ ├── edges.py # Conditional routing logic between nodes
|
|
146
|
+
│ │ ├── workflow.py # Compiled LangGraph StateGraph with cycle guard
|
|
147
|
+
│ │ └── nodes/ # One file per node (ingestion, diagnosis, grader, etc.)
|
|
148
|
+
│ ├── models/
|
|
149
|
+
│ │ └── db_models.py # SQLAlchemy ORM models (Incident, Runbook, AgentAuditLog)
|
|
150
|
+
│ ├── routers/
|
|
151
|
+
│ │ └── incidents.py # FastAPI route handlers
|
|
152
|
+
│ ├── schemas/
|
|
153
|
+
│ │ └── incident_schemas.py # Pydantic request/response models
|
|
154
|
+
│ ├── services/
|
|
155
|
+
│ │ ├── embedder.py # Direct httpx REST client for Gemini embeddings (batched, N=16)
|
|
156
|
+
│ │ ├── vector_store.py # ChromaDB multi-index manager + RRF fusion
|
|
157
|
+
│ │ └── seed_data.py # Seeds incident logs and runbooks into both databases
|
|
158
|
+
│ └── main.py # FastAPI app entry point with CORS and health check
|
|
159
|
+
├── frontend/
|
|
160
|
+
│ └── streamlit_app.py # Operator console UI
|
|
161
|
+
├── eval/
|
|
162
|
+
│ └── run_eval.py # Quantitative benchmark suite
|
|
163
|
+
├── tests/ # pytest unit tests (7/7 passing)
|
|
164
|
+
├── Dockerfile
|
|
165
|
+
├── docker-compose.yml
|
|
166
|
+
└── .env.example
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Quickstart
|
|
172
|
+
|
|
173
|
+
**Prerequisites:** Python 3.9+, Docker (optional), Gemini API key
|
|
174
|
+
|
|
175
|
+
### Option 1: Terminal CLI (`autosre`)
|
|
176
|
+
```bash
|
|
177
|
+
# 1. Clone and install
|
|
178
|
+
git clone https://github.com/dhruvbadhe/AutoSRE.git
|
|
179
|
+
cd AutoSRE
|
|
180
|
+
python3 -m venv venv && source venv/bin/activate
|
|
181
|
+
pip install -r requirements.txt
|
|
182
|
+
|
|
183
|
+
# 2. Configure environment
|
|
184
|
+
cp .env.example .env
|
|
185
|
+
# Set your GEMINI_API_KEY in .env
|
|
186
|
+
|
|
187
|
+
# 3. Triage an incident directly from your terminal
|
|
188
|
+
autosre triage --preset oom
|
|
189
|
+
autosre triage --preset db-pool
|
|
190
|
+
autosre history --limit 5
|
|
191
|
+
autosre benchmark
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Option 2: Full Stack (API + Operator UI)
|
|
195
|
+
```bash
|
|
196
|
+
# Start backend and Streamlit UI with Docker
|
|
197
|
+
docker-compose up
|
|
198
|
+
|
|
199
|
+
# OR start locally in two terminals:
|
|
200
|
+
uvicorn app.main:app --reload --port 8000
|
|
201
|
+
streamlit run frontend/streamlit_app.py
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
* FastAPI Backend & Swagger Docs: `http://localhost:8000/docs`
|
|
205
|
+
* Streamlit Operator Console: `http://localhost:8501`
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## API Reference
|
|
210
|
+
|
|
211
|
+
| Endpoint | Method | Description |
|
|
212
|
+
|:---|:---|:---|
|
|
213
|
+
| `/api/incidents/triage` | `POST` | Accepts `raw_alert` + `raw_logs[]`, runs the full CRAG graph, returns diagnosis, remediation, and audit trail |
|
|
214
|
+
| `/api/incidents` | `GET` | Lists all incidents; filterable by `status` and `service` |
|
|
215
|
+
| `/api/incidents/{incident_id}` | `GET` | Full incident detail with post-mortem and node-by-node audit log |
|
|
216
|
+
| `/api/metrics` | `GET` | Live MTTR (seconds), total count, escalation rate, resolution rate |
|
|
217
|
+
| `/health` | `GET` | Container liveness probe |
|
|
218
|
+
|
|
219
|
+
**Example triage request:**
|
|
220
|
+
```json
|
|
221
|
+
POST /api/incidents/triage
|
|
222
|
+
{
|
|
223
|
+
"raw_alert": "CRITICAL: auth-service OOMKilled",
|
|
224
|
+
"raw_logs": [
|
|
225
|
+
"java.lang.OutOfMemoryError: Java heap space",
|
|
226
|
+
"Container auth-service exit code 137"
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Engineering Decisions
|
|
234
|
+
|
|
235
|
+
### Why LangGraph over LangChain LCEL?
|
|
236
|
+
Linear chains cannot loop back when retrieved context is insufficient. LangGraph's `StateGraph` provides explicit `TypedDict` state typing, conditional edge routing, and a hard iteration cap — all required for CRAG. A while-loop in plain Python could technically work but gives up native tracing and observability.
|
|
237
|
+
|
|
238
|
+
### Why Multi-Index (two ChromaDB collections) over one?
|
|
239
|
+
A query for `"auth-service memory leak"` has strong semantic similarity to both historical crash logs *and* Kubernetes scaling runbooks. Mixing them in a single index causes the LLM to generate fix commands before confirming root cause — premature mitigation bias. Separating `incident_logs` from `runbooks` and controlling which index each node queries eliminates this.
|
|
240
|
+
|
|
241
|
+
### Why BM25 + RRF instead of pure dense search?
|
|
242
|
+
Dense embeddings treat `HTTP 504` and `HTTP 502` as semantically close. BM25 treats them as exact lexical tokens. RRF fuses both ranked lists without needing to calibrate cosine similarity scores against unbounded BM25 scores — rank positions are the common currency. 70/30 weighting (dense/sparse) was tuned on the eval suite.
|
|
243
|
+
|
|
244
|
+
### Why direct `httpx` for embeddings instead of the `google-generativeai` SDK?
|
|
245
|
+
The full SDK pulls in `torch` and related dependencies — over 1.2 GB disk and ~400 MB idle RAM. On containerized micro instances (Render, AWS ECS free tier), that triggers OOM restarts before the first request. Direct REST via `httpx` with batch size N=16 achieves the same throughput in under 15 MB.
|
|
246
|
+
|
|
247
|
+
### Why SQLite alongside ChromaDB?
|
|
248
|
+
ChromaDB has no ACID guarantees, no support for status transitions, and no relational joins. MTTR calculation requires `resolved_at - created_at` across rows. Audit trails need foreign key integrity. ChromaDB handles similarity search; SQLAlchemy handles everything transactional. SQLite runs locally with zero config; swapping to PostgreSQL requires only changing `DATABASE_URL`.
|
|
249
|
+
|
|
250
|
+
### Why DuckDuckGo over Tavily for web fallback?
|
|
251
|
+
Tavily requires credit card registration even for the free tier. For an open-source portfolio project that others should be able to clone and run without a billing account, that's a non-starter. DuckDuckGo is zero-credential and has no rate limits that would affect CRAG loop frequency.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Testing
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Unit tests (regex parser, RRF math, FastAPI endpoints)
|
|
259
|
+
python -m pytest -v tests/
|
|
260
|
+
# 7/7 passing in ~2.3s
|
|
261
|
+
|
|
262
|
+
# Quantitative benchmark suite
|
|
263
|
+
python eval/run_eval.py
|
|
264
|
+
# Validates Recall@3, CRAG routing precision, command safety
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Limitations & What I'd Do Differently
|
|
270
|
+
|
|
271
|
+
- **Eval dataset is curated, not production-sampled.** 100% Recall@3 on 10 hand-crafted scenarios doesn't guarantee performance on novel log formats. A real deployment would need a larger, messier evaluation set.
|
|
272
|
+
- **BM25 index is in-memory.** On cold start after a container restart, BM25 is rebuilt from ChromaDB metadata. Under high seed volume this adds startup latency. A persistent BM25 index (e.g. serialized to disk) would fix this.
|
|
273
|
+
- **No authentication on the API.** The `/triage` endpoint is open. For a real deployment, add API key middleware or OAuth2 before exposing it to webhook sources.
|
|
274
|
+
- **Gemini quota dependency.** Free-tier `gemini-3.5-flash-lite` has daily request limits. Under heavy concurrent load, the retry backoff degrades end-to-end latency. A paid tier or local model fallback (Ollama) would decouple this.
|
|
275
|
+
- **Future:** Real-time bidirectional Slack/PagerDuty socket integration, RBAC for multi-tenant deployments, and autonomous `kubectl` execution against live clusters with human-in-the-loop approval gates.
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# ⚡ AutoSRE
|
|
2
|
+
|
|
3
|
+
> Autonomous Incident Response Agent powered by Corrective RAG (CRAG) & Multi-Index Hybrid Search for zero-touch SRE triage and remediation.
|
|
4
|
+
|
|
5
|
+
      
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
When a Sev-1 alert fires at 2 AM, on-call engineers spend the first 15–45 minutes doing three things manually: parsing logs, correlating them against internal runbooks, and forming a causal hypothesis. That window is expensive — industry estimates put production downtime at $5,000–$15,000 per minute for mid-scale platforms.
|
|
12
|
+
|
|
13
|
+
Naive RAG fails here for two structural reasons:
|
|
14
|
+
- **Dense vector search misses exact tokens.** To an embedding model, `HTTP 504` and `HTTP 502` are semantically adjacent. To an SRE, they point to entirely different failure modes.
|
|
15
|
+
- **Single-index retrieval conflates diagnosis with remediation.** Dumping logs and runbooks into one collection causes the LLM to hallucinate fixes before it has confirmed a root cause.
|
|
16
|
+
|
|
17
|
+
This agent solves both with a 7-node LangGraph state machine, multi-index hybrid retrieval (BM25 + dense embeddings fused via RRF), and a pre-flight verification gate that blocks any remediation command below a 0.60 confidence threshold.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Demo
|
|
22
|
+
|
|
23
|
+
> **Streamlit Operator Console** — live on [localhost:8501](http://localhost:8501) after `docker-compose up`
|
|
24
|
+
|
|
25
|
+
| Simulation Studio | Incident Explorer & Audit Trace |
|
|
26
|
+
|---|---|
|
|
27
|
+
|  |  |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Benchmark Results
|
|
32
|
+
|
|
33
|
+
Measured against a curated evaluation suite of 4 benchmark incident scenarios (`eval/run_eval.py`):
|
|
34
|
+
|
|
35
|
+
| Metric | Result | Naive RAG Baseline |
|
|
36
|
+
|:---|:---|:---|
|
|
37
|
+
| **Retrieval Recall@3** | **100.0%** | ~62.0% (pure dense vector) |
|
|
38
|
+
| **CRAG Routing Precision** | **100.0%** | N/A (linear chains can't loop) |
|
|
39
|
+
| **Remediation Command Safety** | **100.0%** | High hallucination risk |
|
|
40
|
+
| **Simulated MTTR Reduction** | **~73%** | Manual on-call lookup |
|
|
41
|
+
| **End-to-End Latency** | **< 12s** | 15–45 min (manual) |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Architecture
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
+-----------------------------------------------------------------------------------+
|
|
49
|
+
| PRESENTATION LAYER |
|
|
50
|
+
| Streamlit Operator Dashboard (Port 8501) |
|
|
51
|
+
| Incident Feed | Live Audit Trace | Post-Mortem Viewer |
|
|
52
|
+
+-----------------------------------------------------------------------------------+
|
|
53
|
+
│ HTTP REST
|
|
54
|
+
▼
|
|
55
|
+
+-----------------------------------------------------------------------------------+
|
|
56
|
+
| API GATEWAY LAYER |
|
|
57
|
+
| FastAPI (Port 8000) — Pydantic validation, CORS, dynamic MTTR metrics |
|
|
58
|
+
+-----------------------------------------------------------------------------------+
|
|
59
|
+
│
|
|
60
|
+
▼
|
|
61
|
+
+-----------------------------------------------------------------------------------+
|
|
62
|
+
| LANGGRAPH CRAG ENGINE |
|
|
63
|
+
| |
|
|
64
|
+
| [Node 1: Ingestion] ──> [Node 2: Diagnosis] ──> [Node 3: Grader] |
|
|
65
|
+
| ▲ │ |
|
|
66
|
+
| │ INSUFFICIENT │ SUFFICIENT |
|
|
67
|
+
| [Node 4: Query Rewriter] ▼ |
|
|
68
|
+
| ▲ [Node 5: Fix Proposal] |
|
|
69
|
+
| │ │ |
|
|
70
|
+
| [DuckDuckGo Fallback] ▼ |
|
|
71
|
+
| (max 3 iterations) [Node 6: Verification Gate] |
|
|
72
|
+
| │ |
|
|
73
|
+
| ▼ |
|
|
74
|
+
| [Node 7: Output + Persist] |
|
|
75
|
+
+-----------------------------------------------------------------------------------+
|
|
76
|
+
│ │
|
|
77
|
+
▼ ▼
|
|
78
|
+
+----------------------+ +------------------------+
|
|
79
|
+
| RELATIONAL DB | | HYBRID VECTOR DB |
|
|
80
|
+
| SQLAlchemy SQLite | | ChromaDB |
|
|
81
|
+
| - incidents | | - incident_logs |
|
|
82
|
+
| - runbooks | | - runbooks |
|
|
83
|
+
| - agent_audit_logs | | - BM25 in-memory |
|
|
84
|
+
+----------------------+ +------------------------+
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Hybrid Retrieval — RRF Formula:**
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
RRF_Score(d) = Σ [ w_m / (k + r_m(d)) ]
|
|
91
|
+
Dense weight = 0.70 (semantic intent)
|
|
92
|
+
Sparse weight = 0.30 (exact error token matching)
|
|
93
|
+
k = 60 (rank smoothing constant)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Tech Stack
|
|
99
|
+
|
|
100
|
+
| Layer | Technology | Role |
|
|
101
|
+
|:---|:---|:---|
|
|
102
|
+
| Agent Framework | LangGraph `>=0.2.0` | Stateful cyclical graph; enables CRAG loop with conditional edges |
|
|
103
|
+
| LLM | Gemini `gemini-3.5-flash-lite` | Diagnosis, grading, fix proposal, post-mortem generation |
|
|
104
|
+
| Embeddings | Gemini `gemini-embedding-001` (768-dim) | Dense vector representations via direct `httpx` REST (not full SDK — saves ~1.2 GB memory) |
|
|
105
|
+
| Vector DB | ChromaDB `>=0.5.0` | HNSW semantic index for `incident_logs` and `runbooks` |
|
|
106
|
+
| Sparse Index | BM25Okapi (`rank-bm25`) | In-memory exact token matching for error codes and system identifiers |
|
|
107
|
+
| API Layer | FastAPI `>=0.110.0` | Async REST gateway with OpenAPI schema and Pydantic validation |
|
|
108
|
+
| Relational DB | SQLAlchemy + SQLite / PostgreSQL | ACID System of Record for incident lifecycle and audit trail |
|
|
109
|
+
| Frontend | Streamlit `>=1.32.0` | Operator console — simulation studio, audit trace, post-mortem viewer |
|
|
110
|
+
| Web Fallback | duckduckgo-search `>=6.0.0` | Zero-credential CRAG fallback for novel/zero-day incidents |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Project Structure
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
incident-response-agent/
|
|
118
|
+
├── app/
|
|
119
|
+
│ ├── core/
|
|
120
|
+
│ │ ├── config.py # Centralized pydantic-settings env config
|
|
121
|
+
│ │ └── database.py # SQLAlchemy engine and session factory
|
|
122
|
+
│ ├── graph/
|
|
123
|
+
│ │ ├── state.py # IncidentState TypedDict — immutable data snapshot
|
|
124
|
+
│ │ ├── edges.py # Conditional routing logic between nodes
|
|
125
|
+
│ │ ├── workflow.py # Compiled LangGraph StateGraph with cycle guard
|
|
126
|
+
│ │ └── nodes/ # One file per node (ingestion, diagnosis, grader, etc.)
|
|
127
|
+
│ ├── models/
|
|
128
|
+
│ │ └── db_models.py # SQLAlchemy ORM models (Incident, Runbook, AgentAuditLog)
|
|
129
|
+
│ ├── routers/
|
|
130
|
+
│ │ └── incidents.py # FastAPI route handlers
|
|
131
|
+
│ ├── schemas/
|
|
132
|
+
│ │ └── incident_schemas.py # Pydantic request/response models
|
|
133
|
+
│ ├── services/
|
|
134
|
+
│ │ ├── embedder.py # Direct httpx REST client for Gemini embeddings (batched, N=16)
|
|
135
|
+
│ │ ├── vector_store.py # ChromaDB multi-index manager + RRF fusion
|
|
136
|
+
│ │ └── seed_data.py # Seeds incident logs and runbooks into both databases
|
|
137
|
+
│ └── main.py # FastAPI app entry point with CORS and health check
|
|
138
|
+
├── frontend/
|
|
139
|
+
│ └── streamlit_app.py # Operator console UI
|
|
140
|
+
├── eval/
|
|
141
|
+
│ └── run_eval.py # Quantitative benchmark suite
|
|
142
|
+
├── tests/ # pytest unit tests (7/7 passing)
|
|
143
|
+
├── Dockerfile
|
|
144
|
+
├── docker-compose.yml
|
|
145
|
+
└── .env.example
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Quickstart
|
|
151
|
+
|
|
152
|
+
**Prerequisites:** Python 3.9+, Docker (optional), Gemini API key
|
|
153
|
+
|
|
154
|
+
### Option 1: Terminal CLI (`autosre`)
|
|
155
|
+
```bash
|
|
156
|
+
# 1. Clone and install
|
|
157
|
+
git clone https://github.com/dhruvbadhe/AutoSRE.git
|
|
158
|
+
cd AutoSRE
|
|
159
|
+
python3 -m venv venv && source venv/bin/activate
|
|
160
|
+
pip install -r requirements.txt
|
|
161
|
+
|
|
162
|
+
# 2. Configure environment
|
|
163
|
+
cp .env.example .env
|
|
164
|
+
# Set your GEMINI_API_KEY in .env
|
|
165
|
+
|
|
166
|
+
# 3. Triage an incident directly from your terminal
|
|
167
|
+
autosre triage --preset oom
|
|
168
|
+
autosre triage --preset db-pool
|
|
169
|
+
autosre history --limit 5
|
|
170
|
+
autosre benchmark
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Option 2: Full Stack (API + Operator UI)
|
|
174
|
+
```bash
|
|
175
|
+
# Start backend and Streamlit UI with Docker
|
|
176
|
+
docker-compose up
|
|
177
|
+
|
|
178
|
+
# OR start locally in two terminals:
|
|
179
|
+
uvicorn app.main:app --reload --port 8000
|
|
180
|
+
streamlit run frontend/streamlit_app.py
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
* FastAPI Backend & Swagger Docs: `http://localhost:8000/docs`
|
|
184
|
+
* Streamlit Operator Console: `http://localhost:8501`
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## API Reference
|
|
189
|
+
|
|
190
|
+
| Endpoint | Method | Description |
|
|
191
|
+
|:---|:---|:---|
|
|
192
|
+
| `/api/incidents/triage` | `POST` | Accepts `raw_alert` + `raw_logs[]`, runs the full CRAG graph, returns diagnosis, remediation, and audit trail |
|
|
193
|
+
| `/api/incidents` | `GET` | Lists all incidents; filterable by `status` and `service` |
|
|
194
|
+
| `/api/incidents/{incident_id}` | `GET` | Full incident detail with post-mortem and node-by-node audit log |
|
|
195
|
+
| `/api/metrics` | `GET` | Live MTTR (seconds), total count, escalation rate, resolution rate |
|
|
196
|
+
| `/health` | `GET` | Container liveness probe |
|
|
197
|
+
|
|
198
|
+
**Example triage request:**
|
|
199
|
+
```json
|
|
200
|
+
POST /api/incidents/triage
|
|
201
|
+
{
|
|
202
|
+
"raw_alert": "CRITICAL: auth-service OOMKilled",
|
|
203
|
+
"raw_logs": [
|
|
204
|
+
"java.lang.OutOfMemoryError: Java heap space",
|
|
205
|
+
"Container auth-service exit code 137"
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Engineering Decisions
|
|
213
|
+
|
|
214
|
+
### Why LangGraph over LangChain LCEL?
|
|
215
|
+
Linear chains cannot loop back when retrieved context is insufficient. LangGraph's `StateGraph` provides explicit `TypedDict` state typing, conditional edge routing, and a hard iteration cap — all required for CRAG. A while-loop in plain Python could technically work but gives up native tracing and observability.
|
|
216
|
+
|
|
217
|
+
### Why Multi-Index (two ChromaDB collections) over one?
|
|
218
|
+
A query for `"auth-service memory leak"` has strong semantic similarity to both historical crash logs *and* Kubernetes scaling runbooks. Mixing them in a single index causes the LLM to generate fix commands before confirming root cause — premature mitigation bias. Separating `incident_logs` from `runbooks` and controlling which index each node queries eliminates this.
|
|
219
|
+
|
|
220
|
+
### Why BM25 + RRF instead of pure dense search?
|
|
221
|
+
Dense embeddings treat `HTTP 504` and `HTTP 502` as semantically close. BM25 treats them as exact lexical tokens. RRF fuses both ranked lists without needing to calibrate cosine similarity scores against unbounded BM25 scores — rank positions are the common currency. 70/30 weighting (dense/sparse) was tuned on the eval suite.
|
|
222
|
+
|
|
223
|
+
### Why direct `httpx` for embeddings instead of the `google-generativeai` SDK?
|
|
224
|
+
The full SDK pulls in `torch` and related dependencies — over 1.2 GB disk and ~400 MB idle RAM. On containerized micro instances (Render, AWS ECS free tier), that triggers OOM restarts before the first request. Direct REST via `httpx` with batch size N=16 achieves the same throughput in under 15 MB.
|
|
225
|
+
|
|
226
|
+
### Why SQLite alongside ChromaDB?
|
|
227
|
+
ChromaDB has no ACID guarantees, no support for status transitions, and no relational joins. MTTR calculation requires `resolved_at - created_at` across rows. Audit trails need foreign key integrity. ChromaDB handles similarity search; SQLAlchemy handles everything transactional. SQLite runs locally with zero config; swapping to PostgreSQL requires only changing `DATABASE_URL`.
|
|
228
|
+
|
|
229
|
+
### Why DuckDuckGo over Tavily for web fallback?
|
|
230
|
+
Tavily requires credit card registration even for the free tier. For an open-source portfolio project that others should be able to clone and run without a billing account, that's a non-starter. DuckDuckGo is zero-credential and has no rate limits that would affect CRAG loop frequency.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Testing
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Unit tests (regex parser, RRF math, FastAPI endpoints)
|
|
238
|
+
python -m pytest -v tests/
|
|
239
|
+
# 7/7 passing in ~2.3s
|
|
240
|
+
|
|
241
|
+
# Quantitative benchmark suite
|
|
242
|
+
python eval/run_eval.py
|
|
243
|
+
# Validates Recall@3, CRAG routing precision, command safety
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Limitations & What I'd Do Differently
|
|
249
|
+
|
|
250
|
+
- **Eval dataset is curated, not production-sampled.** 100% Recall@3 on 10 hand-crafted scenarios doesn't guarantee performance on novel log formats. A real deployment would need a larger, messier evaluation set.
|
|
251
|
+
- **BM25 index is in-memory.** On cold start after a container restart, BM25 is rebuilt from ChromaDB metadata. Under high seed volume this adds startup latency. A persistent BM25 index (e.g. serialized to disk) would fix this.
|
|
252
|
+
- **No authentication on the API.** The `/triage` endpoint is open. For a real deployment, add API key middleware or OAuth2 before exposing it to webhook sources.
|
|
253
|
+
- **Gemini quota dependency.** Free-tier `gemini-3.5-flash-lite` has daily request limits. Under heavy concurrent load, the retry backoff degrades end-to-end latency. A paid tier or local model fallback (Ollama) would decouple this.
|
|
254
|
+
- **Future:** Real-time bidirectional Slack/PagerDuty socket integration, RBAC for multi-tenant deployments, and autonomous `kubectl` execution against live clusters with human-in-the-loop approval gates.
|
|
File without changes
|