AI Customer Support Agent
Aria is a full-stack RAG support agent. It indexes company documents (PDF, TXT, MD), answers in natural language with inline source citations, and refuses to invent facts when retrieval fails.
Built as a production-shaped portfolio project: LangGraph orchestration, local embeddings, Postgres-backed memory, PII redaction, audit logging, MCP tools, LangSmith traces, and SSE streaming to a React UI.
Support teams spend time on the same product, shipping, warranty, and return questions. Generic chatbots either hallucinate or know nothing about the business.
Aria only uses your corpus. If the answer is not there, it says so — no fabrication from general model knowledge.
| Area | Implementation |
|---|---|
| Orchestration | LangGraph StateGraph with retrieve / grade / rewrite / tools / generate |
| Grounding | ChromaDB + sentence-transformers; LLM-as-judge chunk grading |
| Honesty | Explicit decline path when graded context is empty |
| Memory | LangGraph Postgres checkpointer (thread survives restart / refresh) |
| Safety | Presidio PII redaction on input and output; moderation filters |
| Tools | MCP client for live web search + document lookup |
| Observability | LangSmith tracing per turn; separate Postgres audit table |
| UX | Token-by-token SSE, citation chips, distinct decline styling |
input_filter -> retrieve -> grade
|-- relevant (+ live) -> tools -> generate -> output_filter
|-- relevant ---------> generate -> output_filter
|-- empty, retries left -> rewrite -> retrieve
|-- empty, cap reached --> decline
Full walkthrough: docs/architecture.md.
aria/
├── backend/
│ ├── app/
│ │ ├── api/ # chat (SSE), documents, health
│ │ ├── graph/ # LangGraph state, nodes, edges
│ │ ├── rag/ # ingest, retrieve, grade, rewrite
│ │ ├── safety/ # Presidio, filters, audit
│ │ ├── tools/ # MCP client, web search, lookup
│ │ ├── memory/ # Postgres checkpointer
│ │ └── streaming/ # SSE helpers
│ ├── scripts/ingest_documents.py
│ ├── Dockerfile
│ └── requirements.txt
├── frontend/ # React + Vite + TypeScript
├── docs/architecture.md
├── docker-compose.yml
└── railway.json
- Python 3.11+
- Node.js 18+
- Docker (recommended) or a Postgres instance
- A Mistral AI API key
- Optional: LangSmith API key, MCP web-search URL
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.envSet at least MISTRAL_API_KEY and DATABASE_URL in backend/.env.
# set MISTRAL_API_KEY in your shell or a root .env file
docker compose up --buildAPI: http://localhost:8000 — ingestion runs on container start.
cd frontend
npm install
npm run devUI: http://localhost:5173 (VITE_API_URL defaults to http://localhost:8000).
cd backend
python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate
pip install -r requirements.txt
python -m spacy download en_core_web_sm
python scripts/ingest_documents.py
uvicorn app.main:app --reload --port 8000Drop documents into backend/data/sample_docs/ (or your DOCS_SOURCE_DIR), then re-run the ingest script or POST /documents/ingest.
| Method | Path | Purpose |
|---|---|---|
POST |
/chat/stream |
SSE chat turn (thread_id, message) |
GET |
/chat/history/{thread_id} |
Rehydrate conversation |
POST |
/documents/ingest |
Re-index document set |
GET |
/health |
Liveness |
- Backend — Railway (
railway.json+backend/Dockerfile). Attach Postgres; setDATABASE_URL,MISTRAL_API_KEY,ALLOWED_ORIGINS. - Frontend — Vercel (
frontend/). SetVITE_API_URLto the Railway URL.
Portfolio / educational use.
