CoolFace
Modelpublic

eorgantzoglou/qwen2.5-0.5b-airline-triage-lora

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
1likes31downloads
Model Card

Qwen2.5-0.5B Airline Ticket Triage (LoRA)

LoRA adapters that turn Qwen2.5-0.5B-Instruct into a classifier for airline customer-support messages. Given a tweet, the model returns JSON with an intent (10 classes), an urgency level (3 levels, time-based criterion) and an abusive flag.

Trained on 5,130 tweets from the Customer Support on Twitter corpus, labeled by DeepSeek V4 Flash and audited against a 300-message human-reviewed gold set (labeler–human agreement: intent 97.7%, urgency 92.3%).

Full pipeline (labeling, audit, training, FastAPI serving, AWS deployment): github.com/eorgantzoglou/Smart-Support-Ticket-Triage

Results

Evaluated on the 300-message gold set against human labels — the gold set was fully excluded from training:

MetricValue
Intent accuracy (10 classes)73.0%
Intent macro-F10.645
Urgency accuracy (3 levels)80.0%
Valid JSON output300/300

The zero-shot base model classifies essentially everything as general_question — the classification ability comes from these adapters. Errors concentrate in rare classes (special_assistance: F1 0.29 from only 121 training examples); frequent classes do well (praise 0.91, delay 0.83, lost luggage 0.80).

Usage

python
import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

BASE = "Qwen/Qwen2.5-0.5B-Instruct"
ADAPTER = "eorgantzoglou/qwen2.5-0.5b-airline-triage-lora"

SYSTEM_PROMPT = (
    "You are a triage assistant for an airline's customer support. "
    "Classify the customer tweet. Respond with json only, in exactly this format: "
    '{"intent": "...", "urgency": "...", "abusive": true/false}. '
    "intent must be one of: delay_disruption, checkin_boarding_issue, "
    "flight_cancellation_rebooking, lost_luggage, special_assistance, "
    "general_complaint, general_question, praise_feedback, spam_irrelevant, "
    "other_unclear. urgency must be one of: high, medium, low."
)

tokenizer = AutoTokenizer.from_pretrained(BASE)
model = PeftModel.from_pretrained(
    AutoModelForCausalLM.from_pretrained(BASE, torch_dtype=torch.float32), ADAPTER
).merge_and_unload()

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": "my bags are lost and nobody at the desk is helping"},
]
inputs = tokenizer(
    tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True),
    return_tensors="pt",
)
out = model.generate(**inputs, max_new_tokens=60, do_sample=False,
                     pad_token_id=tokenizer.eos_token_id)
print(tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
# {"intent": "lost_luggage", "urgency": "high", "abusive": false}

The system prompt must match the one used in training (above) — the model was fine-tuned with it and expects it verbatim.

Training

  • —LoRA: r=16, α=32, dropout 0.05, adapters on all linear layers (q/k/v/o/gate/up/down) — ~35 MB of weights
  • —2 epochs, lr 2e-4, fp16, on a free Colab T4
  • —Chat-format dataset (system/user/assistant), 5,130 train / 570 val

Limitations

  • —The abusive flag is unreliable: only 10 of 6,000 training examples were abusive. In production this signal should come from a separate moderation layer, not this classifier.
  • —Rare intents (special_assistance, spam_irrelevant) have low F1 due to class imbalance.
  • —English only; trained on airline-domain tweets — expect degradation on other support domains.