EmpathRAG
Emotion-Aware Retrieval-Augmented Generation with Safety Guardrails for Student Mental Health
MSML641 Β· Applied Machine Learning Β· University of Maryland Β· Spring 2025
Standard RAG systems treat every message identically as a neutral information request. A student in crisis and a student asking for study tips go through the same retrieval pipeline, with no emotional awareness and no safety gate.
EmpathRAG fixes this. It is a 5-stage NLP pipeline that classifies a student's emotional state before retrieval, rewrites queries based on that state, and intercepts crisis-level messages with a trained NLI classifier before the language model is ever invoked.
Pipeline
Student Message
β
ββββΆ [1] Emotion Classifier RoBERTa + LoRA (CPU)
β distress Β· anxiety Β· frustration Β· neutral Β· hopeful
β
ββββΆ [2] Safety Guardrail DeBERTa-v3 NLI (CPU)
β β If crisis β return 988 lifeline Β· STOP Β· generator never runs
β
ββββΆ [3] Query Router Deterministic templates + session tracker
β Rewrites query with emotion context Β· tracks 6 trajectory states
β
ββββΆ [4] FAISS Retrieval all-mpnet-base-v2 Β· 1,674,369 vectors
β Emotion-match re-ranking Β· SQLite metadata sidecar
β
ββββΆ [5] Mistral 7B Generator Q4_K_M GGUF Β· 28/33 GPU layers
Sliding 3-turn memory Β· 2-paragraph empathetic response
Results
| Metric | Value | Target | |
|---|---|---|---|
| RoBERTa Emotion F1 (weighted) | 0.7127 | > 0.55 | β |
| DeBERTa Crisis Recall (held-out NLI test set, 23K samples) | 0.9629 | > 0.80 | β |
| DeBERTa Crisis Recall (30 adversarial probes, 6 categories) | 0.75 | β | β |
| DeBERTa Crisis Precision | 0.7951 | > 0.65 | β |
| BERTScore F1 | 0.8266 | > 0.72 | β |
| Wilcoxon p-value (Full vs BM25) | 3.62e-08 | < 0.05 | β |
| Euphemistic recall β NLI vs keyword | 100% vs 20% | β | π |
Ablation β Emotion Alignment Score (3-condition)
| Condition | Retrieval | Emotion Conditioning | Score |
|---|---|---|---|
| A β BM25 baseline | Sparse | None | 0.30 |
| C β Dense RAG | FAISS semantic | None | 0.50 |
| D β Full EmpathRAG | FAISS + emotion | Query rewrite + re-rank | 0.88 |
Emotion conditioning contributes +0.38 over pure dense retrieval (CβD). Wilcoxon signed-rank: p = 3.62e-08.
Note: Condition B (DPR two-tower baseline) was descoped β deprioritised to increase adversarial probe depth. A ColBERT-scale index would be required for DPR to offer meaningful gains over FAISS flat-L2 at 1.67M vectors.
Key Finding
The NLI-framed safety guardrail outperforms a keyword filter across every adversarial probe category that matters:
| Probe Category | EmpathRAG (NLI) | Keyword Filter |
|---|---|---|
| Direct crisis language | 100% | 80% |
| Euphemistic / indirect | 100% | 20% |
| Negation bypass | 100% | 60% |
| Bait-and-switch | 40% | 20% |
Keyword filters miss indirect phrasing. NLI understands semantic entailment. This is the core research finding.
Demo
π Demo recording in progress β Loom walkthrough coming soon.
The Gradio demo shows:
- Real-time emotion timeline with trajectory detection across turns
- Safety guardrail panel with Integrated Gradients token attribution highlights
- Multi-turn conversation memory (sliding 3-turn window)
- Session ID for human evaluation correlation
To run locally (requires models β see Setup):
python demo/app.py
VRAM Budget (RTX 3060, 6 GB)
| Component | Device | VRAM |
|---|---|---|
| RoBERTa + DeBERTa | CPU | 0 MB |
| Sentence Transformer | GPU (encode only) | 440 MB |
| Mistral 7B Q4_K_M | GPU resident | 3,870 MB |
| KV cache + compute | GPU | ~630 MB |
| Total peak | ~4,940 MB β |
Repo Structure
Empath-RAG/
βββ src/
β βββ pipeline/
β β βββ pipeline.py # 5-stage orchestrator Β· conversation memory
β β βββ query_router.py # Emotion-conditioned query rewriting
β β βββ session_tracker.py # Trajectory detection (6 states)
β βββ models/
β β βββ guardrail_ig.py # DeBERTa NLI + Integrated Gradients
β β βββ annotate_corpus.py # Corpus emotion annotation (Colab A100)
β βββ data/
β βββ preprocess.py # GoEmotions 27β5 label collapse
β βββ build_faiss_index.py # FAISS IVFFlat builder
β βββ build_nli_pairs.py # NLI training pair construction
βββ demo/
β βββ app.py # Gradio demo Β· emotion timeline Β· crisis panel
βββ eval/
β βββ run_ablation.py # Conditions A / C / D
β βββ run_bertscore.py # BERTScore F1
β βββ run_wilcoxon.py # Wilcoxon signed-rank test
β βββ run_adversarial.py # NLI vs keyword filter Β· 30 probes
β βββ test_prompts.json # 50 prompts Β· 10 per emotion class
β βββ adversarial_probes.json # 30 probes Β· 6 categories Γ 5
βββ notebooks/
β βββ colab_emotion_classifier.ipynb # RoBERTa + LoRA Β· A100
β βββ colab_deberta_guardrail.ipynb # DeBERTa NLI Β· A100 Β· bf16
βββ data/
βββ MANIFEST.md # Dataset download instructions
Setup
Requirements: Python 3.12 Β· CUDA 12.1 Β· 6 GB VRAM Β· 16 GB RAM Β· ~15 GB disk
β οΈ Install order is critical β do not skip steps.
# 1. Clone
git clone https://github.com/MukulRay1603/Empath-RAG.git
cd Empath-RAG
python -m venv venv
venv\Scripts\activate # Windows
# 2. PyTorch with CUDA β install FIRST
pip install torch==2.5.1+cu121 --index-url https://download.pytorch.org/whl/cu121
# 3. llama-cpp-python CUDA wheel β install SECOND
pip install "llama_cpp_python==0.3.4" --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu121
# 4. Everything else
pip install -r requirements.txt
# 5. Force correct numpy (faiss requires < 2.0)
pip install "numpy==1.26.4" --force-reinstall
Model downloads β see data/MANIFEST.md for dataset download instructions.
Mistral 7B GGUF β download mistral-7b-instruct-v0.2.Q4_K_M.gguf from TheBloke/Mistral-7B-Instruct-v0.2-GGUF β place at models/generator/mistral-7b-instruct-v0.2.Q4_K_M.gguf
Datasets
| Dataset | Role | License |
|---|---|---|
| GoEmotions | Emotion classifier training | Apache 2.0 |
| Reddit Mental Health | FAISS retrieval corpus | CC BY 4.0 |
| Suicide Detection | Guardrail NLI training | Public |
| Empathetic Dialogues | BERTScore gold references | CC BY-NC 4.0 |
Evaluation Status
| Task | Status |
|---|---|
| Emotion Classifier (RoBERTa F1 = 0.7127) | β Complete |
| Safety Guardrail (DeBERTa recall = 0.9629) | β Complete |
| BERTScore Evaluation (F1 = 0.8266) | β Complete |
| Wilcoxon Test (p = 3.62e-08) | β Complete |
| Adversarial Probe Evaluation (30 probes) | β Complete |
| Human Evaluation (8β10 raters) | π In Progress |
| Loom Demo Recording | π In Progress |
Known Limitations
- Bait-and-switch probes: Positive openers cause the guardrail to misclassify follow-up crisis content (40% recall). Most dangerous documented failure mode.
- Domain transfer false positives: Academic hyperbole ("this thesis is killing me") fires the guardrail at high confidence β trained on r/SuicideWatch, never saw graduate student language.
- Generator quality: Mistral 7B Q4_K_M produces adequate but not optimal empathetic responses. Architecture supports drop-in model replacement.
- Faithfulness gap: No automated faithfulness metric deployed β RAGAS and DeepEval both produced degenerate scores with a small model judge. BERTScore reported instead.
v2 Safety Direction
EmpathRAG Core is being hardened as a guarded conversational RAG research system,
not a production counseling replacement. The Core plan prioritizes fail-closed
safety loading, multi-level triage, private-by-default demo behavior, curated
resource retrieval, and stronger safety evaluation. Start with
docs/README.md and
docs/planning/MASTER_CHECKLIST.md.
License
MIT License β see LICENSE for details.
Dataset licenses vary β see Datasets table above. Mistral 7B: Apache 2.0.