πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

Support Ticket Agent with Knowledge Base

AI AgentsCustomer Support Agent🟒 Free Lesson

Advertisement

Support Ticket Agent with Knowledge Base

Customer Support AgentTicket RouterKB SearchResponse GenEscalationSentiment AnalyzerQuality CheckerSupport Orchestrator

What is a Customer Support Agent?

Customer support agents automate ticket handling by classifying issues, searching knowledge bases for solutions, generating responses, and escalating complex cases to human agents. They handle routine inquiries while ensuring complex issues reach the right experts.

The key pipeline is: ticket intake β†’ classification β†’ knowledge retrieval β†’ response generation β†’ quality check β†’ delivery or escalation. Each step adds value: faster response times, consistent quality, and intelligent routing.

Effective support agents maintain conversation context, track resolution status, and learn from historical tickets to improve over time.

Project Overview

We will build a customer support agent that:

  • Classifies incoming tickets by category and urgency
  • Searches knowledge base for relevant solutions
  • Generates personalized response drafts
  • Detects customer sentiment and adjusts tone
  • Escalates complex or high-priority issues
  • Tracks resolution metrics and customer satisfaction

Expected outcome: An agent that handles 70%+ of support tickets automatically.

Difficulty: Advanced (requires understanding of NLP classification, RAG, and conversation design)

Architecture

Support Agent ArchitectureTicket ClassifierCategory + urgencyKB RetrieverChromaDB searchResponse GeneratorLLM + templatesSentiment AnalyzerEscalation EngineAnalyticsSupport Orchestrator

Tools & Setup

ToolVersionPurpose
Python3.11+Core language
ChromaDB0.4+Knowledge base storage
openai1.0+LLM backbone
pydantic2.0+Data models
pandas2.0+Analytics

Step 1: Environment Setup

python -m venv venv
source venv/bin/activate
pip install chromadb openai pydantic pandas
export OPENAI_API_KEY="sk-your-key"

Step 2: Project Structure

Architecture Diagram
support-agent/
β”œβ”€β”€ knowledge/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── kb_store.py
β”œβ”€β”€ classification/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── classifier.py
β”œβ”€β”€ response/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ generator.py
β”‚   └── sentiment.py
β”œβ”€β”€ escalation/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── engine.py
β”œβ”€β”€ agent.py
└── main.py

Step 3: Knowledge Base Store

# knowledge/kb_store.py
import chromadb
from openai import OpenAI
from typing import List, Dict

class KnowledgeBase:
    def __init__(self, collection_name: str = "support_kb"):
        self.client = chromadb.Client()
        self.collection = self.client.get_or_create_collection(
            name=collection_name,
            metadata={"hnsw:space": "cosine"},
        )
        self.openai = OpenAI()

    def _get_embedding(self, text: str) -> List[float]:
        response = self.openai.embeddings.create(
            model="text-embedding-3-small",
            input=text,
        )
        return response.data[0].embedding

    def add_articles(self, articles: List[Dict]) -> None:
        texts = [a["content"] for a in articles]
        embeddings = [self._get_embedding(t) for t in texts]
        ids = [f"article_{i}" for i in range(len(articles))]
        metadatas = [{"title": a.get("title", ""), "category": a.get("category", "")} for a in articles]
        self.collection.add(
            documents=texts,
            embeddings=embeddings,
            ids=ids,
            metadatas=metadatas,
        )

    def search(self, query: str, n_results: int = 3) -> List[Dict]:
        embedding = self._get_embedding(query)
        results = self.collection.query(
            query_embeddings=[embedding],
            n_results=n_results,
        )
        return [
            {
                "content": results["documents"][0][i],
                "title": results["metadatas"][0][i].get("title", ""),
                "category": results["metadatas"][0][i].get("category", ""),
                "score": 1 - results["distances"][0][i],
            }
            for i in range(len(results["documents"][0]))
        ]

Step 4: Ticket Classifier

# classification/classifier.py
from openai import OpenAI
import json

