Skip to content

ML Classifier

The ML Classifier assigns priority P1–P4 to each event using a RoBERTa model with a three-tier cache (PostgreSQL → in-memory dict → Redis) and a rule-based fallback.


Priority System

Priority Severity Color SLA Meaning
P1 CRITICAL 🔴 Red Immediate Production down, data loss, security breach
P2 ERROR 🟠 Orange 1 hour Service degraded, failed jobs, high error rate
P3 WARNING/INFO 🟡 Yellow 4 hours Performance degradation, non-critical issues
P4 DEBUG 🟢 Green Next day Debug traces, verbose logs

Classification Flow

flowchart TD
  EV[Enriched Event] --> TID{template_id?}
  TID -->|No| FALLBACK[Rule Fallback]
  TID -->|Yes| CACHE1[PostgreSQL<br/>template_priority]
  CACHE1 -->|Hit| USE_CACHED[Use Cached Priority]
  CACHE1 -->|Miss| CACHE2[In-Memory Dict]
  CACHE2 -->|Hit| USE_CACHED
  CACHE2 -->|Miss| CACHE3[Redis]
  CACHE3 -->|Hit| USE_CACHED
  CACHE3 -->|Miss| ROBERTA[RoBERTa Inference]
  ROBERTA -->|Confidence ≥ 0.8| STORE[Store in All Caches]
  ROBERTA -->|Confidence < 0.8| FALLBACK
  FALLBACK --> RULE[Severity→Priority Rule]
  USE_CACHED --> OUTPUT[Event with Priority]
  STORE --> OUTPUT
  RULE --> OUTPUT

RoBERTa Model

Property Value
Architecture RobertaForSequenceClassification
Base roberta-base (125M params)
Classes 4 (P1, P2, P3, P4)
Max Length 512 tokens
Input template_text (Drain3 template)
Output Priority + Confidence (0–1)
Model Path /app/model/log_priority_roberta
Version roberta_v1.1 (folder name)

Service: Separate FastAPI service on port 8001 (ml-service) - GET /health — model loaded status - POST /predict — {text: str} → {priority, confidence}


Inference Pipeline

# ml_classifier.py
class MLClassifier:
    def __init__(self):
        self.model = None
        self.tokenizer = None
        self._model_path = "/app/model/log_priority_roberta"

    def load(self):
        self.tokenizer = AutoTokenizer.from_pretrained(self._model_path)
        self.model = AutoModelForSequenceClassification.from_pretrained(
            self._model_path, device_map="cpu"
        )

    def predict(self, template_text: str) -> dict | None:
        if not self.is_loaded:
            return None

        inputs = self.tokenizer(
            template_text, truncation=True, max_length=512,
            return_tensors="pt"
        )
        with torch.no_grad():
            logits = self.model(**inputs).logits
            probs = torch.softmax(logits, dim=-1)
            conf, pred = torch.max(probs, dim=-1)

        priority = ["P1", "P2", "P3", "P4"][pred.item()]
        confidence = conf.item()

        if confidence >= 0.80:
            return {"priority": priority, "confidence": confidence}
        return None  # Trigger fallback

Rule Fallback

When model unavailable or confidence < 0.80:

SEVERITY_TO_PRIORITY = {
    "CRITICAL": {"priority": "P1", "confidence": 0.95},
    "ERROR":    {"priority": "P2", "confidence": 0.85},
    "WARNING":  {"priority": "P3", "confidence": 0.75},
    "INFO":     {"priority": "P3", "confidence": 0.70},
    "DEBUG":    {"priority": "P4", "confidence": 0.90},
}

Deterministic, no ML dependency.


Cache Tiers

Tier Store Lookup Write TTL
L1 PostgreSQL template_priority Startup load_from_postgres() set() → INSERT Persistent
L2 In-process dict get(template_id) set() → dict Process lifetime
L3 Redis ml:priority:{template_id} get() setex() 24h

Cache Key: ml:priority:{template_id}

{
  "priority": "P2",
  "confidence": 0.87,
  "model_version": "roberta_v1.1"
}

Event Output Fields

Field Source Example
priority ML / Cache / Rule P2
priority_confidence Model confidence 0.87
priority_source ml | cache | rule ml
model_version Model folder name roberta_v1.1

Configuration

Env Var Default Description
ML_MIN_CONFIDENCE 0.80 Min confidence to cache/use ML result
ML_MODEL_PATH /app/model/log_priority_roberta Model weights directory
ML_SERVICE_URL http://ml-service:8001 For remote inference (unused, local)

Metrics (Logged per Batch)

Counter Meaning
ml_cache_hits_total Served from any cache tier
ml_predictions_total RoBERTa inference executed
ml_fallback_total Rule fallback used

Target: Cache hit rate > 95%

# Check via API
curl -s http://localhost:8000/api/ai-insights/stats | jq .ml_status
# "healthy" if hit_rate >= 95% and low_conf == 0

Training (Offline)

# 1. Label templates via LLM
python devtools/label_with_llm.py  # Uses NVIDIA API, writes labels

# 2. Fine-tune RoBERTa
jupyter devtools/IaOps.ipynb  # Notebook: tokenize → train → export

# 3. Export model
trainer.save_model("/app/model/log_priority_roberta")

# 4. Deploy: rebuild ml-service + pipeline images
docker compose build ml-service consumer-pipeline
docker compose up -d ml-service consumer-pipeline

Troubleshooting

Symptom Check
All priority_source=rule Model not loaded (ml-service logs), confidence threshold too high
Low cache hit rate New templates (normal), cache TTL too short, Redis unavailable
High latency ml-service not running, model loading, CPU contention
Wrong priorities Retrain with better labels, check label_with_llm.py thresholds
# Check ML service
curl http://localhost:8001/health
# {"status":"healthy","model_loaded":true,"model_version":"roberta_v1.1"}

# Test inference
curl -X POST http://localhost:8001/predict \
  -H "Content-Type: application/json" \
  -d '{"text": "Database connection pool exhausted"}'