Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

20 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ€– Telecom Support Agent

Python FastAPI ChromaDB LangChain Tests Coverage CI License

Multi-Agent RAG Support Bot β€” Grounded in Real Policy Docs

Answers billing, plan, and troubleshooting questions accurately β€” and knows exactly when to escalate to a human.


View Repository API Docs Submission License

πŸ† Built for The Talent Hack Β· Deutsche Telekom Digital Labs Β· AI Engineer Track
See SUBMISSION.md for the full hackathon write-up and architecture rationale.


🌟 Platform Overview

🎯 Project Vision

The Telecom Support Agent is a production-grade multi-agent AI system that handles real customer support queries β€” grounded entirely in policy documents, with zero hallucinated answers. Every response is retrieved from actual telecom policy docs, cited at the source, and confidence-gated before delivery. When the system isn't certain enough, or when a request would mutate account state, it escalates automatically β€” never silently fails.

graph TD
    A[πŸ’¬ Customer Message] --> B[🎯 Intent Router]

    B --> C[πŸ’³ Billing Agent]
    B --> D[πŸ“‹ Plan Info Agent]
    B --> E[πŸ”§ Troubleshooting Agent]

    C --> F[πŸ” RAG Retrieval]
    D --> F
    E --> F

    F --> G[πŸ“„ ChromaDB + Policy Docs]
    G --> H[βœ… Confidence Gate]

    H -->|High Confidence| I[πŸ“€ Grounded Answer + Citation]
    H -->|Low Confidence| J[🚨 Escalate to Human]
    H -->|Account-Mutating Request| J

    style A fill:#e1f5fe
    style G fill:#f3e5f5
    style I fill:#e8f5e9
    style J fill:#fce4ec
Loading

✨ Core Capabilities

Feature Technology Detail
🎯 Intent Classification Rule-based + LLM billing / plan_info / troubleshooting / out_of_scope
πŸ“„ RAG-Grounded Answers ChromaDB Section-aware chunking on ## markdown headers
πŸ€– Domain-Specific Agents Injectable LLM pipeline 3 specialized agents + orchestrator
πŸ›‘οΈ Confidence Gate Deterministic threshold Numeric score β€” not an LLM self-report
🚨 Escalation Guard Keyword-rule engine Refund / cancel / plan-switch β†’ always human
πŸ§ͺ Zero-API Testing Stub injection Full pipeline testable without an Azure OpenAI key
🐳 Containerized Docker One-command deployment

πŸ—οΈ System Architecture

🎨 Agent Pipeline Design

                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  User message ──────▢│       Intent Router           β”‚
                      β”‚  billing / plan_info /         β”‚
                      β”‚  troubleshooting / out_of_scopeβ”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό                      β–Ό                      β–Ό
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚  πŸ’³ Billing      β”‚   β”‚  πŸ“‹ Plan Info    β”‚   β”‚  πŸ”§ Troubleshooting  β”‚
     β”‚  Agent           β”‚   β”‚  Agent           β”‚   β”‚  Agent               β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚                      β”‚                         β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β–Ό
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚    πŸ” RAG Retrieval    β”‚
                         β”‚  ChromaDB + Policy Docsβ”‚
                         β”‚  Section-aware chunks  β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β–Ό
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚   βœ… Confidence Gate   β”‚
                         β”‚  threshold: numeric    β”‚
                         β”‚  mutating: keyword ruleβ”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                           β–Ό                    β–Ό
                  πŸ“€ Grounded Answer      🚨 Escalate to Human
                  + Source Citation       (ticket reference)

πŸ“‚ Project Structure