class TicketClassifier:
    CATEGORIES = [
        "billing", "technical_issue", "account_access",
        "feature_request", "bug_report", "how_to",
        "refund", "shipping", "other",
    ]

    def __init__(self, model: str = "gpt-4-turbo-preview"):
        self.client = OpenAI()
        self.model = model

    def classify(self, ticket: dict) -> dict:
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": f"""Classify this support ticket.
                Categories: {', '.join(self.CATEGORIES)}
                
                Return JSON:
                {{
                    "category": "category name",
                    "urgency": "critical|high|medium|low",
                    "sentiment": "positive|neutral|negative|angry",
                    "complexity": "simple|moderate|complex",
                    "needs_escalation": true/false,
                    "key_issues": ["list of main issues"]
                }}"""},
                {"role": "user", "content": f"Subject: {ticket.get('subject', '')}\n\nMessage: {ticket.get('message', '')}"},
            ],
            temperature=0.0,
        )
        try:
            return json.loads(response.choices[0].message.content)
        except:
            return {
                "category": "other",
                "urgency": "medium",
                "sentiment": "neutral",
                "complexity": "moderate",
                "needs_escalation": False,
                "key_issues": [],
            }

Step 5: Response Generator

# response/generator.py
from openai import OpenAI
from typing import List, Dict

class ResponseGenerator:
    def __init__(self, model: str = "gpt-4-turbo-preview"):
        self.client = OpenAI()
        self.model = model

    def generate(
        self,
        ticket: dict,
        classification: dict,
        kb_results: List[Dict],
        tone: str = "professional",
    ) -> str:
        kb_context = "\n".join(
            f"Article: {r['title']}\n{r['content'][:500]}"
            for r in kb_results
        ) if kb_results else "No relevant articles found."
        sentiment_note = ""
        if classification.get("sentiment") in ("negative", "angry"):
            sentiment_note = "Customer is frustrated. Use empathetic tone, acknowledge their frustration."
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": f"""You are a {tone} customer support agent.
                {sentiment_note}
                
                Rules:
                - Be helpful and solution-oriented
                - Reference relevant knowledge base articles
                - If you cannot resolve, explain what escalation will do
                - Never make promises about refunds or credits without approval
                - Keep responses concise (150-300 words)"""},
                {"role": "user", "content": f"Customer ticket:\nSubject: {ticket.get('subject', '')}\nMessage: {ticket.get('message', '')}\n\nCategory: {classification.get('category')}\nUrgency: {classification.get('urgency')}\n\nRelevant knowledge base:\n{kb_context}\n\nDraft a response:"},
            ],
            temperature=0.5,
        )
        return response.choices[0].message.content

# response/sentiment.py
from openai import OpenAI

class SentimentAnalyzer:
    def __init__(self, model: str = "gpt-4-turbo-preview"):
        self.client = OpenAI()
        self.model = model

    def analyze(self, text: str) -> dict:
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": """Analyze sentiment and emotional state.
                Return JSON: {"sentiment": "...", "emotion": "...", "frustration_level": 1-10}"""},
                {"role": "user", "content": text},
            ],
            temperature=0.0,
        )
        import json
        try:
            return json.loads(response.choices[0].message.content)
        except:
            return {"sentiment": "neutral", "emotion": "neutral", "frustration_level": 3}

Step 6: Complete Agent

# agent.py
from knowledge.kb_store import KnowledgeBase
from classification.classifier import TicketClassifier
from response.generator import ResponseGenerator
from response.sentiment import SentimentAnalyzer
from escalation.engine import EscalationEngine
from typing import Dict, List

class CustomerSupportAgent:
    def __init__(self, model: str = "gpt-4-turbo-preview"):
        self.kb = KnowledgeBase()
        self.classifier = TicketClassifier(model)
        self.response_gen = ResponseGenerator(model)
        self.sentiment = SentimentAnalyzer(model)
        self.escalation = EscalationEngine()
        self.tickets: List[Dict] = []

    def load_knowledge_base(self, articles: List[Dict]) -> None:
        self.kb.add_articles(articles)

    def handle_ticket(self, ticket: Dict) -> Dict:
        classification = self.classifier.classify(ticket)
        kb_results = self.kb.search(
            f"{ticket.get('subject', '')} {ticket.get('message', '')}",
            n_results=3,
        )
        sentiment = self.sentiment.analyze(ticket.get("message", ""))
        if classification.get("needs_escalation") or sentiment.get("frustration_level", 0) >= 8:
            escalation = self.escalation.escalate(ticket, classification)
            response = f"This ticket has been escalated. {escalation['message']}"
        else:
            response = self.response_gen.generate(
                ticket, classification, kb_results
            )
        result = {
            "ticket_id": ticket.get("id", "unknown"),
            "classification": classification,
            "sentiment": sentiment,
            "kb_results": kb_results,
            "response": response,
            "escalated": classification.get("needs_escalation", False),
        }
        self.tickets.append(result)
        return result

    def get_metrics(self) -> Dict:
        total = len(self.tickets)
        if total == 0:
            return {"total": 0}
        escalated = sum(1 for t in self.tickets if t["escalated"])
        categories = {}
        for t in self.tickets:
            cat = t["classification"].get("category", "other")
            categories[cat] = categories.get(cat, 0) + 1
        return {
            "total_tickets": total,
            "escalated": escalated,
            "auto_resolved": total - escalated,
            "resolution_rate": f"{((total - escalated) / total * 100):.1f}%",
            "categories": categories,
        }

# escalation/engine.py
from typing import Dict

class EscalationEngine:
    def escalate(self, ticket: Dict, classification: Dict) -> Dict:
        priority = "P1" if classification.get("urgency") == "critical" else "P2"
        reason = classification.get("key_issues", ["Complex issue"])[0] if classification.get("key_issues") else "Requires human review"
        return {
            "priority": priority,
            "reason": reason,
            "message": f"This ticket has been escalated to our {priority} support team. Reason: {reason}. A specialist will respond within 2 hours.",
            "assignee": "senior_support",
        }

Mathematical Foundation

Ticket Resolution Score:

Where each parameter means:

  • β€” complexity score (0-1)
  • β€” urgency score (0-1)
  • β€” sentiment score (0-1)
  • β€” sigmoid function

Intuition: Probability a ticket can be auto-resolved. Lower complexity and calmer sentiment increase auto-resolution likelihood.

Knowledge Base Relevance:

Intuition: Cosine similarity between query and document embeddings measures knowledge base relevance.

Testing & Evaluation

import pytest
from agent import CustomerSupportAgent

@pytest.fixture
def agent():
    return CustomerSupportAgent()

def test_classify():
    classifier = TicketClassifier()
    result = classifier.classify({"subject": "Can't login", "message": "My password reset isn't working"})
    assert "category" in result
    assert result["category"] == "account_access"

def test_handle_ticket(agent):
    result = agent.handle_ticket({
        "id": "T001",
        "subject": "Need help with billing",
        "message": "I was charged twice for my subscription"
    })
    assert "response" in result
    assert "classification" in result

Performance Metrics

MetricValueNotes
Classification Accuracy90%+Category detection
Auto-Resolution Rate70%+Without escalation
Response Generation2-5sGPT-4 per ticket
KB Search Latency50-100msChromaDB
Customer Satisfaction4.2/5+When well-tuned

Deployment

# main.py
from agent import CustomerSupportAgent

def main():
    agent = CustomerSupportAgent()
    articles = [
        {"title": "Reset Password", "content": "Go to settings, click reset password...", "category": "account_access"},
        {"title": "Billing FAQ", "content": "We charge monthly on your billing date...", "category": "billing"},
    ]
    agent.load_knowledge_base(articles)
    print("Support Agent Ready\n")
    while True:
        subject = input("Subject: ").strip()
        message = input("Message: ").strip()
        if not subject:
            break
        result = agent.handle_ticket({"subject": subject, "message": message})
        print(f"\nCategory: {result['classification']['category']}")
        print(f"Response: {result['response'][:200]}...\n")

if __name__ == "__main__":
    main()

Real-World Use Cases

  • SaaS Support: Handle common product questions
  • E-commerce: Order status, returns, and refunds
  • Technical Support: Troubleshooting and how-to guides
  • HR Support: Employee policy questions
  • IT Help Desk: Password resets and access requests

Common Pitfalls & Solutions

PitfallSolution
Wrong classificationContinuously train on new tickets
Tone mismatchesAdjust tone based on sentiment
KB gapsTrack unanswered questions for content creation
Escalation overloadTune escalation thresholds
Repetitive responsesAdd variation in response templates

Summary with Key Takeaways

  • Ticket classification enables automatic routing and prioritization
  • Knowledge base retrieval provides consistent, accurate answers
  • Sentiment analysis adapts response tone to customer emotional state
  • Smart escalation ensures complex issues reach human experts
  • Metrics tracking enables continuous improvement

Need Expert AI Agents Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement