# Contoso Electronics AI Support — End-to-End .NET AI Demo

A comprehensive demo application showcasing the **full .NET AI stack** in a realistic customer-support scenario. One `dotnet run` command launches 6 interconnected services that ingest product docs, orchestrate multi-agent workflows, call external tools via MCP, analyze sentiment with Python, and serve a streaming Blazor chat UI — all observable through the Aspire Dashboard.

## What This Demonstrates

| Technology | What it does here |
|---|---|
| **Microsoft.Extensions.AI (MEAI)** | `IChatClient` / `IEmbeddingGenerator` abstractions used everywhere — zero vendor lock-in |
| **Microsoft Agent Framework (MAF)** | 3 agents (Research, Sentiment, Response) composed in a concurrent→sequential workflow |
| **Model Context Protocol (MCP)** | MCP server exposing order lookup, warranty check, and replacement tools |
| **Data Ingestion + Vector Data** | Markdown docs → semantic chunks → SQLite vector store with auto-embedding |
| **.NET Aspire** | Orchestrates all services with service discovery, health checks, and distributed tracing |
| **Python Polyglot** | FastAPI + HuggingFace `transformers` for deterministic sentiment analysis |
| **AI Evaluation** | 5 test scenarios × 6 quality evaluators with HTML reporting |

## Architecture

```
┌──────────────────────────────────────────────────────────────┐
│                   ContosoSupport.AppHost                     │
│                  (Aspire Orchestration)                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────┐    ┌──────────────────────────────────────┐ │
│  │  Azure       │    │     ContosoSupport.AgentWorker       │ │
│  │  OpenAI      │◄───│  ┌───────────┐  ┌───────────────┐   │ │
│  │  - gpt-4.1   │    │  │ Research   │  │ Sentiment     │   │ │
│  │  - embedding │    │  │ Agent      │  │ Proxy Agent   │   │ │
│  └──────┬───────┘    │  │ (LLM +     │  │ (→ Python)    │   │ │
│         │            │  │  vectors)  │  │               │   │ │
│         │            │  └─────┬─────┘  └───────┬───────┘   │ │
│         │            │        └──── concurrent ────┘        │ │
│  ┌──────▼───────┐    │               │                      │ │
│  │  Ingestion   │    │        ┌──────▼──────┐               │ │
│  │  Worker      │    │        │  Response   │               │ │
│  │  (markdown   │    │        │  Agent      │               │ │
│  │   → vectors) │    │        │  (LLM + MCP │               │ │
│  └──────┬───────┘    │        │   tools)    │               │ │
│         │            │        └─────────────┘               │ │
│   ┌─────▼─────┐      └──────────────────────────────────────┘ │
│   │  SQLite   │                    ▲                          │
│   │  Vector   │◄───────────────────┘  (search)               │
│   │  Store    │                                              │
│   └───────────┘      ┌──────────────┐   ┌────────────────┐   │
│                      │  MCP Server  │   │  Python        │   │
│                      │  - orders    │   │  Sentiment     │   │
│                      │  - warranty  │   │  (HuggingFace) │   │
│                      │  - replace   │   │  FastAPI       │   │
│                      └──────────────┘   └────────────────┘   │
│                                                              │
│   ┌──────────────────────────┐   ┌────────────────────────┐  │
│   │  ContosoSupport.Web     │   │  Aspire Dashboard      │  │
│   │  (Blazor Chat UI)       │   │  (traces/logs/metrics) │  │
│   └──────────────────────────┘   └────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘
```

**Request flow**: User message → Blazor Web → AgentWorker → Research ‖ Sentiment (concurrent) → Response (sequential, with MCP tools) → streamed reply

## Quick Start

### Option A: GitHub Codespaces (Recommended)

The fastest way to get running — **zero local setup required**.

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/luisquintanilla/dotnet-ai-e2e?quickstart=1)

1. Click the button above (or **Code → Codespaces → New codespace**)
2. Wait for the devcontainer to build (~2 min — installs .NET 10, Python 3.12, uv, Aspire CLI)
3. Configure your Azure OpenAI connection:

