Spaces:
Sleeping
Sleeping
| """ | |
| Nimbus Bank Triage β Classifier Agent | |
| Reads the sanitized ticket and produces a structured classification: | |
| category, urgency, sentiment, confidence, and reasoning. | |
| Uses Claude Haiku at temperature 0.0 for deterministic results. | |
| """ | |
| import os | |
| from typing import Literal | |
| from langchain_core.messages import SystemMessage, HumanMessage | |
| from pydantic import BaseModel, Field | |
| from src.utils.models import get_fast_llm, invoke_structured_with_retry | |
| # ββ Load classifier prompt βββββββββββββββββββββββββββββββββββ | |
| _PROMPT_PATH = os.path.join( | |
| os.path.dirname(os.path.dirname(__file__)), "prompts", "classifier.md" | |
| ) | |
| with open(_PROMPT_PATH, "r", encoding="utf-8") as f: | |
| CLASSIFIER_SYSTEM_PROMPT = f.read() | |
| # Confidence threshold β below this, ticket is flagged for human triage | |
| CONFIDENCE_THRESHOLD = int(os.environ.get("CLASSIFIER_CONFIDENCE_THRESHOLD", "70")) | |
| # ββ Structured output schema ββββββββββββββββββββββββββββββββ | |
| class ClassificationResult(BaseModel): | |
| category: Literal["Fraud", "Dispute", "Access_Issue", "Inquiry"] = Field( | |
| description="Ticket category" | |
| ) | |
| urgency: Literal["Critical", "High", "Medium", "Low"] = Field( | |
| description="Urgency level" | |
| ) | |
| sentiment: Literal["Angry", "Distressed", "Neutral", "Positive"] = Field( | |
| description="Customer sentiment" | |
| ) | |
| confidence: int = Field(ge=0, le=100, description="Classification confidence 0-100") | |
| reasoning: str = Field(description="Short explanation for the audit log") | |
| def classify_ticket(state: dict) -> dict: | |
| """ | |
| Classifier Agent node function. | |
| Reads the wrapped payload from state and produces a structured | |
| classification with category, urgency, sentiment, and confidence. | |
| Args: | |
| state: Current TriageState dict | |
| Returns: | |
| Partial state update with classification fields. | |
| """ | |
| wrapped_payload = state.get("wrapped_payload", "") | |
| errors = list(state.get("errors", [])) | |
| try: | |
| llm = get_fast_llm() | |
| result = invoke_structured_with_retry( | |
| llm=llm, | |
| messages=[ | |
| SystemMessage(content=CLASSIFIER_SYSTEM_PROMPT), | |
| HumanMessage(content=f"Classify this support ticket:\n\n{wrapped_payload}"), | |
| ], | |
| schema=ClassificationResult, | |
| ) | |
| return { | |
| "category": result["category"], | |
| "urgency": result["urgency"], | |
| "sentiment": result["sentiment"], | |
| "classifier_confidence": result["confidence"], | |
| "classifier_reasoning": result["reasoning"], | |
| "errors": errors, | |
| } | |
| except Exception as e: | |
| # Classification failure β low confidence forces human triage | |
| errors.append(f"classifier_error: {type(e).__name__}: {e}") | |
| return { | |
| "category": "Inquiry", | |
| "urgency": "High", | |
| "sentiment": "Neutral", | |
| "classifier_confidence": 0, | |
| "classifier_reasoning": f"Classification failed: {type(e).__name__}", | |
| "errors": errors, | |
| } | |