# Kiến trúc Dual-Agent (Classifier + Stylist)

Hệ thống Lead Search không dùng 1 Agent nguyên khối mà chia làm 2 Agent phối hợp: **Classifier** (phân loại ý định) và **Stylist** (sinh ngôn ngữ chốt sale). Thiết kế này giúp tiết kiệm chi phí LLM và giảm latency.

## Luồng xử lý chi tiết (Sequence Diagram)

```mermaid
sequenceDiagram
    autonumber
    participant User as User Chat
    participant Ctrl as Controller
    participant CLS as Classifier Agent
    participant Tool as ProductSearchEngine
    participant STY as Stylist Agent
    participant Redis as Redis Cache

    User->>Ctrl: Gửi tin nhắn
    Ctrl->>Redis: Load InsightJSON (device_id)
    Redis-->>Ctrl: Trả về InsightJSON cũ + chat_history
    Ctrl->>CLS: Truyền message + InsightJSON + history

    alt Khách chỉ chào hỏi (Early Exit)
        CLS-->>STY: tool_name = null, pass trực tiếp
    else Khách tìm sản phẩm
        CLS->>Tool: tool_name = lead_search_tool + Split Query Args
        Tool->>Tool: Cascading Search 7 tầng (StarRocks)
        Tool->>Tool: Check Stock (Canifa API)
        Tool->>Tool: Enrich Outfit (SQLite ai_matches)
        Tool-->>STY: Danh sách sản phẩm có stock + outfit context
    end

    STY->>STY: Sinh AI Response (max 200 từ) + Update InsightJSON
    STY-->>Ctrl: StylistOutput (ai_response, product_ids, user_insight)
    Ctrl->>Redis: Lưu InsightJSON mới (TTL 24h)
    Ctrl-->>User: Trả về câu trả lời + link sản phẩm
```

## Classifier Agent (AI Nhẹ — Router)

Classifier đóng vai trò Lễ tân, chuyên trách phân loại ý định khách hàng.

| Thuộc tính | Chi tiết |
|---|---|
| **Model** | LLM nhẹ, output Structured JSON |
| **Input** | message + InsightJSON + chat_history_summary |
| **Output** | `ClassifierOutput(reasoning, tool_name, lead_search_args, ai_response)` |
| **Nhiệm vụ chính** | Xác định khách ở Mode nào (1-5), quyết định gọi Tool hay Early Exit |
| **File** | `graph.py` — hàm `_classifier_node()` |

**Early Exit:** Khi khách chỉ chào hỏi (Mode 1), Classifier bypass Tool và pass thẳng cho Stylist. Tiết kiệm latency và cost vì không cần query Database.

### ClassifierOutput Schema

```python
class ClassifierOutput(BaseModel):
    reasoning: str                          # Lý luận gọi tool hay trả lời trực tiếp
    tool_name: str | None                   # "lead_search_tool" hoặc null (Early Exit)
    lead_search_args: ClassifierLeadSearchArgs | None  # Args cho search tool
    ai_response: str | None                 # Câu trả lời khi Early Exit
    product_ids: list[str] | None           # Mã SKU nếu khách hỏi trúng mã
```

## Stylist Agent (AI Nặng — Best Seller)

Stylist đóng vai trò chốt sale, nhận data sản phẩm từ Tool và sinh câu trả lời thuyết phục.

| Thuộc tính | Chi tiết |
|---|---|
| **Model** | LLM lớn, nặng |
| **Input** | Tool results + InsightJSON + STAGE + tone_directive |
| **Output** | `StylistOutput(ai_response, product_ids, user_insight)` |
| **Nhiệm vụ chính** | Sinh câu trả lời tư vấn, gợi ý combo phối đồ, cập nhật InsightJSON |
| **File** | `graph.py` — hàm `_stylist_node()` |

### Guardrails (Rào chắn)

Stylist bị ràng buộc bởi `STYLIST_SYSTEM_PROMPT` trong `prompts.py`:

- Không tự ý đề cập giảm giá nếu không có trong data
- Không chèo kéo ở Mode 5 (Retention)
- Không quăng list sản phẩm ở Mode 1 (Browse)
- Tối đa 200 từ mỗi response
- Ưu tiên gợi ý combo (áo + quần + phụ kiện) thay vì chỉ 1 sản phẩm

## State Management (LangGraph StateGraph)

Toàn bộ luồng được quản lý bởi **LangGraph StateGraph**. State chứa:

```python
class LeadGraphState(TypedDict):
    user_message: str
    chat_history: list[dict]
    insight_json: InsightJSON
    classifier_output: ClassifierOutput
    tool_results: list[dict]        # Kết quả từ ProductSearchEngine
    stylist_output: StylistOutput
    final_response: str
```

## Tracing và Observability

Toàn bộ quá trình được trace qua **Langfuse**. Metrics theo dõi:

| Metric | Mô tả |
|---|---|
| `classifier_ms` | Thời gian Classifier xử lý |
| `stylist_ms` | Thời gian Stylist xử lý |
| `tool_ms` | Thời gian ProductSearchEngine chạy |
| `total_ms` | Tổng thời gian end-to-end |
| `stage` | Mode hiện tại của khách |
| `tool_called` | Classifier có gọi Tool không |

File tham chiếu: `backend/agent/lead_stage_agent/graph.py`