telecom-support-agent/
β”‚
β”œβ”€β”€ πŸ“ app/
β”‚   β”œβ”€β”€ πŸ“ agents/
β”‚   β”‚   β”œβ”€β”€ intent_agent.py             # billing / plan_info / troubleshooting / out_of_scope
β”‚   β”‚   β”œβ”€β”€ billing_agent.py            # RAG-grounded billing answers
β”‚   β”‚   β”œβ”€β”€ plan_agent.py               # RAG-grounded plan comparisons
β”‚   β”‚   β”œβ”€β”€ troubleshooting_agent.py    # RAG-grounded troubleshooting steps
β”‚   β”‚   β”œβ”€β”€ escalation_agent.py         # deterministic escalation gate
β”‚   β”‚   └── orchestrator.py             # full pipeline wiring + error handling
β”‚   β”‚
β”‚   β”œβ”€β”€ πŸ“ rag/
β”‚   β”‚   β”œβ”€β”€ embeddings.py               # offline hashing embedder (zero model download)
β”‚   β”‚   β”œβ”€β”€ ingest.py                   # chunk + embed + load policy docs
β”‚   β”‚   └── retriever.py                # retrieval wrapper, fails soft to []
β”‚   β”‚
β”‚   β”œβ”€β”€ llm.py                          # Azure OpenAI client (only wired in when key is present)
β”‚   └── main.py                         # FastAPI app + conditional LLM wiring
β”‚
β”œβ”€β”€ πŸ“ data/policies/                   # sample billing, plan, troubleshooting docs
β”œβ”€β”€ πŸ“ tests/                           # 29 tests β€” unit + API layer
β”‚   β”œβ”€β”€ test_intent_agent.py
β”‚   β”œβ”€β”€ test_billing_agent.py
β”‚   β”œβ”€β”€ test_plan_agent.py
β”‚   β”œβ”€β”€ test_troubleshooting_agent.py
β”‚   β”œβ”€β”€ test_escalation_gate.py
β”‚   β”œβ”€β”€ test_retrieval.py
β”‚   β”œβ”€β”€ test_orchestrator.py
β”‚   └── test_api.py                     # FastAPI TestClient
β”‚
β”œβ”€β”€ SUBMISSION.md                       # Hackathon write-up + rationale
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ .env.example
└── requirements.txt

πŸ€– Specialized Agent System

🎯 Five Agents, One Pipeline

1. 🎯 Intent Router

Role: Entry point classifier

Classifies into:
  - billing         Bill queries, payment issues
  - plan_info       Plan comparisons, upgrades
  - troubleshooting Network, device, connectivity
  - out_of_scope    Routes away gracefully

Method:
  - Rule-based primary pass
  - LLM fallback for ambiguous input
  - Stub fallback when no API key set

Output:
  - intent_label
  - confidence_score
  - routed_agent

2. πŸ’³ Billing Agent

Role: Billing & payment specialist

Handles:
  - Unexpected charge queries
  - Invoice breakdown requests
  - Payment failure investigation
  - Roaming charge explanations

Method:
  - ChromaDB retrieval on billing docs
  - Section-aware policy matching
  - Citation extraction from chunks

Output:
  - Grounded answer
  - Source citation (doc + section)
  - Confidence score

3. πŸ“‹ Plan Info Agent

Role: Plan comparison specialist

Handles:
  - Plan feature comparisons
  - Upgrade / downgrade info
  - Add-on and bundle details
  - Contract term queries

Method:
  - ChromaDB retrieval on plan docs
  - Multi-chunk context assembly
  - Comparative answer synthesis

Output:
  - Grounded comparison
  - Source citation
  - Confidence score

4. πŸ”§ Troubleshooting Agent

Role: Technical support specialist

Handles:
  - Network connectivity issues
  - Device configuration problems
  - Service outage queries
  - Signal and speed issues

Method:
  - ChromaDB retrieval on tech docs
  - Step-by-step answer extraction
  - Escalation if steps exceed scope

Output:
  - Grounded troubleshooting steps
  - Source citation
  - Confidence score

5. πŸ›‘οΈ Escalation Gate (Confidence Guard)

Role: Quality gate + safety enforcer

Triggers escalation on:
  Keyword rule (deterministic):         Numeric threshold:
  - "refund" / "get my money back"      - confidence_score < threshold
  - "cancel" / "close my account"       - retrieval returns []
  - "switch plan" / "change plan"       - answer flagged low-certainty

