CoolFace
Modelpublic

jcanizalez/qwen3-1.7b-k8s-alert-triage-lora

sourceHugging Faceapache-2.0updated 6d agoView on Hugging Face
0likes21downloads
Model Card

Qwen3-1.7B Kubernetes alert triage (LoRA)

A LoRA adapter for Qwen3-1.7B that reads one Kubernetes alert plus the state of its namespace and names the fault that caused it. It is small enough to run on two CPU cores inside the cluster it watches, so alerts, logs and topology never leave it.

On 124 held-out alerts it scores 82.3% accuracy (a second training run of the same recipe scored 79.8%), against 67.7% for Claude Opus 5 and 60.5% for Gemini 3.5 Flash-Lite given the same prompt.

Code, dataset harness and every result: github.com/jcanizalez/k8s-alert-triage

Labels

bad_image_tag, crashloop_bad_command, dependency_scaled_to_zero, dns_broken, init_container_failing, liveness_probe_failing, missing_configmap, missing_secret, readiness_probe_too_strict, resource_quota_exceeded, unschedulable_resources, wrong_service_selector, and none for routine noise.

Prompt

The model was trained on chat messages with thinking turned off. The system message lists the labels; the user message is the alert followed by the namespace's pods, services and recent events, built by prompt_for in eval/baseline.py. Use that function, or match its format exactly:

text
ALERT: ServiceHasNoEndpoints
severity: critical
namespace: demo
object: frontend
summary: Service frontend has no ready endpoints
description: ...

PODS:
  frontend-554f685c79-tlhjb: phase=Running ready=True restarts=0 waiting=[] lastTerminated=[]

SERVICES:
  frontend: type=ClusterIP selector={'app': 'nothing-matches-this'}

RECENT EVENTS:
  Warning Failed frontend-576f985f7b-cjvfv: Error: ImagePullBackOff

The answer is one label, for example wrong_service_selector.

Use it

With transformers and PEFT:

python
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-1.7B", torch_dtype="auto")
model = PeftModel.from_pretrained(base, "jcanizalez/qwen3-1.7b-k8s-alert-triage-lora")
tok = AutoTokenizer.from_pretrained("jcanizalez/qwen3-1.7b-k8s-alert-triage-lora")

prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True, enable_thinking=False)
ids = tok(prompt, return_tensors="pt")
out = model.generate(**ids, max_new_tokens=48, do_sample=False)
print(tok.decode(out[0][ids["input_ids"].shape[1]:], skip_special_tokens=True))

For llama.cpp, merge the adapter into the 16-bit base and convert to GGUF at q8_0. Serve with --reasoning off so the template matches training.

Do not quantize to 4 bits. The same adapter scored 82.3% loaded, 80.6% merged at 16 bits, 77.4% as a q80 GGUF and 30.6% as q4k_m.

Training

  • —LoRA r=16, alpha=16, dropout 0, on all seven projections of every layer: 17,432,576 trainable parameters, 1.00% of the model.
  • —16-bit base (not QLoRA), so merging is exact.
  • —302 training alerts from 156 injection windows in a kind cluster, split by injection window so no incident appears in both training and test.
  • —3 epochs, learning rate 2e-4, effective batch 8, AdamW 8-bit, linear schedule, seed 7. About 9 minutes on a free Colab T4 with Unsloth.

Limits

Trained on one small demo app in one local cluster, with twelve faults injected on purpose. It knows that cluster's failures, not yours: retrain it on your own alerts before relying on it. It is weakest at dns_broken and at recognising routine noise, where a larger model does better, so escalate what it is unsure of.