saibalajiomg commited on
Commit
7ec3930
Β·
verified Β·
1 Parent(s): 25bae15

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +42 -21
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** (not a hub-and-spoke β€” each agent passes state to the next) with conditional Human-in-the-Loop gating:
101
 
102
  ```mermaid
103
  graph LR
104
  A[πŸ“© Ticket In] --> B[🏷️ Classify]
105
  B --> C[🧠 Memory]
106
- C --> D[πŸ” RAG]
107
- D --> E[πŸ“‰ Churn]
108
- E --> F[🚨 Incident]
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 Llama for complex |
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
- | **Llama 3.1 8B** | OpenRouter (cloud API) | Complex reasoning, action-taking, high-priority |
 
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 + priority:
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 Llama (frontier) |
180
- | Action | πŸ”΅ Cloud Llama | πŸ”΅ Cloud Llama |
 
 
181
 
182
- > **Result**: ~80% of tickets are handled locally at **$0 cost** and **<200ms latency**. Only complex/high-risk tickets go to cloud.
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** β€” Review flagged tickets, approve or override AI decisions
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. "Acme Corp"). All data is isolated per tenant β€” one tenant can never see another's tickets or data |
256
- | **Role** | `support_agent` can submit tickets. `manager` can also review HITL-flagged tickets and override AI decisions |
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** (300+ tests) β†’ Upload failure logs |
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 (semantic cache + rate limiter) |
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