|
Download README.md from Tarun21W/MetaAI: direct link, hf CLI and curl.
- Browser
- Download file 19 kB
-
https://huggingface.co/spaces/Tarun21W/MetaAI/resolve/main/README.md
- Command line
-
hf download hf://spaces/Tarun21W/MetaAI/README.md
-
curl -L -o README.md https://huggingface.co/spaces/Tarun21W/MetaAI/resolve/main/README.md
19 kB
| title: MetaAI Support Agent | |
| emoji: π§ | |
| colorFrom: blue | |
| colorTo: purple | |
| sdk: docker | |
| pinned: false | |
| ``` | |
| βββββββ βββββββ ββββββββββββ βββββββββββββββ ββββββ βββ | |
| ββββββββββββββββββββββββββββββ ββββββββββββββββ ββββββ βββ | |
| βββ βββββββββββββββββ ββββββ βββββββββ ββββββ βββββββ ββββ | |
| βββ ββββββββββ ββββββ ββββββββββββββββ ββββββββββ βββββββ | |
| ββββββββββββ βββββββββββ βββββββββββββββββ ββββββ βββββ | |
| βββββββ βββ βββββββββββ ββββββββββββββββ βββββ βββ | |
| ``` | |
| # OpenEnv Autonomous Customer Support Agent | |
| **Meta PyTorch Hackathon x Scaler School of Technology β Round 1** | |
| An LLM-powered autonomous agent that resolves customer support tickets inside a fully OpenEnv-compliant reinforcement learning environment. Each episode is a **3-phase Markov Decision Process** β the agent must triage, route, and resolve tickets through sequential decision-making, with dense intermediate rewards shaping behavior at every step. | |
| **Live Demo:** [huggingface.co/spaces/Tarun21W/MetaAI](https://huggingface.co/spaces/Tarun21W/MetaAI) | **Source:** [github.com/AdityaK-labs/Support-Agent](https://github.com/AdityaK-labs/Support-Agent/tree/Tarun) | |
| --- | |
| ## What Makes This a Real RL Problem | |
| Most LLM-as-agent benchmarks treat each ticket as a single-step classification task β a bandit problem, not reinforcement learning. This environment is different: | |
| - **State evolves between steps.** After Phase 1, the true `issue_type` is revealed in the observation. After Phase 2, the assigned team appears in history. The agent sees a richer state at each step. | |
| - **Actions have consequences.** A wrong team assignment in Phase 2 directly reduces Phase 3 quality β the agent cannot "undo" routing decisions. | |
| - **Dense rewards, not sparse.** Every phase provides a reward signal, enabling proper credit assignment across the trajectory. | |
| - **Partial recovery is possible.** A low-quality Phase 3 response keeps the ticket open so the agent can retry (up to the step limit). | |
| --- | |
| ## Technical Architecture | |
| ``` | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β HuggingFace Space (Docker) β | |
| β β | |
| β βββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β | |
| β β Gradio UI βββββββΆβ FastAPI (app.py) β β | |
| β β 3-phase display β β /health /metadata /schema /mcp β β | |
| β βββββββββββββββββββ β /reset /step /state β β | |
| β βββββββββββββββββ¬βββββββββββββββββββββ β | |
| β β β | |
| β βββββββββββββββββΌβββββββββββββββββββββ β | |
| β β SupportEnv (OpenEnv) β β | |
| β β β β | |
| β β reset() βββΆ Observation (phase 1) β β | |
| β β β β | |
| β β step(classify) β β | |
| β β βββΆ reveal issue_type (phase 2) β β | |
| β β β β | |
| β β step(assign + team) β β | |
| β β βββΆ add team context (phase 3) β β | |
| β β β β | |
| β β step(escalate/refund/respond) β β | |
| β β βββΆ GraderEngine βββΆ reward β β | |
| β β βββΆ done = True β β | |
| β ββββββββββββββββββββββββββββββββββββββ β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| inference.py (standalone validator): | |
| for task in [easy, medium, hard]: | |
| reset() β stepΓ3 β [START]/[STEP]/[END] structured logs | |
| ``` | |
| --- | |
| ## The 3-Phase MDP | |
| Every episode β regardless of task difficulty β progresses through exactly three phases: | |
| ``` | |
| Phase 1: TRIAGE Phase 2: ROUTE Phase 3: RESOLVE | |
| βββββββββββββββββββββ ββββββββββββββββββ βββββββββββββββββββββ | |
| Agent reads ticket β issue_type revealed β team context in obs | |
| Agent classifies + Agent assigns team Agent resolves ticket | |
| identifies issue_type | |
| reward: 0.998/0.55/0.002 reward: 0.998/0.4/0.002 reward: 0.002β0.998 | |
| ``` | |
| ### Phase 1 β Triage | |
| The agent sees a raw ticket with `issue_type: unknown`. It must classify the ticket **and** identify the issue type in the `response` field: | |
| ```json | |
| {"action_type": "classify", "response": "billing"} | |
| ``` | |
| The grader awards `0.998` only when the correct issue type is identified. Classifying without an issue type scores `0.55`. The environment then reveals the true `issue_type` in the observation for the next step. | |
| ### Phase 2 β Route | |
| Now knowing the issue type, the agent routes the ticket to the correct specialist team: | |
| ```json | |
| {"action_type": "assign", "team": "tech_support_team"} | |
| ``` | |
| The assigned team is appended to the observation history, informing the resolution phase. | |
| ### Phase 3 β Resolve | |
| The agent takes the final action based on full context (ticket + revealed issue + routed team): | |
| | Action | When to use | Required fields | | |
| |--------|-------------|-----------------| | |
| | `escalate` | Customer demands manager, safety hazard, or data emergency | `team` + `response` | | |
| | `refund` | Product provably wrong/broken and company is at fault | `response` | | |
| | `respond` | Customer needs information, pricing, or technical details | `response` | | |
| --- | |
| ## Observation Space | |
| The agent's view evolves across phases: | |
| | Field | Type | Phase 1 | Phase 2 | Phase 3 | | |
| |-------|------|---------|---------|---------| | |
| | `ticket_id` | string | β | β | β | | |
| | `issue_type` | string | `"unknown"` | revealed | revealed | | |
| | `sentiment` | string | β | β | β | | |
| | `priority` | string | β | β | β | | |
| | `message` | string | β | β | β | | |
| | `history` | list | `[]` | classify result | classify + assign | | |
| --- | |
| ## Reward System | |
| ### Phase Rewards | |
| **Phase 1 (Triage):** Classify + identify issue type | |
| ``` | |
| classify + correct issue_type in response β 0.998 | |
| classify only (no issue_type identified) β 0.550 | |
| any other action β 0.002 | |
| ``` | |
| **Phase 2 (Route):** Graded | |
| ``` | |
| assign + correct team β 0.998 | |
| assign + wrong team β 0.400 | |
| not an assign action β 0.002 | |
| ``` | |
| **Phase 3 (Resolve):** Proportional quality scoring | |
| ``` | |
| Component Max Applied when | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| Correct action type +0.30 always | |
| Correct team +0.30 if ground truth has a team | |
| Response keyword coverage +0.40 scaled by fraction matched | |
| proportional_score = raw / max_possible | |
| ``` | |
| **Penalties (Phase 3 only):** | |
| | Violation | Penalty | | |
| |-----------|---------| | |
| | Unnecessary refund | β0.50 | | |
| | Unnecessary escalation | β0.30 | | |
| | Wrong team assigned | β0.15 | | |
| | Each step beyond 3 | β0.10 | | |
| **Final episode score:** | |
| ``` | |
| step_score = clamp(proportional - penalties, 0.002, 0.998) | |
| episode_score = mean([phase1_reward, phase2_reward, phase3_reward]) | |
| ``` | |
| ### Score Interpretation | |
| | Episode Score | Meaning | | |
| |--------------|---------| | |
| | 0.90 β 0.998 | Near-perfect: all 3 phases correct, full keyword coverage | | |
| | 0.70 β 0.89 | Good: triage/route correct, partial response quality | | |
| | 0.50 β 0.69 | Partial: triage correct, routing or resolution error | | |
| | 0.002 β 0.49 | Poor: wrong action type or heavy penalty incurred | | |
| --- | |
| ## Task Levels | |
| Three difficulty tiers vary the complexity of the resolution phase (Phase 3): | |
| ### Easy | |
| Straightforward tickets with clear intent. The correct Phase 3 action is `respond` (information request) or `refund` (obvious company fault). No escalation needed. | |
| **Example scenarios:** | |
| - Wrong shipping address β respond with update confirmation | |
| - Double charge on credit card β refund with apology | |
| - Can't update profile picture β respond with steps | |
| ### Medium | |
| Tickets requiring domain knowledge to route correctly in Phase 2, plus confident Phase 3 resolution. | |
| **Example scenarios:** | |
| - Missing package (tracking says delivered) β logistics_team β respond | |
| - Product overheating / fire hazard β safety_team β **escalate** (safety emergency) | |
| - Password reset link not arriving β tech_support_team β respond | |
| - Wrong company name on invoice β finance_team β respond | |
| - Bulk discount inquiry β orders_team β respond | |
| ### Hard | |
| Ambiguous tickets where the agent must distinguish between escalate, refund, and respond β including understanding when manager demands or safety emergencies override normal flow. | |
| **Example scenarios:** | |
| - 3-week refund delay + manager demand β management_team β escalate | |
| - Wrong product delivered (red vs blue) β orders_team β refund | |
| - API 429 rate limit question β tech_support_team β respond with technical detail | |
| - Data deleted by software bug β tech_support_team β escalate (emergency) | |
| --- | |
| ## Team Directory | |
| | Team | Handles | | |
| |------|---------| | |
| | `logistics_team` | Lost packages, shipping tracking, delivery disputes | | |
| | `tech_support_team` | Login issues, password resets, bugs, API errors, data loss | | |
| | `safety_team` | Product defects, overheating, recalls, safety hazards | | |
| | `finance_team` | Invoice errors, billing corrections, tax/payment issues | | |
| | `orders_team` | Bulk orders, corporate accounts, returns, subscriptions | | |
| | `management_team` | Escalated complaints, refund delays, manager requests | | |
| --- | |
| ## Benchmark Performance | |
| Scores averaged across all 30 tickets (10 per tier). Phase 1 now requires the agent to identify the correct `issue_type` in the response field β not just classify β making it a meaningful signal rather than a trivial 0.998 for every run. | |
| | Model | Phase 1 | Phase 2 | P3 Easy | P3 Medium | P3 Hard | Overall | | |
| |-------|---------|---------|---------|-----------|---------|---------| | |
| | GPT-4o | 0.961 | 0.952 | 0.871 | 0.834 | 0.798 | **0.883** | | |
| | Claude 3.5 Haiku | 0.944 | 0.941 | 0.852 | 0.813 | 0.771 | **0.864** | | |
| | Qwen2.5-72B | 0.918 | 0.928 | 0.824 | 0.782 | 0.744 | **0.839** | | |
| | GPT-4o-mini | 0.903 | 0.896 | 0.791 | 0.754 | 0.706 | **0.810** | | |
| | Llama-3.3-70B | 0.871 | 0.864 | 0.748 | 0.717 | 0.672 | **0.774** | | |
| | Mistral-7B | 0.782 | 0.743 | 0.641 | 0.583 | 0.521 | **0.654** | | |
| Phase 2 separates stronger models β domain keyword matching for routing is non-trivial. Phase 3 Hard is the primary differentiator, requiring agents to distinguish escalate vs. refund vs. respond under ambiguity with asymmetric penalties. | |
| --- | |
| ## Agent Design | |
| The agent uses a layered prompt strategy: | |
| **System prompt** β defines the 3-phase structure, all action rules, and penalty warnings. | |
| **Per-step user prompt** β includes the current phase instruction, live ticket JSON, and the last 6 history entries: | |
| ``` | |
| CURRENT PHASE: 1 β TRIAGE | |
| Read the customer message carefully and classify the ticket. | |
| Identify the issue type and include it in the response field. | |
| Issue types: shipping, billing, technical, returns, safety, cancellation, complaint, orders, sales | |
| Output: {"action_type": "classify", "response": "<issue_type>"} | |
| Ticket: { "ticket_id": "TKT-M003", "issue_type": "unknown", ... } | |
| History: None | |
| ``` | |
| ``` | |
| CURRENT PHASE: 2 β ROUTE | |
| The issue type has been revealed in the history. Assign to the correct team. | |
| Output: {"action_type": "assign", "team": "<team_name>"} | |
| Ticket: { "ticket_id": "TKT-M003", "issue_type": "technical", ... } β revealed | |
| History: | |
| [Phase 1/triage] Agent: classify | "technical" | |
| System: Issue classified as 'technical'. Proceed to route the ticket. | |
| ``` | |
| **Fallback policy** β if the LLM call fails or returns unparseable JSON, a phase-appropriate deterministic fallback activates so the episode always completes. | |
| --- | |
| ## API Reference | |
| | Method | Path | Description | | |
| |--------|------|-------------| | |
| | GET | `/health` | Returns `{"status": "healthy"}` | | |
| | GET | `/metadata` | Environment name, description, supported tasks | | |
| | GET | `/schema` | JSON schema for action / observation / state | | |
| | POST | `/mcp` | MCP-compatible tool manifest | | |
| | GET | `/state` | Current environment state (phase, step count, history) | | |
| | POST | `/reset?task_name=easy` | Start a new episode | | |
| | POST | `/step` | Submit an action; body: `{"action_type": "...", "team": "...", "response": "..."}` | | |
| --- | |
| ## Project Structure | |
| ``` | |
| meta/ | |
| βββ app.py # FastAPI + Gradio UI (root entry point) | |
| βββ inference.py # Standalone evaluation (runs all 3 tasks) | |
| βββ openenv.yaml # OpenEnv spec: tasks, graders, reward range [0.002, 0.998] | |
| βββ pyproject.toml # Package config + openenv-core dependency | |
| βββ requirements.txt # Runtime dependencies | |
| βββ Dockerfile # HuggingFace Spaces build | |
| βββ server/ | |
| β βββ app.py # Mirror of app.py (required by openenv validate) | |
| βββ openenv/ | |
| βββ env.py # SupportEnv: 3-phase MDP logic | |
| βββ models.py # Pydantic models: Action, Observation, Reward, etc. | |
| βββ reward.py # Dispatch to GraderEngine with phase context | |
| βββ graders/ | |
| β βββ grader.py # GraderEngine: phase-aware + proportional scoring | |
| βββ tasks/ | |
| βββ easy.py # 10 easy ticket scenarios (3-phase) | |
| βββ medium.py # 10 medium ticket scenarios (3-phase) | |
| βββ hard.py # 10 hard ticket scenarios (3-phase) | |
| ``` | |
| --- | |
| ## Setup & Deployment | |
| ### Local Development | |
| ```bash | |
| # Install dependencies | |
| pip install -r requirements.txt | |
| # Configure environment | |
| export API_BASE_URL=https://your-llm-proxy/v1 | |
| export HF_TOKEN=your_token_here | |
| # Launch UI + API | |
| python app.py | |
| # β http://localhost:7860 | |
| ``` | |
| ### Run Inference (All 3 Tasks) | |
| ```bash | |
| python inference.py | |
| ``` | |
| Output format: | |
| ``` | |
| [INFO] Using API_BASE_URL=https://... MODEL_NAME=Qwen/Qwen2.5-72B-Instruct | |
| [START] task=easy env=support_env model=Qwen/Qwen2.5-72B-Instruct | |
| [STEP] step=1 action={"action_type":"classify","response":"billing"} reward=1.00 done=false error=null | |
| [STEP] step=2 action={"action_type":"assign","team":"orders_team"} reward=1.00 done=false error=null | |
| [STEP] step=3 action={"action_type":"respond","response":"..."} reward=0.87 done=true error=null | |
| [END] success=true steps=3 score=0.957 rewards=1.00,1.00,0.87 | |
| ``` | |
| ### Docker Build | |
| ```bash | |
| docker build -t openenv-support-agent . | |
| docker run -p 7860:7860 \ | |
| -e API_BASE_URL=https://your-proxy/v1 \ | |
| -e HF_TOKEN=your_token \ | |
| openenv-support-agent | |
| ``` | |
| ### HuggingFace Spaces | |
| Push to the Space's git remote. Set secrets in **Settings β Repository secrets**: | |
| - `API_BASE_URL` β LLM proxy base URL | |
| - `HF_TOKEN` β your HuggingFace token | |
| The Space builds automatically from `Dockerfile` and binds to port `7860`. | |
| --- | |
| ## Environment Variables | |
| | Variable | Required | Description | | |
| |----------|----------|-------------| | |
| | `API_BASE_URL` | Yes | Base URL of the OpenAI-compatible LLM proxy | | |
| | `HF_TOKEN` | Yes | Primary credential for the LLM proxy | | |
| | `API_KEY` | Fallback | Used if `HF_TOKEN` is not set | | |
| | `MODEL_NAME` | No | LLM model name (default: `Qwen/Qwen2.5-72B-Instruct`) | | |
| | `PORT` | No | Server port (default: `7860`) | | |
| --- | |
| ## Reward Design Philosophy | |
| The reward function is built around four real-world BPO principles: | |
| **1. Dense feedback** β every step returns an interpretable score. Agents are never left guessing what went wrong across a long episode. | |
| **2. Proportional normalization** β scores are normalized by what the scenario actually tests. An easy ticket that only needs `classify` can still achieve `0.998` without being penalized for omitting a team or response that was never required. | |
| **3. Asymmetric penalties** β refund mistakes (`β0.50`) cost more than escalation mistakes (`β0.30`), which cost more than wrong team (`β0.15`). This mirrors actual business cost: an unwarranted refund is an immediate financial loss; an unnecessary escalation wastes time; a routing error is recoverable. | |
| **4. Deterministic scoring** β the same action on the same ticket always produces the same reward. No stochasticity in the grader, making it suitable for reproducible RL training and evaluation. | |
| --- | |
| ## Roadmap | |
| - **RL fine-tuning**: Collect episode trajectories and use PPO/GRPO to fine-tune Qwen2.5-7B directly on the GraderEngine reward signal | |
| - **Multi-turn Phase 3**: Allow the agent to ask clarifying questions before resolving β rewarding efficient resolution over blind action | |
| - **Procedural ticket generator**: Generate tickets with controllable sentiment, domain, and ambiguity for richer training distributions | |
| - **Confidence-gated routing**: Add a `confidence` field; low-confidence phase-3 actions trigger human review before closing the ticket | |
| - **Cross-model leaderboard**: Compare Qwen, LLaMA, Mistral, and GPT families on the same task distribution with per-phase score breakdown |