Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files
README.md
CHANGED
|
@@ -97,16 +97,16 @@ sequenceDiagram
|
|
| 97 |
|
| 98 |
## π§ The 6-Agent Triage Pipeline
|
| 99 |
|
| 100 |
-
CustomerCore uses **LangGraph** to orchestrate 6 specialized agents in a **sequential pipeline**
|
| 101 |
|
| 102 |
```mermaid
|
| 103 |
graph LR
|
| 104 |
A[π© Ticket In] --> B[π·οΈ Classify]
|
| 105 |
B --> C[π§ Memory]
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
F --> G{π HITL Check}
|
| 110 |
G -->|Safe| H[β
Finalize]
|
| 111 |
G -->|Risky| I[βΈοΈ Human Review]
|
| 112 |
I --> H
|
|
@@ -114,7 +114,7 @@ graph LR
|
|
| 114 |
|
| 115 |
| # | Agent | What it does | Key detail |
|
| 116 |
|---|-------|-------------|------------|
|
| 117 |
-
| 1 | **Classify Agent** | Categorizes ticket (Billing, Technical, Security, Account) and assigns priority (Low β Critical) | Uses LLM Router β local Gemma for routine, cloud
|
| 118 |
| 2 | **Memory Agent** | Recalls past interactions for this customer | Uses **Mem0** with tenant-scoped identifiers |
|
| 119 |
| 3 | **RAG Agent** | Hybrid search β BM25 keyword + ChromaDB vector retrieval with **Reciprocal Rank Fusion** (RRF) | Optional cross-encoder reranking via `ms-marco-MiniLM-L-6-v2` |
|
| 120 |
| 4 | **Churn Agent** | Runs customer features through our trained **Random Forest** model | Features: monthly spend, tenure, ticket count, contract months |
|
|
@@ -123,6 +123,8 @@ graph LR
|
|
| 123 |
|
| 124 |
When HITL flags a ticket, LangGraph's **`interrupt_before` checkpoint** pauses execution. The state is saved in memory. A human operator reviews from the dashboard and calls `resume_triage()` to continue. The LangGraph `MemorySaver` checkpointer makes this possible β it stores the full agent state at the interrupt point so execution can resume exactly where it stopped.
|
| 125 |
|
|
|
|
|
|
|
| 126 |
---
|
| 127 |
|
| 128 |
## π RAG β How Knowledge Retrieval Works
|
|
@@ -166,23 +168,37 @@ The training pipeline (`src/ml/train_churn.py`) trains all 3 models, compares F1
|
|
| 166 |
| Model | Provider | When it's used |
|
| 167 |
|:------|:---------|:---------------|
|
| 168 |
| **Gemma 3 4B** | Ollama (runs locally) | Classification, extraction, routine reasoning |
|
| 169 |
-
| **
|
|
|
|
| 170 |
|
| 171 |
### SLA-Aware LLM Router β Smart Model Selection
|
| 172 |
|
| 173 |
-
The router (`src/rag/router.py`) automatically picks the model based on task type
|
| 174 |
|
| 175 |
| Task | Low/Medium Priority | High/Critical Priority |
|
| 176 |
|:-----|:-------------------|:----------------------|
|
| 177 |
| Classify | π’ Local Gemma (~150ms, $0) | π’ Local Gemma |
|
| 178 |
| Extract | π’ Local Gemma | π’ Local Gemma |
|
| 179 |
-
| Reason | π’ Local Gemma | π΅ Cloud
|
| 180 |
-
| Action | π΅ Cloud
|
|
|
|
|
|
|
| 181 |
|
| 182 |
-
|
| 183 |
|
| 184 |
SLA latency targets per priority: Critical β€200ms, High β€500ms, Medium β€1000ms, Low β€2000ms. Violations are tracked in Prometheus metrics.
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
---
|
| 187 |
|
| 188 |
## π Data Pipeline β How Data Flows
|
|
@@ -241,20 +257,20 @@ The live dashboard at [huggingface.co/spaces/saibalajiomg/customercore](https://
|
|
| 241 |
|
| 242 |
### What you see:
|
| 243 |
|
| 244 |
-
- **Session Context Bar** β Tenant, Role, and Auth status at the top
|
| 245 |
-
- **AI Triage Pipeline** β Submit tickets or use 1-click demo presets (billing issue, outage report, etc.)
|
| 246 |
- **Prediction Cards** β Priority, Routing Team, Churn Risk %, Outage Detection
|
| 247 |
- **Suggested Resolution** β AI-generated response with KB citations from RAG
|
| 248 |
-
- **HITL Workspace** β
|
| 249 |
- **System Health Panel** β Service status (Supabase β
, Redis, ChromaDB)
|
| 250 |
|
| 251 |
### Understanding the Session Context:
|
| 252 |
|
| 253 |
| Field | What it means |
|
| 254 |
|:------|:-------------|
|
| 255 |
-
| **Tenant** | The company/organization (e.g. "
|
| 256 |
-
| **Role** | `support_agent` can submit tickets. `manager` can
|
| 257 |
-
| **Session / Token** | Active JWT token status. The token carries `tenant_id` + `role` claims, signed with HS256. Auto-generated on the dashboard for demo purposes |
|
| 258 |
|
| 259 |
### How Authentication Works:
|
| 260 |
|
|
@@ -306,6 +322,7 @@ Two execution paths: **Fast path** (regex, <5ms) catches obvious violations. **S
|
|
| 306 |
- **BM25 Index**: Physically partitioned per tenant (separate corpora)
|
| 307 |
- **Supabase**: Row-Level Security (RLS) policies enforce isolation at the database layer
|
| 308 |
- **Role-Based Access Control**: `support_agent` < `manager` < `admin` β HITL resume requires `manager`+
|
|
|
|
| 309 |
|
| 310 |
---
|
| 311 |
|
|
@@ -381,7 +398,7 @@ Three workflows run automatically:
|
|
| 381 |
|
| 382 |
| Workflow | Trigger | What it does |
|
| 383 |
|:---------|:--------|:------------|
|
| 384 |
-
| **CI Pipeline** (`ci.yml`) | Push to `main` or PR | Install deps β Lint with **Ruff** β Run **pytest** (
|
| 385 |
| **ML Training** (`train.yml`) | Push to `main` | Train churn models β Log to DagsHub MLflow β Post **CML report** as PR comment with metrics |
|
| 386 |
| **HF Deploy** (`hf_deploy.yml`) | Push to `main` | Sync entire repo to Hugging Face Space β Triggers Docker rebuild β Live in ~2 min |
|
| 387 |
|
|
@@ -612,13 +629,13 @@ CustomerCore/
|
|
| 612 |
| **Auth** | PyJWT (HS256), RBAC, Supabase Row-Level Security |
|
| 613 |
| **Event Streaming** | Redpanda (Kafka-compatible, no JVM, no ZooKeeper) |
|
| 614 |
| **Object Storage** | MinIO (local S3), DagsHub DVC remote (cloud) |
|
| 615 |
-
| **Caching** | Redis / Upstash Redis
|
| 616 |
| **Observability** | Prometheus, Grafana, OpenTelemetry Collector, Langfuse |
|
| 617 |
| **Infrastructure** | Docker, Docker Compose, Kubernetes (Kind), Hugging Face Spaces |
|
| 618 |
| **CI/CD** | GitHub Actions, CML (Continuous Machine Learning), Ruff (linter) |
|
| 619 |
| **Data Transforms** | dbt (DuckDB adapter) β 8 Gold mart models |
|
| 620 |
-
| **Security** | AES-256-GCM encryption, Constitutional AI (8-rule safety engine) |
|
| 621 |
-
| **Secrets** | Doppler (cloud secrets manager) |
|
| 622 |
| **Logging** | structlog (structured JSON logs) |
|
| 623 |
|
| 624 |
---
|
|
@@ -687,6 +704,10 @@ pytest tests/ -v
|
|
| 687 |
| **UTF-8 encoding on Windows** | Python on Windows defaults to CP1252 β MLflow logging fails with emoji/special chars | Set `PYTHONIOENCODING=utf-8` and use `python -X utf8` flag |
|
| 688 |
| **CML reports on every push** | ML training workflow triggers even on README changes | Accepted trade-off: ensures model registry is always in sync. Can be scoped to `src/ml/**` paths if needed |
|
| 689 |
| **Database schema drift** | New columns added in code but HF Space container has old schema | Added `migrations.py` that runs `ALTER TABLE ADD COLUMN IF NOT EXISTS` on every startup |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 690 |
|
| 691 |
---
|
| 692 |
|
|
|
|
| 97 |
|
| 98 |
## π§ The 6-Agent Triage Pipeline
|
| 99 |
|
| 100 |
+
CustomerCore uses **LangGraph** to orchestrate 6 specialized agents in a **parallel + sequential hybrid pipeline** with conditional Human-in-the-Loop gating. The graph topology uses a **fan-out / fan-in pattern** where the Memory, RAG, Churn, and Incident agents execute concurrently after classification, then converge at the HITL gate:
|
| 101 |
|
| 102 |
```mermaid
|
| 103 |
graph LR
|
| 104 |
A[π© Ticket In] --> B[π·οΈ Classify]
|
| 105 |
B --> C[π§ Memory]
|
| 106 |
+
B --> D[π RAG]
|
| 107 |
+
B --> E[π Churn]
|
| 108 |
+
B --> F[π¨ Incident]
|
| 109 |
+
C & D & E & F --> G{π HITL Check}
|
| 110 |
G -->|Safe| H[β
Finalize]
|
| 111 |
G -->|Risky| I[βΈοΈ Human Review]
|
| 112 |
I --> H
|
|
|
|
| 114 |
|
| 115 |
| # | Agent | What it does | Key detail |
|
| 116 |
|---|-------|-------------|------------|
|
| 117 |
+
| 1 | **Classify Agent** | Categorizes ticket (Billing, Technical, Security, Account) and assigns priority (Low β Critical) | Uses SLA-Aware LLM Router β local Gemma for routine, cloud frontier for critical |
|
| 118 |
| 2 | **Memory Agent** | Recalls past interactions for this customer | Uses **Mem0** with tenant-scoped identifiers |
|
| 119 |
| 3 | **RAG Agent** | Hybrid search β BM25 keyword + ChromaDB vector retrieval with **Reciprocal Rank Fusion** (RRF) | Optional cross-encoder reranking via `ms-marco-MiniLM-L-6-v2` |
|
| 120 |
| 4 | **Churn Agent** | Runs customer features through our trained **Random Forest** model | Features: monthly spend, tenure, ticket count, contract months |
|
|
|
|
| 123 |
|
| 124 |
When HITL flags a ticket, LangGraph's **`interrupt_before` checkpoint** pauses execution. The state is saved in memory. A human operator reviews from the dashboard and calls `resume_triage()` to continue. The LangGraph `MemorySaver` checkpointer makes this possible β it stores the full agent state at the interrupt point so execution can resume exactly where it stopped.
|
| 125 |
|
| 126 |
+
> **Performance gain**: Running Memory, RAG, Churn, and Incident agents concurrently instead of sequentially reduced pipeline latency by **~45%** (from ~7 seconds to ~3β4 seconds for complex tickets).
|
| 127 |
+
|
| 128 |
---
|
| 129 |
|
| 130 |
## π RAG β How Knowledge Retrieval Works
|
|
|
|
| 168 |
| Model | Provider | When it's used |
|
| 169 |
|:------|:---------|:---------------|
|
| 170 |
| **Gemma 3 4B** | Ollama (runs locally) | Classification, extraction, routine reasoning |
|
| 171 |
+
| **Gemini 2.5 Flash** | OpenRouter (cloud API) | Fast-tier cloud fallback β when Ollama unavailable |
|
| 172 |
+
| **Claude 3.5 Sonnet** | OpenRouter (cloud API) | Frontier-tier reasoning for critical/complex tickets |
|
| 173 |
|
| 174 |
### SLA-Aware LLM Router β Smart Model Selection
|
| 175 |
|
| 176 |
+
The router (`src/rag/router.py`) automatically picks the right model based on task type, priority, and runtime environment:
|
| 177 |
|
| 178 |
| Task | Low/Medium Priority | High/Critical Priority |
|
| 179 |
|:-----|:-------------------|:----------------------|
|
| 180 |
| Classify | π’ Local Gemma (~150ms, $0) | π’ Local Gemma |
|
| 181 |
| Extract | π’ Local Gemma | π’ Local Gemma |
|
| 182 |
+
| Reason | π’ Local Gemma | π΅ Cloud Frontier (Claude 3.5 Sonnet) |
|
| 183 |
+
| Action | π΅ Cloud Fast (Gemini 2.5 Flash) | π΅ Cloud Frontier |
|
| 184 |
+
|
| 185 |
+
> **Result**: ~80% of tickets are handled locally at **$0 cost** and **<200ms latency**. Only complex/high-risk tickets go to the frontier cloud model.
|
| 186 |
|
| 187 |
+
**Dynamic Local β Cloud Fallback**: The `LLMClient` detects the runtime environment at startup. If `SPACE_ID` (Hugging Face) or `APP_ENV=production` is set, local Ollama calls are transparently redirected to `openrouter/google/gemini-2.5-flash` with zero timeout delay. If local Ollama fails on a development machine (e.g., not running), the same fallback activates automatically.
|
| 188 |
|
| 189 |
SLA latency targets per priority: Critical β€200ms, High β€500ms, Medium β€1000ms, Low β€2000ms. Violations are tracked in Prometheus metrics.
|
| 190 |
|
| 191 |
+
### L2 Semantic Cache β Avoid Redundant LLM Calls
|
| 192 |
+
|
| 193 |
+
On top of model routing, a **two-layer semantic cache** (`src/rag/router.py`) intercepts calls before they reach the LLM:
|
| 194 |
+
|
| 195 |
+
| Layer | Storage | Hit condition | Benefit |
|
| 196 |
+
|:------|:--------|:--------------|:--------|
|
| 197 |
+
| **L1 Exact** | Redis in-memory dict | Same prompt hash | Sub-millisecond, $0 cost |
|
| 198 |
+
| **L2 Semantic** | Redis + embedding similarity | Cosine similarity > 0.92 | ~85% of near-duplicate tickets served from cache |
|
| 199 |
+
|
| 200 |
+
Cache hit ratio is tracked as a Grafana metric. Each cache hit saves ~$0.002β$0.04 in API costs and 150β800ms of latency.
|
| 201 |
+
|
| 202 |
---
|
| 203 |
|
| 204 |
## π Data Pipeline β How Data Flows
|
|
|
|
| 257 |
|
| 258 |
### What you see:
|
| 259 |
|
| 260 |
+
- **Session Context Bar** β Tenant, Role, and Auth status at the top. Changing either instantly re-generates a JWT and enforces access rules
|
| 261 |
+
- **AI Triage Pipeline** β Submit tickets or use 1-click demo presets (billing issue, outage report, PII leak, etc.)
|
| 262 |
- **Prediction Cards** β Priority, Routing Team, Churn Risk %, Outage Detection
|
| 263 |
- **Suggested Resolution** β AI-generated response with KB citations from RAG
|
| 264 |
+
- **HITL Workspace** β Role-gated: `manager`+ sees the flagged ticket review queue; `support_agent` sees an explicit "Access Denied" panel. Switching roles instantly clears any previously loaded data β no stale reviews persist
|
| 265 |
- **System Health Panel** β Service status (Supabase β
, Redis, ChromaDB)
|
| 266 |
|
| 267 |
### Understanding the Session Context:
|
| 268 |
|
| 269 |
| Field | What it means |
|
| 270 |
|:------|:-------------|
|
| 271 |
+
| **Tenant** | The company/organization (e.g. "acme-corp", "globex", "initech"). All data is isolated per tenant β one tenant can never see another's tickets or triage history |
|
| 272 |
+
| **Role** | `support_agent` can submit tickets and view results. `manager` can additionally access the HITL Workspace to review and approve/override flagged AI decisions |
|
| 273 |
+
| **Session / Token** | Active JWT token status. The token carries `tenant_id` + `role` claims, signed with HS256. Auto-generated on the dashboard for demo purposes β in production this would come from Supabase Auth or Auth0 |
|
| 274 |
|
| 275 |
### How Authentication Works:
|
| 276 |
|
|
|
|
| 322 |
- **BM25 Index**: Physically partitioned per tenant (separate corpora)
|
| 323 |
- **Supabase**: Row-Level Security (RLS) policies enforce isolation at the database layer
|
| 324 |
- **Role-Based Access Control**: `support_agent` < `manager` < `admin` β HITL resume requires `manager`+
|
| 325 |
+
- **Frontend RBAC enforcement**: The HITL Workspace instantly clears previously loaded reviews and displays an "Access Denied" message the moment the active role is switched to `support_agent` β no stale data persists across role changes
|
| 326 |
|
| 327 |
---
|
| 328 |
|
|
|
|
| 398 |
|
| 399 |
| Workflow | Trigger | What it does |
|
| 400 |
|:---------|:--------|:------------|
|
| 401 |
+
| **CI Pipeline** (`ci.yml`) | Push to `main` or PR | Install deps β Lint with **Ruff** β Run **pytest** (307 tests) β Upload failure logs |
|
| 402 |
| **ML Training** (`train.yml`) | Push to `main` | Train churn models β Log to DagsHub MLflow β Post **CML report** as PR comment with metrics |
|
| 403 |
| **HF Deploy** (`hf_deploy.yml`) | Push to `main` | Sync entire repo to Hugging Face Space β Triggers Docker rebuild β Live in ~2 min |
|
| 404 |
|
|
|
|
| 629 |
| **Auth** | PyJWT (HS256), RBAC, Supabase Row-Level Security |
|
| 630 |
| **Event Streaming** | Redpanda (Kafka-compatible, no JVM, no ZooKeeper) |
|
| 631 |
| **Object Storage** | MinIO (local S3), DagsHub DVC remote (cloud) |
|
| 632 |
+
| **Caching** | Redis / Upstash Redis β L1 exact cache + L2 semantic cache (cosine similarity > 0.92) |
|
| 633 |
| **Observability** | Prometheus, Grafana, OpenTelemetry Collector, Langfuse |
|
| 634 |
| **Infrastructure** | Docker, Docker Compose, Kubernetes (Kind), Hugging Face Spaces |
|
| 635 |
| **CI/CD** | GitHub Actions, CML (Continuous Machine Learning), Ruff (linter) |
|
| 636 |
| **Data Transforms** | dbt (DuckDB adapter) β 8 Gold mart models |
|
| 637 |
+
| **Security** | AES-256-GCM encryption, Constitutional AI (8-rule safety engine), frontend RBAC enforcement |
|
| 638 |
+
| **Secrets** | Doppler (cloud secrets manager), Hugging Face Space Secrets |
|
| 639 |
| **Logging** | structlog (structured JSON logs) |
|
| 640 |
|
| 641 |
---
|
|
|
|
| 704 |
| **UTF-8 encoding on Windows** | Python on Windows defaults to CP1252 β MLflow logging fails with emoji/special chars | Set `PYTHONIOENCODING=utf-8` and use `python -X utf8` flag |
|
| 705 |
| **CML reports on every push** | ML training workflow triggers even on README changes | Accepted trade-off: ensures model registry is always in sync. Can be scoped to `src/ml/**` paths if needed |
|
| 706 |
| **Database schema drift** | New columns added in code but HF Space container has old schema | Added `migrations.py` that runs `ALTER TABLE ADD COLUMN IF NOT EXISTS` on every startup |
|
| 707 |
+
| **Supabase direct port 5432 blocked in cloud** | IPv6-only resolution on direct PostgreSQL connections times out on HF Spaces (IPv4 only) | Switched migrations to Supabase **Connection Pooler** on port `6543` β IPv4-compatible, stable in all cloud environments |
|
| 708 |
+
| **Ollama unavailable in cloud containers** | HF Spaces don't ship with Ollama β local model calls time out after several seconds | `LLMClient` detects `SPACE_ID` / `APP_ENV=production` at startup and transparently redirects local tier calls to `openrouter/google/gemini-2.5-flash` |
|
| 709 |
+
| **Stale HITL data persists after role switch** | Switching from `manager` to `support_agent` in the demo left previously fetched review rows visible | Added an immediate role guard in `generateToken()` that clears the HITL table and shows an "Access Denied" banner the instant the role changes to `support_agent` |
|
| 710 |
+
| **Misleading DB timeout error messages** | When Supabase was unreachable, the UI catch block printed "Ensure role is manager" β wrong root cause | Updated catch blocks to distinguish `NetworkError` / `ENOTFOUND` from auth errors and display an accurate "Database unreachable" message with guidance |
|
| 711 |
|
| 712 |
---
|
| 713 |
|