Spaces:
Sleeping
Sleeping
File size: 10,095 Bytes
c6c243c 76d3616 c6c243c 76d3616 c6c243c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | # LogSentinel v2: Building a Multi-Agent SOC War-Room for RLVR Training
**Author:** Surya-sj
**HF Space:** [Surya-sj/logsentinel](https://huggingface.co/spaces/Surya-sj/logsentinel)
**Colab:** [Open Notebook](https://colab.research.google.com/drive/1N-We4n7g9vtH1A1Emtjndqpc8X0CH8zl)
---
## The Problem I Set Out to Solve
Modern incident response is not a single-agent, single-turn task. When a production system goes down at 3am, four people are on a call simultaneously:
- The **Incident Commander** coordinating the response
- The **App SRE** watching pod logs and nginx errors
- The **DB SRE** staring at replication lag and connection pool metrics
- The **Security Analyst** hunting for injection patterns and exfiltration signals
Each of them sees a *different slice* of reality. They have to talk to each other, negotiate severity, and act fast β without stepping on each other's toes.
Current LLM benchmarks test none of this. They ask a single agent to classify logs or answer MCQs. That's not incident response. That's a quiz.
I built **LogSentinel v2** to fix that.
---
## What I Built
LogSentinel v2 is an OpenEnv-compliant reinforcement learning environment that simulates a realistic SOC (Security Operations Center) war-room. It supports:
- **4 agent roles** with different log views
- **5-phase episode lifecycle** driven by actions, not step counts
- **Composable verifiable rewards** with 5 components and 4 anti-hacking penalties
- **Procedural scenario generation** with seeds for reproducibility
- **Adaptive curriculum** that adjusts difficulty based on rolling success rate
- **GRPO training pipeline** built on TRL + Unsloth
---
## Environment Design
### The 5-Phase Lifecycle
```
[DETECT] β [TRIAGE] β [MITIGATE] β [VERIFY] β [FINAL_REPORT]
```
Phase transitions are **action-driven**. The agent can't skip phases β it has to actually do the work of each phase before advancing. Detecting an incident transitions to triage. Executing a mitigation transitions to verify. This forces long-horizon reasoning.
### Partial Observability
Each role sees only the logs from sources relevant to their domain:
```
incident_commander β all sources (but gets fewer metrics)
app_sre β nginx, app-server-1, app-server-2, k8s
db_sre β postgres-primary, app-server-1
security_analyst β nginx, app-server-1, waf, audit-log
```
This means a DB SRE running a query about replication lag sees things the Security Analyst cannot β and vice versa. Agents must use **handoff actions** to share findings via a shared board that all roles can read.
### The Shared Board
When a DB SRE discovers replication lag, they write to the shared board:
```json
{
"action_type": "request_handoff",
"agent_role": "db_sre",
"handoff_to": "incident_commander",
"handoff_note": "Replication lag 15.2s on pg-replica-1. WAL 256MB behind. Recommend read failover."
}
```
Every agent sees this in their next observation. This is the coordination mechanism β explicit, structured, and gradeable.
---
## Reward Engineering
The reward formula is:
```
R_total = 0.40 Γ R_outcome
+ 0.20 Γ R_detection_f1
+ 0.15 Γ R_severity_accuracy
+ 0.10 Γ R_efficiency
+ 0.15 Γ R_teamwork
β penalties
```
Every component is logged in `state.reward_breakdown` so you can plot each one during training.
### Why this formula works for RLVR
Each component requires **real work** to earn:
- **R_outcome** only goes up when `service_health > 0.7` β which only happens after evidence-backed mitigations
- **R_detection_f1** uses precision + recall, so spamming all incident types tanks your precision
- **R_severity_accuracy** gives partial credit for near-misses (P2 when truth is P1 = 0.5, not 0)
- **R_efficiency** rewards finishing in fewer steps, so the agent learns to be decisive
- **R_teamwork** rewards useful handoffs with non-trivial notes β empty handoffs don't count
### Anti-Hacking Mechanisms
I spent a lot of time thinking about how an RL agent would try to game this environment. Here's what I found and how I stopped it:
| Attack | What the agent would do | How I stop it |
|--------|------------------------|---------------|
| Incident spam | Propose every incident type for max recall | F1 precision term collapses |
| Blind mitigation | Execute mitigations without looking at logs | Penalty + no world state change |
| Instant report | Submit report without detecting anything | `report_before_detection` penalty |
| Noop farming | Repeat `observe_logs` to burn steps safely | Noop counter β efficiency drop |
---
## Scenario Generation
Scenarios are procedurally generated from a `ScenarioConfig`:
```python
ScenarioConfig(
num_incidents=3,
difficulty=DifficultyLevel.HARD,
attack_subtlety=0.8, # attacker traffic looks like normal POSTs
observability_quality=0.7, # 30% of normal logs are dropped
confounding_noise_ratio=0.5,
seed=42, # fully reproducible
)
```
On **hard** difficulty, there are 3 simultaneous incidents:
1. A DB replication lag cascade causing nginx 502s
2. A memory leak causing OOMKills
3. A SQL injection + data exfiltration attack that initially looks like normal search traffic
The security incident is the hardest to catch β the first log from the attacker is a normal-looking `POST /api/search 200 OK`. You need to correlate the UNION SELECT pattern, the 4.2MB response anomaly, and the rate limit breach across multiple sources to identify it.
---
## Adaptive Curriculum
The `adaptive_curriculum` task adjusts difficulty automatically:
```
rolling_avg > 0.70 β promote to harder difficulty
rolling_avg < 0.35 β demote to easier difficulty
window = last 20 episodes
```
This means a model that's mastered easy single-incident scenarios gets automatically challenged with multi-incident hard scenarios β without any manual tuning.
---
## Training Pipeline
The GRPO training script uses TRL's `GRPOTrainer` with Unsloth for 4-bit quantization:
```python
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Qwen2.5-7B-Instruct-bnb-4bit",
max_seq_length=2048,
load_in_4bit=True,
)
```
The reward function passed to GRPO is the environment's own `grade_action` + episode-level `compute_episode_reward` β the same signal used during evaluation. This is what makes it RLVR: the reward is **verifiable** against ground truth, not a learned value function.
The Colab notebook walks through:
1. Installing deps
2. Running baseline (heuristic) evaluation
3. GRPO training
4. Post-training evaluation
5. Plotting baseline vs trained reward curves
---
## Results
### Baseline (Heuristic Agent)
The baseline agent uses simple rules: classify logs by level, propose incident based on keyword matching, assign severity heuristically.
```
Avg total reward: 0.45
Success rate: ~60%
Avg detection F1: 0.51
Avg severity accuracy: 0.72
Avg teamwork score: 0.00 β handoffs never used
```
The heuristic never uses handoffs (teamwork = 0) and never verifies recovery (efficiency suffers). It gets lucky on severity because the mapping is simple.
### Real LLM Benchmark Results
We benchmarked two Qwen3 models against the heuristic baseline β no fine-tuning, zero-shot:
| Metric | Heuristic Baseline | Qwen3-0.6B (local) | Qwen3-32B (Groq) |
|--------|-------------------|---------------------|------------------|
| Avg Total Reward | 0.41 | **0.49** | **0.49** |
| Efficiency Score | 0.00 | **0.81** | **0.81** |
| Avg Steps to Resolve | 45 | **8** | **8** |
| Success Rate | 66.7% | 66.7% | 66.7% |
The standout result: **efficiency**. The heuristic agent grinds through 45 steps because it follows a fixed sequence. Both Qwen3 models resolve incidents in 8 steps β they read the phase, output the right JSON action, and advance. The reward gap comes almost entirely from not wasting steps.
Teamwork score (handoffs) remains 0.0 for all zero-shot models β this is exactly the gap that GRPO training is designed to close. A trained agent learns that `request_handoff` actions earn `R_teamwork` reward, creating emergent coordination behaviour that no prompt engineering alone achieves.
---
## What I Learned
**1. Phase design matters more than reward weights.**
Early versions had step-count phase transitions. The agent learned to stall in easy phases. Switching to action-driven transitions immediately fixed this β the agent can only advance by doing the right thing.
**2. Anti-hacking is a first-class design concern.**
Every reward component I added, I immediately asked: how would an RL agent game this? The answer was almost always "spam the easiest action." Designing against that upfront saved a lot of debugging later.
**3. Partial observability creates emergent coordination pressure.**
When each role sees different logs, a single agent acting as all roles simultaneously has to explicitly decide what to share. This pressure is what makes handoffs meaningful rather than just a formality.
**4. Verifiable rewards are worth the engineering effort.**
Ground truth is pre-computed at scenario generation time. Grading is deterministic and fast (<1ms per step). This makes the training loop extremely tight compared to learned reward models.
---
## Try It
```bash
# Reset a hard SOC scenario
curl -X POST https://Surya-sj-logsentinel.hf.space/reset \
-H "Content-Type: application/json" \
-d '{"task_name": "soc_warroom_hard", "seed": 42}'
# See all tasks
curl https://Surya-sj-logsentinel.hf.space/tasks
# Full API docs
https://Surya-sj-logsentinel.hf.space/docs
```
Or open the [Colab notebook](https://colab.research.google.com/drive/1N-We4n7g9vtH1A1Emtjndqpc8X0CH8zl) and run the full baseline evaluation β no GPU needed for that part.
---
## Links
- **HF Space:** https://huggingface.co/spaces/Surya-sj/logsentinel
- **Colab Notebook:** https://colab.research.google.com/drive/1N-We4n7g9vtH1A1Emtjndqpc8X0CH8zl
- **API Docs:** https://Surya-sj-logsentinel.hf.space/docs
|