Why deterministic (not LLM self-report):
  The model proposes answers.
  It never decides on its own that it is "confident enough."
  Mutating requests are caught by rule β€” not by asking the LLM if it feels sure.

Output:
  - escalate: true/false
  - reason: "low_confidence" | "account_mutating" | "out_of_scope"
  - ticket_reference: TKT-{uuid}

πŸ” RAG Pipeline

πŸ“„ Section-Aware Chunking

Chunks split on markdown ## headers β€” not fixed character windows. Topical coherence per chunk matters more for retrieval quality than raw chunk size.

# ingest.py β€” section-aware chunking
def chunk_policy_doc(text: str) -> list[str]:
    """Split on ## headers to preserve topical coherence."""
    sections = re.split(r'\n##\s+', text)
    return [s.strip() for s in sections if s.strip()]

# Each chunk = one coherent policy topic
# e.g. "## Roaming Charges" stays together as one retrieval unit

🧠 Offline Hashing Embedder

app/rag/embeddings.py uses a keyword-overlap based hashing embedder β€” no sentence-transformers, no external model download. The project runs immediately in network-locked environments.

# embeddings.py β€” swap-ready interface
class BaseEmbedder(ABC):
    @abstractmethod
    def embed(self, text: str) -> list[float]: ...

class HashingEmbedder(BaseEmbedder):
    """Offline keyword-overlap embedder. Zero external calls."""
    def embed(self, text: str) -> list[float]: ...

class AzureOpenAIEmbedder(BaseEmbedder):
    """Drop-in Azure OpenAI embedder for production semantic search."""
    def embed(self, text: str) -> list[float]: ...

Swap HashingEmbedder β†’ AzureOpenAIEmbedder in config.py for production-grade semantic search. The interface is identical.


πŸ§ͺ Testing

πŸ“Š Coverage Breakdown

pip install -r requirements-dev.txt
pytest tests/ --cov=app --cov-report=term-missing

29 tests Β· 85% coverage

Module Tests What's Covered
intent_agent.py 4 All 4 intent labels, ambiguous input
billing_agent.py 3 Grounded answer, citation, stub fallback
plan_agent.py 3 Plan comparison, multi-chunk context
troubleshooting_agent.py 3 Step extraction, empty retrieval
escalation_agent.py 5 Keyword rule, numeric threshold, both triggers
retriever.py 4 Match, no-match, soft fail to []
orchestrator.py 4 Full pipeline, error handling
api.py 3 /chat endpoint via FastAPI TestClient

πŸ”Œ Injectable LLM β€” Test Without Azure OpenAI Credentials

Every agent accepts an injectable llm_call parameter. The full pipeline is unit-testable without touching a real Azure OpenAI deployment:

# In tests β€” inject a stub instead of Azure OpenAI
def stub_llm(system_prompt: str, user_message: str) -> str:
    return "STUB: This is a test answer."

agent = BillingAgent(llm_call=stub_llm)
result = agent.answer("Why is my bill higher?")
assert result.confidence > 0
assert result.source_citation is not None
# In production β€” real Azure OpenAI client is wired in only when
# all required Azure credentials are configured.

# app/main.py
ACTIVE_LLM_CALL = (
    azure_llm_call
    if all(
        [
            os.getenv("AZURE_OPENAI_API_KEY"),
            os.getenv("AZURE_OPENAI_ENDPOINT"),
            os.getenv("AZURE_OPENAI_API_VERSION"),
            os.getenv("AZURE_OPENAI_DEPLOYMENT"),
        ]
    )
    else stub_llm
)

orchestrator = Orchestrator(llm_call=ACTIVE_LLM_CALL)

πŸ” Required Azure OpenAI Environment Variables

AZURE_OPENAI_API_KEY=xxxxxxxxxxxxxxxx

AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com/

AZURE_OPENAI_API_VERSION=2024-12-01-preview

AZURE_OPENAI_DEPLOYMENT=<your-deployment-name>

⚑ Quick Start

πŸ“‹ Prerequisites

Required:
  - Python: 3.11+
  - pip: latest

Optional:
  - AZURE_OPENAI_API_KEY: for real LLM answers (stubs work without it)