```bash
cd ContosoSupport/ContosoSupport.AppHost

# Managed Identity (recommended — no API key needed)
az login
dotnet user-secrets set "ConnectionStrings:openai" "https://YOUR-ACCOUNT.openai.azure.com/"

# Or with an API Key
dotnet user-secrets set "ConnectionStrings:openai" "Endpoint=https://YOUR-ACCOUNT.openai.azure.com/;Key=YOUR-API-KEY"
```

4. Run everything:

```bash
cd ContosoSupport
aspire run
```

5. Open the **web** endpoint from the Aspire Dashboard and start chatting!

> **Azure OpenAI requirement**: You need an Azure OpenAI resource with `gpt-4.1` and `text-embedding-3-small` model deployments. For managed identity, ensure your account has the **Cognitive Services OpenAI User** role.

---

### Option B: Local Development

<details>
<summary>Prerequisites for local setup</summary>

- [**.NET 10 SDK**](https://dotnet.microsoft.com/download/dotnet/10.0)
- [**Aspire CLI**](https://aspire.dev/get-started/install-cli/) (`dotnet tool install -g aspire`)
- [**Python 3.12+**](https://python.org) with [**uv**](https://docs.astral.sh/uv/)
- **Azure CLI** (`az login`)
- **Azure OpenAI** resource with `gpt-4.1` and `text-embedding-3-small` deployments

</details>

```bash
# 1. Clone and build
git clone https://github.com/YOUR-ORG/dotnet-ai-e2e.git
cd dotnet-ai-e2e
dotnet build ContosoSupport

# 2. Configure Azure OpenAI credentials
cd ContosoSupport/ContosoSupport.AppHost
dotnet user-secrets set "ConnectionStrings:openai" "https://YOUR-ACCOUNT.openai.azure.com/"
cd ..

# 3. Run everything
aspire run              # or: dotnet run --project ContosoSupport.AppHost
```

Aspire launches all 6 services and opens the Dashboard with health status, distributed traces, structured logs, and OpenTelemetry metrics.

### Try It Out

Open the **web** endpoint shown in the Aspire Dashboard. Try these prompts:

- *"Tell me about the X500 headphones"* — tests Research agent + vector search
- *"My headphones broke after 2 months, order ORD-2025-1001"* — tests warranty check + MCP tools
- *"This is the THIRD time I'm calling! Nobody helps me!!"* — tests Sentiment agent (NEGATIVE) + empathetic response

## Project Structure

```
dotnet-ai-e2e/
├── .devcontainer/                         # Codespaces / devcontainer config
├── ContosoSupport/                        # .NET solution
│   ├── ContosoSupport.slnx               # Solution file
│   ├── ContosoSupport.AppHost/           # Aspire orchestration
│   ├── ContosoSupport.ServiceDefaults/   # Shared OTel + service discovery
│   ├── ContosoSupport.Shared/            # Shared models (IngestedChunk)
│   ├── ContosoSupport.Ingestion/         # Worker: markdown → vector store
│   │   └── data/                         #   15 mock Contoso documents
│   ├── ContosoSupport.AgentWorker/       # MAF agents + workflow
│   ├── ContosoSupport.McpServer/         # MCP tools (orders, warranty)
│   ├── ContosoSupport.Web/              # Blazor chat frontend
│   ├── ContosoSupport.Evaluation/       # AI quality evaluation (xUnit)
│   ├── PythonSentiment/                 # Python FastAPI sentiment service
│   │   ├── pyproject.toml
│   │   └── src/main.py
│   ├── docs/                             # Layer-by-layer walkthrough
│   └── README.md                         # Solution-level readme
└── README.md                            # ← You are here
```

## Technology Stack Deep Dive

### Layer 1 — MEAI Foundation
Every service uses `IChatClient` and `IEmbeddingGenerator` from Microsoft.Extensions.AI. This means swapping Azure OpenAI for Ollama, Anthropic, or any other provider requires changing one line of registration code — zero business logic changes.

### Layer 2 — Knowledge (Data Ingestion + Vector Data)
The Ingestion worker watches the `data/` directory. When markdown files change, it runs them through a `SemanticSimilarityChunker`, generates embeddings via `text-embedding-3-small`, and stores them in a SQLite vector database. The AgentWorker's Research agent queries this same database.

### Layer 3 — Business Integration (MCP)
The MCP server exposes 4 tools with mock data: `lookup_order`, `get_customer_orders`, `check_warranty`, `initiate_replacement`. The Response agent discovers and calls these tools via the Model Context Protocol — the same standard used by Claude, Cursor, and other AI tools.

### Layer 4 — Agent Intelligence (MAF)
Three specialized agents compose a workflow:
- **Research Agent**: LLM + vector search tool → finds relevant product docs
- **Sentiment Agent**: Custom `AIAgent` subclass → calls Python service (no LLM cost)
- **Response Agent**: LLM + MCP tools → takes action on the customer's behalf

Research and Sentiment run **concurrently**, then their combined context feeds into Response **sequentially**.

### Layer 5 — Polyglot (Python)
Sentiment analysis uses HuggingFace `transformers` — a solved ML problem that doesn't need an LLM. The Python service runs via Aspire's `AddUvicornApp()` with automatic `uv` dependency management.

### Layer 6 — Orchestration (Aspire)
One `aspire run` (or `dotnet run --project ContosoSupport.AppHost`) launches everything: .NET services, Python service, service discovery, health checks, and the observability dashboard.

### Layer 7 — Quality (AI Evaluation)
5 test scenarios evaluate the system against 6 quality metrics (Relevance, Groundedness, Coherence, Fluency, Completeness, Retrieval). Run with `dotnet test` and generate HTML reports with `dotnet aieval report`.

## Run Evaluations

```powershell
# Set the judge LLM credentials (same Azure OpenAI or a different one)
cd ContosoSupport\ContosoSupport.Evaluation
# Set via environment variables or appsettings

# Run the evaluation suite
dotnet test ContosoSupport\ContosoSupport.Evaluation

# Generate HTML report
cd ContosoSupport
dotnet aieval report
```

## Documentation

See [`ContosoSupport/docs/`](ContosoSupport/docs/) for detailed layer-by-layer documentation:

| Doc | Topic |
|-----|-------|
| [Overview](ContosoSupport/docs/overview.md) | Architecture and technology stack |
| [01 — Foundation](ContosoSupport/docs/01-foundation-meai.md) | Microsoft.Extensions.AI |
| [02 — Knowledge](ContosoSupport/docs/02-knowledge-ingestion.md) | Data Ingestion + Vector Data |
| [03 — Integration](ContosoSupport/docs/03-business-integration-mcp.md) | Model Context Protocol |
| [04 — Intelligence](ContosoSupport/docs/04-agent-intelligence-maf.md) | Microsoft Agent Framework |
| [05 — Polyglot](ContosoSupport/docs/05-polyglot-python.md) | Python sentiment analysis |
| [06 — Orchestration](ContosoSupport/docs/06-orchestration-aspire.md) | .NET Aspire |
| [07 — Quality](ContosoSupport/docs/07-quality-evaluation.md) | AI Evaluation |
| [08 — Request Flow](ContosoSupport/docs/08-request-flow.md) | End-to-end trace walkthrough |
| [Smoke Test](ContosoSupport/docs/smoke-test.md) | Step-by-step manual testing guide |

## Mock Data

The `ContosoSupport.Ingestion/data/` directory contains 15 realistic Contoso Electronics documents (copied to build output automatically):

| Category | Files | Examples |
|----------|-------|---------|
| Products (5) | `contoso-x500-headphones.md`, `contoso-s200-speaker.md`, ... | Specs, pricing, warranty durations |
| Policies (5) | `warranty-policy.md`, `return-policy.md`, ... | Business rules, process steps |
| Support (5) | `troubleshooting-headphones.md`, `faq-orders.md`, ... | How-tos, escalation paths |

Mock orders and customers are hardcoded in `ContosoSupport.McpServer/MockData.cs`.

## License

This is a demo/sample application for educational purposes.
