Portfolio Projects ยท Project 7 of 10

Project 7: Support Ticket Triage & Reply Copilot

๐Ÿ› ๏ธ Beginnerโฑ 1โ€“2 weekends๐Ÿ“„ Resume lines included

A business-friendly project combining classical NLP + LLMs: classify incoming tickets by intent, urgency and sentiment, route them, and draft grounded replies from a knowledge base for an agent to approve.

What you'll build

Architecture

Ticket โ†’ PII masking โ†’ fast classifier (TF-IDF + LogReg or DistilBERT) โ†’ confidence?
     high โ†’ route to queue          low โ†’ LLM zero-shot classification fallback
     โ†’ RAG(KB) โ†’ draft reply (JSON: reply, citations, needs_human: bool) โ†’ agent review UI โ†’ send
Feedback (edits, reroutes) โ†’ retraining data

Tech stack

scikit-learn or Hugging Face Transformers, an LLM, FAISS, FastAPI, Streamlit, plus a public dataset (e.g. customer-support ticket datasets on Kaggle or Hugging Face).

Step by step

  1. Dataset: load tickets with intent labels; split by time if timestamps exist.
  2. Baseline: TF-IDF + logistic regression; report macro-F1 per intent.
  3. Upgrade: fine-tune DistilBERT; compare accuracy and latency.
  4. Fallback: use LLM zero-shot classification when the classifier's confidence is below 0.6.
  5. PII masking (emails, phones, card numbers) before any LLM call.
  6. Reply drafting: RAG over the KB, with a structured JSON output that includes needs_human.
  7. Agent UI: show the draft, the citations and an edit box; log the edit distance as a quality signal.
  8. Measure: macro-F1, the share of drafts sent with minor edits, and average handling time saved.

Starter code

from sklearn.pipeline import make_pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
import re
clf = make_pipeline(TfidfVectorizer(ngram_range=(1, 2), min_df=2), LogisticRegression(max_iter=2000, class_weight="balanced"))
clf.fit(train.text, train.intent); print(classification_report(test.intent, clf.predict(test.text)))
mask = lambda t: re.sub(r"\b\d{10}\b", "<PHONE>", re.sub(r"\S+@\S+", "<EMAIL>", t))
def triage(text):
    p = clf.predict_proba([text])[0]; intent = clf.classes_[p.argmax()]
    if p.max() < 0.6: intent = llm_classify(mask(text), labels=list(clf.classes_))
    return intent, float(p.max())

Deploy it

FastAPI (classifier + drafts) and a Streamlit agent console. Add a demo with 20 sample tickets and a short screen recording.

Put it on your resume

Interview questions you'll get

Stretch goals

Created by Ajeetkumar