System:
  - RAM: 4GB minimum
  - Internet: only needed if using real Azure OpenAI

πŸš€ Installation

Step 1 β€” Clone & Install

git clone https://github.com/AIstar007/telecom-support-agent.git
cd telecom-support-agent

python -m venv venv
source venv/bin/activate        # macOS / Linux
# venv\Scripts\activate         # Windows

pip install -r requirements.txt

Step 2 β€” Ingest Policy Docs

# Run once β€” or whenever your policy docs change
python -m app.rag.ingest

Step 3 β€” Configure Environment

cp .env.example .env
# .env β€” full configuration
OPENAI_API_KEY=sk-your_key_here   # optional β€” stubs work without it

# Retrieval settings
RETRIEVAL_TOP_K=3
CONFIDENCE_THRESHOLD=0.65

# Escalation keywords (pipe-separated)
MUTATING_KEYWORDS=refund|cancel|switch plan|close account|change plan

Step 4 β€” Start the Server

uvicorn app.main:app --reload

βœ… Zero setup required to see it work. Every agent uses deterministic stub logic when no OPENAI_API_KEY is set. Routing, retrieval, and escalation are all real and testable immediately.


🌐 API Usage

Endpoints

# Health check
GET  /health

# Send a support message
POST /chat

Chat Endpoint

curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"session_id": "demo", "message": "why is my bill higher this month"}'

Response β€” Grounded Answer:

{
  "answer": "Your bill may be higher due to international roaming charges applied between the 3rd–8th. Per our Billing Policy Β§4.2, roaming rates apply when your device connects to a non-home network.",
  "source_citation": "billing_policy.md ## Roaming Charges",
  "confidence": 0.87,
  "escalated": false,
  "intent": "billing"
}

Response β€” Escalated:

{
  "answer": null,
  "escalated": true,
  "reason": "account_mutating",
  "ticket_reference": "TKT-8a3f91c2",
  "message": "This request has been escalated to a human agent. Reference: TKT-8a3f91c2"
}

🐳 Docker

docker build -t telecom-support-agent .
docker run -p 8000:8000 --env-file .env telecom-support-agent

🎨 Design Decisions

Decision Rationale
Offline hashing embedder No model download; runs in network-locked environments. Swap-ready interface for semantic embeddings in production.
Section-aware chunking (## splits) Topical coherence per chunk matters more for retrieval quality than raw chunk size.
Deterministic escalation gate The model proposes answers. It never decides on its own that it's confident enough. Keyword rule catches mutating requests; numeric threshold catches low-certainty answers.
Injectable llm_call Full pipeline testable without hitting a real API. Same mechanism conditionally wires in real OpenAI client when key is present.
No LangChain Explicit agent logic, no abstraction overhead β€” every step is traceable and independently testable.

πŸ—ΊοΈ Roadmap

Feature Status
Real DTDL policy corpus πŸ”œ Planned
Auth + account-lookup integration πŸ”œ Planned
Semantic embeddings (OpenAI / sentence-transformers) πŸ”œ Planned (interface ready)
Streaming responses πŸ”œ Planned
Multi-turn conversation memory πŸ”œ Planned

🧱 Tech Stack

Layer Technology
API Framework FastAPI
Vector Store ChromaDB
LLM OpenAI β€” optional, stubs work without it
Embeddings Offline hashing embedder (swap-ready for semantic)
Testing pytest + FastAPI TestClient
CI GitHub Actions
Containerization Docker

πŸš€ Get Started in Minutes

Clone Repo View API Docs Read Submission


πŸ€– Policy-Grounded Β· Confidence-Gated Β· Human-Escalating

Built with ❀️ for Deutsche Telekom Digital Labs β€” The Talent Hack, AI Engineer Track

🌟 Star this repo if you value production-ready AI design! Β· πŸ› Report Issues Β· πŸ’‘ Request Features

πŸ“„ License: MIT Β· πŸ‘¨β€πŸ’» Author: Alen Thomas (AIstar007)

Releases

Packages

Contributors

Languages