# Chatbot Core — Kiến trúc vận hành

> **Tóm tắt:** Tài liệu này giải thích cách Canifa Chatbot hoạt động "bên trong" — từ lúc nhận tin nhắn, qua LangGraph StateGraph, đến khi trả response cuối cùng. Bao gồm: cơ chế chống bịa (Guardrails), API cho n8n automation, và chiến lược quản lý Context Window.

---

## 1. Chatbot Core là gì?

Chatbot Core là **trái tim runtime** — module chạy 24/7, nhận mọi tin nhắn từ khách hàng và điều phối toàn bộ pipeline xử lý.

| Thành phần | Vai trò | Công nghệ |
|-----------|--------|-----------|
| **StateGraph** | Đồ thị trạng thái, điều phối luồng | LangGraph (Python) |
| **Classifier Node** | Phân loại ý định, xuất JSON params | Gemini Flash / GPT-4o-mini |
| **Stylist Node** | Viết câu trả lời, cập nhật Insight | Claude Sonnet / GPT-4o |
| **Tool Layer** | Thực thi search, stock, RAG | Python functions |
| **n8n API Layer** | Endpoint cho workflow automation | FastAPI `/api/agent/n8n/*` |

### Tại sao không dùng ReAct Loop?

Nhiều framework AI agent dùng ReAct (Reason → Act → Observe → loop) — nhưng Canifa **chủ đích không dùng**:

| | ReAct Loop | Canifa Pipeline |
|---|---|---|
| **Vòng lặp** | Agent tự quyết định chạy bao nhiêu vòng | Cố định 3 bước: Classify → Tool → Style |
| **Latency** | 3-10s (phụ thuộc số vòng) | ~1.2s (cố định) |
| **Hallucination** | Agent có thể "mơ" rồi tự chạy tool sai | Classifier bị ép JSON schema cứng |
| **Chi phí** | Nhiều API call không kiểm soát | Tối đa 2 API calls |
| **Debug** | Khó trace vì vòng lặp không đoán trước | Dễ debug vì 3 bước cố định |

> **Quyết định thiết kế:** Đánh đổi flexibility (ReAct) lấy predictability + speed. Với bài toán bán hàng thời trang, khách cần trả lời nhanh hơn là cần AI "suy nghĩ sâu".

---

## 2. Luồng dữ liệu — Từ tin nhắn đến response

### State Object

Mọi dữ liệu trong 1 turn chat được gom vào `LeadStageState`:

```python
class LeadStageState(TypedDict):
    messages: list          # Lịch sử chat (5 tin gần nhất)
    user_insight: str       # InsightJSON (12 trường) từ Redis
    tool_result: str        # Kết quả tool (JSON sản phẩm)
    diagnostics: dict       # Timing, trace, error info
```

### Pipeline 3 bước cố định

```
                        ┌─ tool_name != null ─→ [Tool Layer] ─┐
Tin nhắn → [Classifier] ─┤                                    ├→ [Stylist] → Response
                        └─ tool_name == null  ─────────────────┘ (Early Exit)
```

| Bước | Node | Input | Output | Thời gian |
|------|------|-------|--------|-----------|
| 1 | **Classifier** | messages + user_insight | `ClassifierOutput` (JSON) | ~50ms |
| 2 | **Tool Layer** | JSON params từ Classifier | Danh sách sản phẩm / thông tin | ~200ms |
| 3 | **Stylist** | messages + tool_result + insight | `ai_response` + updated insight | ~800ms |

### Conditional Edge: Early Exit

Khi Classifier nhận diện câu chào hỏi / tán gẫu → `tool_name = null` → **bỏ qua Tool + Stylist** → trả lời ngay từ Classifier. Tiết kiệm ~800ms + 1 API call.

---

## 3. Guardrails — Cơ chế chống bịa

### 3.1. Dual-Lane Search Args

Classifier bị ép xuất ra **2 object riêng biệt** để chống AI tự biên:

| Lane | Ý nghĩa | Ví dụ |
|------|---------|-------|
| **LiteralSearchArgs** | Câu nguyên văn từ khách, KHÔNG được sửa | `"áo khoác phao nam mã AK123"` |
| **InferredSearchArgs** | Các filter AI tự suy luận | `{gender: "Nam", tags: ["Giữ ấm"], color: ["Đen"]}` |

**Tại sao tách 2 lane?** Vì AI đôi khi "sáng tạo" quá mức — biến "áo khoác phao" thành "áo ấm mùa đông lông vũ". Lane Literal giữ nguyên bản gốc làm anchor cho search.

### 3.2. Insight Injection

Thay vì nhồi toàn bộ chat history vào prompt (tốn token), hệ thống dùng **InsightJSON** — bản tóm tắt 12 trường:

```
STAGE=CONSIDERING | GOAL=Áo đi Sapa | CONSTRAINS=<500k | TARGET=Cho bản thân
```

Stylist nhận InsightJSON → biết ngay khách đang ở mode nào, muốn gì → không cần đọc lại 20 tin nhắn cũ.

### 3.3. Deduplication

Khi nhiều tool trả về kết quả trùng SKU → lọc trùng trước khi inject vào Stylist prompt → tiết kiệm Context Window.

### 3.4. Strict Fallback

```python
try:
    response = stylist_chain.invoke(state)
except Exception:
    response = "Dạ bạn cho mình hỏi thêm để tư vấn chính xác hơn nhé!"
```

Không bao giờ để HTTP 500 lọt ra FE. Mọi lỗi đều có fallback.

---

## 4. n8n API Layer — Workflow Automation

Ngoài chatbot, hệ thống cung cấp **REST API** cho n8n (tool automation) gọi vào:

| Endpoint | Mô tả | Use case |
|----------|-------|----------|
| `POST /api/agent/n8n/product-search` | Tìm sản phẩm theo filter | n8n workflow tự động gửi KM |
| `POST /api/agent/n8n/stock-check` | Kiểm tra tồn kho SKU | Alert khi sắp hết hàng |
| `POST /api/agent/n8n/knowledge-search` | RAG search knowledge base | FAQ automation |
| `POST /api/agent/n8n/store-search` | Tìm cửa hàng theo vị trí | Gợi ý cửa hàng gần nhất |

### Tại sao cần API riêng cho n8n?

Chatbot API yêu cầu auth + device_id + chat history → quá nặng cho automation. API n8n là phiên bản nhẹ, nhận filter thuần tuý → trả kết quả thuần tuý, không qua AI.

---

## 5. Context Window Strategy

LLM có giới hạn context (128K tokens cho GPT-4o, 200K cho Claude). Chiến lược quản lý:

| Kỹ thuật | Áp dụng | Hiệu quả |
|---------|---------|----------|
| **Message Trimming** | Chỉ giữ 5 tin gần nhất | Giảm ~80% tokens |
| **InsightJSON thay history** | 12 trường thay vì 20+ tin | Giảm ~70% tokens |
| **Product Dedup** | Lọc SKU trùng | Giảm ~30% product tokens |
| **Lazy Tool** | Chỉ gọi tool khi cần | Giảm prompt size 50% cho câu chào hỏi |

---

## 6. Troubleshooting & Gotchas

| Vấn đề | Nguyên nhân | Fix |
|--------|-------------|-----|
| Bot trả lời "Em không tìm thấy" dù có hàng | Classifier extract sai tags → search miss | Check log `[CLASSIFIER]` xem JSON output |
| Bot chậm >5s | Stylist model quá nặng hoặc tool timeout | Check Langfuse trace: `classifier_ms` vs `stylist_ms` |
| Bot bịa sản phẩm không tồn tại | Enrichment layer bị skip | Verify `post_process_products()` chạy sau Stylist |
| InsightJSON bị reset | Redis key expired (TTL 24h) | Check `lead_insight:{device_id}` trong Redis |
| n8n API trả 401 | Token hết hạn | Refresh API key trong n8n credentials |

---

## References

1. LangGraph Documentation — *"StateGraph: Deterministic Agent Pipelines"*
2. Canifa Engineering — `backend/agent/lead_stage_agent/graph.py`
3. n8n Official — *"Webhook Trigger + HTTP Request Node"*
