--- title: Customer Support OpenEnv emoji: πŸ‘½ colorFrom: blue colorTo: green sdk: docker pinned: false --- # 🎧 Customer Support OpenEnv [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue?logo=python&logoColor=white)](https://www.python.org/) [![OpenEnv](https://img.shields.io/badge/OpenEnv-compatible-brightgreen)](https://github.com/openenv) [![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97-HuggingFace%20Spaces-orange)](https://huggingface.co/spaces) [![FastAPI](https://img.shields.io/badge/FastAPI-0.100%2B-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](LICENSE) > **OpenEnv Hackathon submission** β€” a production-grade customer support simulation environment for training and evaluating LLM-based support agents. --- ## 🌍 Why This Environment? Customer support is one of the most common enterprise AI use cases, yet no standard RL/agent benchmark exists for it. This environment fills that gap: it provides a **realistic, multi-difficulty, fully graded** benchmark where agents must: - 🏷️ **Classify** support tickets into the correct category - ✍️ **Respond** empathetically and accurately to customer issues - πŸ—£οΈ **Hold multi-turn conversations** β€” clarify, resolve, and close tickets All graded automatically with clear, deterministic rubrics (0.0–1.0) and meaningful **partial rewards** on every turn. --- ## βš™οΈ How It Works β€” Workflow ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AGENT LOOP β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” POST /reset β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ ──────────────► β”‚ FastAPI Server β”‚ β”‚ β”‚ β”‚ Agent β”‚ β”‚ (server/app.py) β”‚ β”‚ β”‚ β”‚ (client) β”‚ ◄────────────── β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Observation β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ SupportEnvironment β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ POST /step β”‚ β”‚ (environment.py) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ ──────────────► β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ obs+reward β”‚ β”‚ 15 scenarios Γ— 5 types β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ ◄────────────── β”‚ β”‚ 3 graders (easy/med/hrd)β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ Cumulative reward logic β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ GET /state ──────────────► β”‚ β”‚ β”‚ β”‚ POST /grader ─────────────► β”‚ Score + turn breakdown β”‚ β”‚ β”‚ GET /tasks ──────────────► β”‚ Task list + action schemas β”‚ β”‚ β”‚ POST /baseline ───────────► β”‚ Built-in oracle agent scores β”‚ β”‚ └───────────────────────────────────────────────────────────────────-β”€β”˜ ``` **Episode lifecycle:** 1. Agent calls `POST /reset` β†’ gets the opening customer message 2. Agent sends replies via `POST /step` β†’ gets observation + reward each turn 3. Agent calls `POST /grader` β†’ gets full score breakdown with `turn_scores` 4. Episode ends when `done: true` in the observation --- ## πŸ—‚οΈ Environment Description Simulates a customer support system across **5 issue categories** with **15 unique scenarios** (3 per category): | Category | Sample Scenarios | |---|---| | **Refund** | Missing delivery refund, damaged product return, cancelled-order refund delay | | **Technical** | App crash after update, Slack webhook error, PDF export blank | | **Shipping** | 3-week missing order, wrong-door delivery, split shipment partial arrival | | **Billing** | Duplicate subscription charge, unauthorized upgrade charge, invoice ghost charge | | **Account** | Password reset email missing, account suspended, email address transfer | --- ## πŸ“₯ Action Space Each agent step submits a `SupportAction`: | Field | Type | Required | Description | |---|---|---|---| | `message` | `str` | βœ… | The agent's text reply to the customer | | `intent` | `str` | ❌ | Declared intent: `"classify"`, `"respond"`, `"clarify"`, `"escalate"`, or `"close"` | --- ## πŸ“€ Observation Space The environment returns a `SupportObservation` after each step: | Field | Type | Description | |---|---|---| | `conversation` | `List[str]` | Full message history (alternating customer / agent) | | `customer_query` | `str` | The latest customer message the agent must address | | `task_name` | `str` | Difficulty tier: `"easy"`, `"medium"`, or `"hard"` | | `done` | `bool` | Whether the episode has ended | | `reward` | `float \| None` | Step-level reward (0.0–1.0); `None` on opening observation | | `cumulative_reward` | `float` | Running average reward across all turns so far | | `turn_scores` | `List[float]` | Per-turn reward breakdown (useful for analysis) | | `info` | `str \| None` | Optional context or hints for the agent | --- ## πŸ“‹ Tasks ### 🟒 Easy β€” Ticket Classification **Objective:** Output the correct issue category for a customer message. **Scoring:** - βœ… `1.0` β€” Exact category in reply (`refund`, `billing`, etc.) - 🟑 `0.5` β€” Partial keyword match - ❌ `0.0` β€” Wrong or missing category - Max steps: **1** --- ### 🟑 Medium β€” Single-Turn Response **Objective:** Write a complete, empathetic reply resolving the customer's issue. **Scoring rubric:** | Component | Reward | |---|---| | +0.20 per matching keyword (max 4) | 0.00–0.80 | | Empathy detected (apologize/sorry/understand) | +0.10 | | Reply length > 80 chars | +0.10 | | Unnecessary escalation penalty | βˆ’0.20 | All scores clamped to `[0.0, 1.0]`. Max steps: **1** --- ### πŸ”΄ Hard β€” Multi-Turn Conversation **Objective:** Handle a 3-turn dialogue: clarify β†’ resolve β†’ close. | Turn | Behaviour | Max Reward | |---|---|---| | 1 (clarify) | Ask a `?` question (bonus if on-topic) | +0.40 | | 2 (resolve) | Keyword + empathy + detail | +0.50 | | 3 (close) | Polite closing phrase | +0.30 | `cumulative_reward = mean(turn_scores)`, clamped to `[0.0, 1.0]`. Max steps: **10** --- ## 🎯 Reward Function Design | Signal | When | Magnitude | |---|---|---| | Correct classification | Easy, step 1 | +1.0 / +0.5 / 0.0 | | Keyword coverage | Medium & Hard turn 2 | +0.20 per keyword | | Empathy language | Medium & Hard turn 2 | +0.10–+0.12 | | Response detail (length) | Medium & Hard turn 2 | +0.08–+0.10 | | Clarifying question | Hard turn 1 | +0.30 (+0.10 bonus) | | Polite close | Hard turn 3 | +0.30 | | Unnecessary escalation | Medium | βˆ’0.20 | | Exceeding max steps | All tasks | Episode terminates | **Key property:** Every turn gives a partial signal β€” agents never wait until the end to learn if they did well. --- ## πŸ”Œ API Endpoints | Method | Endpoint | Description | |---|---|---| | `GET` | `/` | Health check | | `POST` | `/reset` | Start a new episode | | `POST` | `/step` | Submit an agent action | | `GET` | `/state` | Current session internal state | | `GET` | `/tasks` | Task list with typed action schemas | | `POST` | `/grader` | Score + turn breakdown for completed episode | | `POST` | `/baseline` | Run built-in oracle agent, return average scores | --- ## πŸš€ Setup & Usage ### 1. Clone ```bash git clone https://huggingface.co/spaces/sanathkumarps/customer_support_env cd customer_support_env ``` ### 2. Install ```bash pip install -r requirements.txt ``` ### 3. Run locally ```bash uvicorn server.app:app --host 0.0.0.0 --port 7860 --reload ``` Visit `http://localhost:7860/docs` for interactive Swagger docs. ### 4. Run with Docker ```bash docker build -t customer_support_env . docker run -p 7860:7860 customer_support_env ``` ### 5. Run the baseline evaluation ```bash export GROQ_API_KEY="gsk-..." # required export ENV_BASE_URL="http://localhost:7860" # optional export GROQ_MODEL="llama-3.1-8b-instant" # optional, default: llama-3.1-8b-instant python run_baseline.py ``` Results print to console and save to `baseline_scores.json`. ### 6. Quick API test ```bash # Health check curl http://localhost:7860/ # Start easy episode curl -X POST http://localhost:7860/reset \ -H "Content-Type: application/json" \ -d '{"task_name":"easy","seed":42}' # Submit action (replace SESSION_ID) curl -X POST http://localhost:7860/step \ -H "Content-Type: application/json" \ -d '{"session_id":"SESSION_ID","message":"refund","intent":"classify"}' # Get grader score curl -X POST http://localhost:7860/grader \ -H "Content-Type: application/json" \ -d '{"session_id":"SESSION_ID"}' ``` --- ## πŸ“Š Baseline Scores | Task | Avg Score | Model | Episodes | |---|---|---|---| | Easy | 0.90 | llama-3.1-8b-instant | 5 | | Medium | 0.55 | llama-3.1-8b-instant | 5 | | Hard | 0.40 | llama-3.1-8b-instant | 5 | > Run `python run_baseline.py` after starting the server to generate fresh scores. --- ## πŸ“ Project Structure ``` customer_support_env/ β”œβ”€β”€ models.py # Pydantic models: SupportAction, SupportObservation, SupportState β”œβ”€β”€ client.py # OpenEnv typed client library β”œβ”€β”€ openenv.yaml # OpenEnv metadata manifest β”œβ”€β”€ requirements.txt # Python dependencies (groq, fastapi, uvicorn…) β”œβ”€β”€ run_baseline.py # llama-3.1-8b-instant baseline evaluation script β”œβ”€β”€ README.md # This file β”œβ”€β”€ Dockerfile # Container config for Hugging Face Spaces β”œβ”€β”€ .dockerignore # Excludes venv, __pycache__, .env from image β”œβ”€β”€ baseline_scores.json # Auto-generated baseline results └── server/ β”œβ”€β”€ __init__.py # Package marker β”œβ”€β”€ app.py # FastAPI server β€” all 7 endpoints └── environment.py # Core env: 15 scenarios, 3 graders, reward logic ``` --- ## πŸ—οΈ Architecture ``` models.py ← Pydantic contracts (Action / Observation / State) β”‚ β”œβ”€β”€ server/environment.py ← Episode logic, 15 scenarios, 3 graders β”‚ β”‚ β”‚ └── Reward signals: per-turn partial rewards + cumulative score β”‚ └── server/app.py ← FastAPI: /reset /step /state /tasks /grader /baseline β”‚ └── client.py ← Typed client for external scripts ``` --- ## πŸ“œ License MIT β€” see [LICENSE](LICENSE). ---

Built for the OpenEnv Hackathon πŸš€  |  Customer support AI benchmark that fills a real gap.