An AI-powered multi-agent system that operates like a smart operations manager for your online store β diagnosing issues, recommending actions, and learning from the past.
- Overview
- Problem Statement
- System Architecture
- Agent Roles & Responsibilities
- Key Features
- Tech Stack
- Project Structure
- Getting Started
- Usage Examples
- Dashboard Notes
- Core Scenarios
- Tool Catalog
- Memory System
- Human-in-the-Loop (HITL)
- Observability & Logging
- Evaluation & Testing
- Roadmap
- Contributing
- License
The E-commerce Operations Brain is a multi-agent AI system designed to simulate an intelligent operations team for an online store. Instead of querying a single dashboard, a business user can ask natural-language questions and receive:
- π Root cause analysis across multiple business domains
- π Actionable recommendations with reasoning
- β Safe execution β actions only happen after human approval
- π§ Memory-backed insights β learns from past incidents
This system is built with agentic AI principles: specialized agents collaborate, share findings, and synthesize a final decision β just like a real ops team.
E-commerce businesses generate signals across dozens of systems: sales data, inventory levels, marketing dashboards, customer support tickets, and more. When something goes wrong β like a revenue drop β no single system tells the full story.
The operational question is always cross-domain:
"Was yesterday's sales drop caused by inventory going out of stock, a campaign failing, or a surge in customer complaints?"
Traditional BI dashboards require a human analyst to manually correlate these signals. This project replaces that manual effort with an autonomous, reasoning AI system that:
- Understands the business question in natural language
- Investigates each relevant domain independently
- Correlates findings to identify root causes
- Recommends and executes corrective actions with human oversight
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REACT + EPAM UUI LOVESHIP FRONTEND β
β Chat Console β HITL Panel β Dashboard β Incidents β
β nginx (port 3000) β proxies /api/* β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β Natural Language Query
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASTAPI BACKEND β
β POST /api/query/submit β GET /api/query/{job_id} β
β POST /api/actions β GET /api/incidents β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ORCHESTRATOR NODE β
β β’ Classifies intent (diagnosis/action/memory/report/chitchat) β
β β’ Selects active agents via AGENT_REGISTRY β
β β’ Loads session context from Redis β
β β’ Pre-fetches similar past incidents from ChromaDB (RAG) β
ββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββββ¬ββββββββββββββ
β β β β β
βΌ βΌ βΌ βΌ βΌ
βββββββββββ ββββββββββββ ββββββββββ ββββββββββ parallel via asyncio
β Sales β βInventory β β Mktg & β βSupport β
β Agent β β Agent β βCampaignβ β& CX β
ββββββ¬βββββ ββββββ¬ββββββ β Agent β β Agent β
β β βββββ¬βββββ βββββ¬βββββ
βββββββββββββ΄ββββββββββββ΄βββββββββββ
β
βΌ (all join into analyst_outputs)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MOCK TOOL APIS (GET /tools/sales|inventory|marketing|support) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SYNTHESIS NODE β
β Merges analyst outputs + RAG past incidents β root causes β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REFLECTION NODE β
β Self-audits conclusions for gaps and low-confidence signals β
ββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββ΄ββββββββββββββββββββββββββ
β Action proposed? β
βΌ yes βΌ no
ββββββββββββ βββββββββββββββ
β HITL Gateβ βFinal Responseβ
β (pause) β ββββββββ¬βββββββ
ββββββ¬ββββββ β
β approved β
βΌ βΌ
ββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
βAction β β MEMORY WRITER β
βExecutor βββββββββΊβ PostgreSQL (incident log) β
βPOST /tools/ β β ChromaDB (vector embed for future RAG) β
βactions/... β β Redis (session history TTL 30 min) β
ββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
| Agent | Responsibility | Invoked for |
|---|---|---|
| Orchestrator | Classifies intent, selects active agents, loads Redis session, fetches RAG context | Every query |
| Sales Agent | Calls GET /tools/sales, analyses revenue trends, order volume, regional performance |
diagnosis, action, memory, report |
| Inventory Agent | Calls GET /tools/inventory, detects stockouts and low-stock impact |
diagnosis, action, memory, report |
| Marketing Agent | Calls GET /tools/marketing, surfaces campaign pauses and promo issues |
diagnosis, action, memory, report |
| Support Agent | Calls GET /tools/support, correlates complaint volume with business events |
diagnosis, action, memory, report |
| Synthesis Node | Merges all analyst outputs + RAG past incidents into ranked root causes | Every query (post-agents) |
| Reflection Node | Self-audits synthesis for weak or incomplete conclusions | Every query (post-synthesis) |
| HITL Node | Emits ActionProposal, checkpoints state to Redis, pauses for human approval | action queries |
| Action Executor | Calls POST /tools/actions/{type} only after hitl_approved == True |
Approved actions only |
| Memory Writer | Single write path: PostgreSQL + ChromaDB + Redis session | Every resolved query |
- π Multi-Agent Orchestration β Specialist agents work in parallel, findings get synthesized
- π Cross-Domain Root Cause Analysis β Correlates signals across sales, inventory, marketing, and CX
- π§ Dual Memory System β Short-term session context + long-term incident memory
- π Human-in-the-Loop (HITL) β All destructive or impactful actions require explicit approval
- πͺ Self-Reflection Layer β Orchestrator checks for weak conclusions before finalizing
- π Structured Outputs β Every response is machine-readable and downstream-ready
- π Observability β Every agent decision and tool call is logged with reasoning traces
- π§ͺ Evaluation Suite β Automated tests for agent behavior on business scenarios
| Layer | Technology | Notes |
|---|---|---|
| LLM | EPAM DIAL (GPT-4o via AzureChatOpenAI) | OpenAI-compatible API β configured via DIAL_API_KEY |
| Agent Framework | LangGraph 0.2 | Single adaptive graph; one graph, not multiple |
| Backend | FastAPI 0.115 + uvicorn | Mock tool APIs + async job endpoints |
| Memory β Short-Term | Redis (TTL 30 min) | Session context + in-flight graph state checkpoint |
| Memory β Long-Term | PostgreSQL + asyncpg + SQLAlchemy | Incident log (query β root causes β actions β outcome) |
| Memory β Vector | ChromaDB 0.5 (embedded, no server) | Semantic search for RAG over past incidents |
| Observability | LangSmith | Trace spans around graph execution, configured at app startup |
| UI | React 18 + EPAM UUI Loveship + Vite | Chat console, operations dashboard, HITL panel, incident history β served via nginx |
| Async | Python asyncio | Parallel analyst execution + non-blocking query jobs |
| Testing | Pytest + pytest-asyncio | Unit + integration + 5 core scenario tests |
ecomm-ops-brain/
β
βββ app/
β βββ main.py # FastAPI entry point + CORS middleware
β βββ config.py # Settings (env vars) + get_llm() + AGENT_REGISTRY
β β
β βββ api/
β β βββ query.py # POST /api/query/submit, GET /api/query/{job_id}, DELETE
β β βββ actions.py # POST /api/actions (HITL resume)
β β βββ incidents.py # GET /api/incidents
β β βββ dashboard.py # GET /api/dashboard (operations dashboard payload)
β β
β βββ graph/
β β βββ state.py # AgentState TypedDict
β β βββ graph.py # LangGraph graph compilation
β β βββ builder.py # Node + edge wiring
β β βββ agents_runner.py # Parallel analyst execution via asyncio.gather
β β βββ routing.py # Conditional edge logic
β β βββ nodes/
β β βββ orchestrator.py # Intent classification + RAG fetch
β β βββ synthesis.py # Cross-domain root-cause synthesis
β β βββ reflection.py # Self-check for weak conclusions
β β βββ hitl.py # HITL pause gate + Redis checkpoint
β β βββ action_executor.py # Executes approved actions
β β
β βββ agents/ # Analyst agents (called by agents_runner.py)
β β βββ base_agent.py
β β βββ sales_agent.py
β β βββ inventory_agent.py
β β βββ marketing_agent.py
β β βββ support_agent.py
β β
β βββ services/
β β βββ query_service.py # Graph invocation + runtime stage signalling
β β βββ action_service.py # HITL resume + action execution + runtime stage updates
β β βββ dashboard_service.py # Dashboard stats, backend health, and data-source labels
β β βββ incident_service.py # Incident read + ChromaDB semantic search
β β
β βββ tools/ # Mock FastAPI routes
β β βββ sales.py # GET /tools/sales
β β βββ inventory.py # GET /tools/inventory
β β βββ marketing.py # GET /tools/marketing
β β βββ support.py # GET /tools/support
β β βββ actions.py # POST /tools/actions/{action_type}
β β
β βββ memory/
β β βββ redis_client.py # Session state + runtime stage diagnostics
β β βββ postgres_client.py # Incident CRUD
β β βββ chroma_client.py # Vector embed + cosine similarity search
β β βββ memory_writer.py # Single write path for all three stores
β β
β βββ schemas/
β β βββ query.py # QueryResult, IncidentContext
β β βββ agents.py # AnalystOutput per domain
β β βββ actions.py # ActionProposal, ActionResult
β β βββ incidents.py # Incident, IncidentSummary
β β
β βββ core/
β β βββ error_handler.py # Global FastAPI exception handlers
β β βββ dependencies.py # DI: shared httpx/redis client instances
β β βββ llm_utils.py # invoke_with_retry() β tenacity wrapper for all LLM calls
β β βββ rate_limiter.py # slowapi Limiter singleton (avoids circular import)
β β
β βββ observability/
β βββ tracer.py # configure_tracing() for LangSmith environment bootstrap
β
βββ frontend/ # React + EPAM UUI Loveship frontend
β βββ Dockerfile # Multi-stage: node:20 builds, nginx:alpine serves
β βββ nginx.conf # /api/* proxied to backend container
β βββ package.json # @epam/loveship, react-router-dom, vite
β βββ vite.config.ts
β βββ src/
β βββ main.tsx # React entry + loveship CSS import
β βββ App.tsx # BrowserRouter + layout
β βββ index.css # Loveship dark theme CSS variables
β βββ api/client.ts # All fetch calls (submit, poll, cancel, action, dashboard)
β βββ types/index.ts # TypeScript types matching backend schemas
β βββ components/
β β βββ Sidebar.tsx # Dark nav sidebar (Chat / Dashboard / Incidents)
β β βββ ChatPage.tsx # Chat UI with polling, badges, expanders
β β βββ HITLPanel.tsx # Per-action-type editable approval panel
β β βββ DashboardPage.tsx # Metrics grid, agent cards, bar chart, event feed
β β βββ IncidentsPage.tsx # Searchable incident history with expandable cards
β βββ pages/ # Barrel re-exports for React Router
β
βββ data/
β βββ incidents.json # 2000 seeded incidents
β
βββ scripts/
β βββ seed_incidents.py # Seeds PostgreSQL + ChromaDB (idempotent)
β
βββ tests/
β βββ unit/
β β βββ test_agents.py
β β βββ test_nodes.py
β β βββ test_schemas.py
β β βββ test_memory.py
β βββ integration/
β βββ test_api.py
β βββ test_graph.py
β βββ test_scenarios.py # 5 core demo scenarios
β
βββ alembic/ # Database migrations
βββ .env.example
βββ requirements.txt
βββ CLAUDE.md # AI coding context and conventions
- Docker Desktop with WSL 2 backend (recommended) β runs all services in containers
- An EPAM DIAL API key (OpenAI-compatible endpoint)
- (Optional) LangSmith account for tracing
For local development without Docker: Python 3.11+, Node 20+, Redis, PostgreSQL 16
# 1. Clone the repository
git clone https://git.epam.com/your-username/ecomm-ops-brain.git
cd ecomm-ops-brain
# 2. Create a virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txtCopy .env.example to .env and fill in your values:
cp .env.example .env# EPAM DIAL
DIAL_API_KEY=your-dial-api-key-here
DIAL_API_BASE=https://your-dial-endpoint/openai
DIAL_MODEL=gpt-4o
# LangSmith (optional, for observability)
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=your-langsmith-api-key-here
LANGCHAIN_PROJECT=ecomm-ops-brain
# Redis (start via WSL: sudo service redis-server start)
REDIS_URL=redis://localhost:6379
# PostgreSQL
POSTGRES_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/ecomm_ops
# ChromaDB (embedded β no server needed)
CHROMA_PATH=./chroma_data
# App
LOG_LEVEL=INFO
HITL_TIMEOUT_SECONDS=120# Clone and configure env
git clone https://git.epam.com/your-username/ecomm-ops-brain.git
cd ecomm-ops-brain
cp .env.example .env # fill in DIAL_API_KEY and optionally LANGCHAIN_API_KEY
# Build and start all 4 services (postgres, redis, backend, frontend)
docker compose up --build| Service | URL |
|---|---|
| React frontend | http://localhost:3000 |
| FastAPI backend | http://localhost:8000 |
| Swagger docs | http://localhost:8000/docs |
docker-entrypoint.sh automatically runs Alembic migrations and seeds 2000 incidents on first start.
# 1. Start Redis + PostgreSQL manually (or via WSL)
sudo service redis-server start
sudo service postgresql start
# 2. Install Python dependencies
pip install -r requirements.txt
# 3. Run migrations and seed
alembic upgrade head
python scripts/seed_incidents.py
# 4. Start backend
uvicorn app.main:app --reload --port 8000
# 5. Start React frontend (separate terminal)
cd frontend
npm install
npm run dev # http://localhost:3000Run tests:
pytest tests/ -v- The dashboard (
/dashboard) is an operations view β business health score, inventory risk table, agent work cards, regional revenue bar chart, and recent activity feed. - All data is live from PostgreSQL and Redis β no mock data on the dashboard.
- Revenue cards, regional sales breakdown, and support SLA/CSAT trends are sourced from the
sales_daily_metricsandsupport_daily_metricsPostgreSQL tables.
Input:
"Why did sales drop yesterday?"
System Output (structured):
{
"summary": "Sales dropped 34% yesterday compared to the prior 7-day average.",
"root_causes": [
{
"domain": "Inventory",
"finding": "3 top-selling SKUs were out of stock for 14+ hours",
"confidence": 0.91
},
{
"domain": "Marketing",
"finding": "Email campaign scheduled for 10am was not sent due to a config error",
"confidence": 0.87
}
],
"recommended_actions": [
"Restock SKUs: SKU-102, SKU-207, SKU-334",
"Reschedule or resend email campaign",
"Apply 10% promotional discount to affected products"
],
"memory_context": "Similar drop occurred on 2024-11-03 β resolved by restocking + campaign relaunch"
}Input:
"Fix the issue."
System pauses and displays:
β οΈ The following actions require your approval before execution:
[1] Restock SKU-102, SKU-207, SKU-334 (triggers purchase order)
[2] Reschedule email campaign for 2pm today
[3] Apply 10% discount to top 3 affected products for 48 hours
Approve all? [yes/no] or select: [1, 2, 3]
User input: 1 2
System executes approved actions only and logs outcome.
Input:
"What did we do last time this happened?"
Output:
On 2024-11-03, a similar 31% sales drop was caused by stockouts + a failed campaign.
Actions taken:
β
Restocked 4 SKUs β resolved within 6 hours
β
Relaunched campaign β recovered 80% of lost revenue by EOD
β Discount offer β not used, deemed unnecessary
Recommendation: Prioritize restock + campaign relaunch over discount.
All tools are mock FastAPI routes under /tools/ that return realistic seeded data for three core scenarios.
| Endpoint | Method | Domain | Description |
|---|---|---|---|
/tools/sales |
GET | Sales | Revenue, order count, AOV, regional breakdown, promo status |
/tools/inventory |
GET | Inventory | Stock levels, stockout products, low-stock alerts |
/tools/marketing |
GET | Marketing | Campaign performance, paused campaigns, active promos |
/tools/support |
GET | Support | Complaint volume, top issue categories, CSAT score |
/tools/actions/restock |
POST | Action | Restocks products to 100 units (HITL) |
/tools/actions/resume_campaign |
POST | Action | Resumes a paused campaign (HITL) |
/tools/actions/apply_discount |
POST | Action | Applies promotional discount to SKUs (HITL) |
/tools/actions/extend_promo |
POST | Action | Extends an active promotion's end date (HITL) |
/tools/actions/create_support_ticket |
POST | Action | Opens a support escalation ticket (HITL) |
/tools/actions/escalate |
POST | Action | Escalates an existing issue (HITL) |
β οΈ All/tools/actions/endpoints are guarded by HITL β they will never be called withouthitl_approved == True.
The system uses a three-layer memory architecture, all written through a single memory_writer.py to avoid scattered writes.
- Keyed by
session_id, TTL = 30 minutes - Stores the current
AgentStatesnapshot so the graph can be resumed after HITL pause - Also tracks runtime stage (
orchestrator β agents β synthesis β reflection β hitl β action β done β idle) for internal diagnostics and troubleshooting
incidentstable:id, timestamp, query, query_type, root_causes, actions_proposed, actions_approved, outcome_notes, conversation_history- Written by
memory_writer.pyat the end of every resolved query - Managed with Alembic migrations
- Each resolved incident is embedded and stored on write
- Retrieved via cosine similarity search at the start of every query (RAG)
- Top-3 similar past incidents are injected into the synthesis prompt as context
- No separate ChromaDB server needed β runs embedded in
./chroma_data/
Schema of a stored incident:
{
"incident_id": "uuid",
"timestamp": "2026-04-13T10:00:00Z",
"query": "Why did sales drop yesterday?",
"query_type": "diagnosis",
"root_causes": ["3 SKUs out of stock", "campaign paused"],
"actions_proposed": ["restock", "resume_campaign"],
"actions_approved": ["restock"],
"outcome_notes": "Revenue recovered 80% within 24h"
}Any action that modifies business state is gated behind a mandatory human approval step enforced in two places in code β hitl.py (graph node) and action_executor.py (both assert hitl_approved == True before proceeding).
Flow:
- Synthesis determines an action is needed β
hitl_nodeemitsActionProposaland setshitl_approved = None - Graph checkpoints full
AgentStateto Redis and returns control to the UI - Streamlit
hitl_panel.pyrenders the approval card β operator clicks Approve, Reject, or edits parameters - UI sends
POST /api/actionswith{ session_id, decision, selected_action_index } action_service.pyloads the paused state from Redis, setshitl_approved, and invokesaction_executor_node
Principles:
- β The system will always propose before executing
- β Operators can approve, reject, or modify action parameters before confirming
- β Rejected actions are logged as "declined" in the incident record
- β
HITL timeout:
HITL_TIMEOUT_SECONDS(default 120 s) β returns 408 if not actioned in time - β No action bypasses this gate β the guard is enforced in both node and executor code
Graph execution is instrumented end-to-end:
- LangSmith Integration β Application startup calls
configure_tracing()and the graph uses LangSmith trace spans around orchestrator, agent runner, synthesis, reflection, HITL, and action execution. - Redis Stage Tracking β Each node updates its runtime stage (
orchestrator β agents β synthesis β reflection β hitl β action β done β idle) so execution state is available for debugging and future admin diagnostics. - Dashboard Data Labels β The operations dashboard distinguishes persisted operational data from demo sales/support snapshots so the UI does not imply unavailable historical data is live.
To view LangSmith traces: https://smith.langchain.com β Project: ecomm-ops-brain
tests/
βββ unit/
β βββ test_agents.py # Each analyst agent in isolation (mock tool responses)
β βββ test_nodes.py # Graph nodes in isolation (mock AgentState)
β βββ test_schemas.py # Pydantic schema validation + serialisation
β βββ test_memory.py # Memory clients with mock backends
βββ integration/
βββ test_api.py # FastAPI endpoint tests (TestClient)
βββ test_graph.py # Full graph execution against mock tool APIs
βββ test_scenarios.py # 5 core demo scenarios end-to-end
5 core demo scenarios (must all pass before the project is considered complete):
| # | Question | Expected behaviour |
|---|---|---|
| 1 | "Why did sales drop yesterday?" | Cross-domain synthesis citing inventory + campaign signals |
| 2 | "Fix the problem." | ActionProposal emitted, graph pauses for HITL |
| 3 | "What did we do last time this happened?" | ChromaDB recall surfaces β₯1 past incident |
| 4 | "Which products are close to stock-out?" | Inventory analyst only, structured list response |
| 5 | "Summarize yesterday's business health." | Full structured report, no action proposed |
# Run all tests
pytest tests/ -v
# Run only scenario tests
pytest tests/integration/test_scenarios.py -v- Project scaffolding and architecture design
- Mock tool APIs (sales, inventory, marketing, support, actions)
- Individual specialist agents (Sales, Inventory, Marketing, Support)
- Orchestrator with LangGraph state machine + intent classification
- Parallel agent execution via asyncio
- Short-term memory via Redis (session context + HITL checkpoint)
- Long-term memory β PostgreSQL incident log + Alembic migrations
- Vector memory β ChromaDB embedded + RAG in synthesis
- Human-in-the-Loop approval gate (pause β approve/reject β resume)
- Self-reflection / gap detection layer
- Structured output schema validation (Pydantic)
- FastAPI REST interface with async job system (submit/poll/cancel)
- LangSmith observability integration
- React + EPAM UUI Loveship frontend β chat console, HITL panel, incident history
- Operations dashboard with health score, agent cards, inventory risk, and activity feed
- Multi-stage Docker build (node:20 β nginx:alpine) with nginx API proxy
- Incident seed script (2000 past incidents)
- Test suite β unit + integration + 5 core scenarios
Contributions, issues, and feature requests are welcome!
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Commit your changes:
git commit -m 'feat: add your feature' - Push to the branch:
git push origin feature/your-feature-name - Open a Pull Request
This project is under the EPAM R&D Python Training.
Esha Jawade
Built with β€οΈ as a deep-learning AI engineering project.
Guided by principles of multi-agent design, responsible AI (HITL), and production-grade observability.
"The best ops team is one that never sleeps, never misses a signal, and always asks before acting."