Explainable Graph-RAG for multi-hop question answering on HotpotQA.
A relational GNN re-ranks passages over a knowledge graph of entity "bridges", a local LLM reads the result, and every step, retrieval, ranking, reasoning path, and answer, is inspectable through a live D3 explorer.
Course project, Current Trends in Machine Learning, MSc, 2nd year.
The reasoning graph (left) shows the retrieved passages and the bridge entities connecting them; the panel on the right shows the answer, the multi-hop reasoning paths, and the ERASER necessity/attribution scores for each passage. Click a bridge entity to see the counterfactual answer if it were removed.
Answering a HotpotQA question means combining facts from two different Wikipedia paragraphs, linked by a shared entity (the "bridge"). Most RAG pipelines retrieve those two paragraphs independently and hope the reader stitches them together; this project makes the bridge itself part of the model and exposes it as an explanation.
Pipeline
- Dense retrieval (
BAAI/bge-large-en-v1.5) selects candidate passages for the query. - Bridge graph construction: entities are linked via
ReFinEDand connected by co-occurrence across passages, weighted by IDF specificity so that generic hubs (countries, years) don't dominate, this is the multi-hop signal HotpotQA is built on. - R-GCN re-ranker (
torch_geometric) scores passages over that graph; its score is fused with the dense score (fusion_alpha), so the graph refines dense retrieval rather than replacing it. - Reader: a local LLM (
qwen3.5:9bvia Ollama) reads the top passages and answers with explicit supporting sentences. - XAI layer: reasoning paths, an ERASER-style necessity/sufficiency overlay, a dual GNN/Dense attribution signal, and counterfactual entity ablation, all served to the same web UI shown above.
On the HotpotQA dev set, the graph-based re-ranker (gnn_bridge_qwen9b) reaches
Joint F1 0.52, clearly above a strong dense-only baseline (baseline_dense, 0.40),
with the same reader and prompt for every system so the comparison isolates the
retrieval architecture. See Report.pdf for the full methodology, all
four baselines (BM25, dense, PPR-over-bridge-graph, R-GCN), ablations, and the XAI
evaluation (ERASER, attribution agreement, counterfactual robustness).
Every answer in the UI is backed by four complementary explanation layers:
| Layer | Question it answers | Level |
|---|---|---|
| Reasoning paths | Which passage → bridge entity → passage chain produced the answer? | Retriever |
| Dual GNN/Dense signal | Where did the graph change the ranking vs. dense alone? | Retriever |
| ERASER overlay | Which retrieved passages are necessary, does removing them flip the answer? | Reader |
| Counterfactual ablation | What happens to the answer if a specific bridge entity is removed? | Interactive |
attribution recall, the fraction of ERASER-necessary passages the GNN actually
surfaced in its top-K, is the project's key diagnostic against explanation
mismatch (a retriever-side explanation that doesn't match what the reader used).
The fastest way to see the system: a FastAPI + D3 web app that serves the interface above from a pre-computed cache of example questions, full reasoning graph, all XAI panels, zero setup beyond Python.
git clone https://github.com/fraadap/GraphRAG.git
cd GraphRAG
./run_light.shThen open http://localhost:8000. run_light.sh creates a virtual env, installs the
~6 lightweight dependencies (requirements.txt), and starts the server in
cache-only mode:
XAI_CACHE_ONLY=1 python -m uvicorn src.api.app:app --host 0.0.0.0 --port 8000Pick a question from Examples ▾, answer, graph and every explanation panel render instantly. Typing a question outside the cached set returns a clear message: the offline demo only serves pre-computed questions (see below for live answering).
The offline demo is a thin shell over the real, trainable pipeline in src/. To
answer arbitrary questions live, reproduce the results, or retrain the re-ranker:
# the committed requirements.txt is the lightweight demo's, the full pipeline
# additionally needs the GPU/ML stack:
uv pip install torch --index-url https://download.pytorch.org/whl/cu124
uv pip install torch-geometric scikit-learn sentence-transformers transformers accelerate rank-bm25
uv pip install "git+https://github.com/amazon-science/ReFinED.git" --no-deps
uv pip install ujson unidecode nltk boto3 lmdb fastcoref
# 1. download HotpotQA
python scripts/download_hotpot.py
# 2. build the knowledge graph + bridge graph
python scripts/build_kg_tier1.py --config configs/kg_tier1.yaml
python scripts/build_bridge_graph.py
# 3. train the R-GCN re-ranker
python scripts/train_gnn.py --config configs/gnn_train.yaml
# 4. evaluate a system end-to-end (retriever + reader + official HotpotQA metrics)
python scripts/run_eval.py --config configs/gnn_bridge_qwen9b.yaml
# 5. serve the live UI (GPU model + Ollama reader instead of the cache)
uvicorn src.api.app:app --host 0.0.0.0 --port 8000Requires an Ollama server (ollama pull qwen3.5:9b) reachable at
http://localhost:11434, and a CUDA GPU for GNN training/inference. Every retriever
(baseline_bm25, baseline_dense, ppr_qwen9b, bridge_qwen9b,
gnn_bridge_qwen9b) shares the same reader and prompt, so configs/*.yaml is the
single source of truth for a reproducible comparison.
src/
├─ api/ FastAPI backend (cache-only + live serving) + static D3 frontend
├─ data/ HotpotQA loader + official eval wrapper
├─ kg_build/ coref, entity linking (ReFinED), relation extraction, bridge graph
├─ gnn/ R-GCN dataset / features / model / training loop
├─ retrieval/ BM25, dense (BGE), PPR, GNN re-ranker, share one Retriever protocol
├─ reader/ Ollama-backed reader + mock reader for GPU-less testing
└─ xai/ ERASER, GNNExplainer, reasoning paths, attribution agreement,
XAI payload builder consumed by the API
scripts/ download / KG build / bridge graph / GNN training / eval / XAI demo
configs/ one YAML per run, baselines + the main R-GCN system
outputs/xai_cache/ pre-computed payloads powering the lightweight demo (tracked in git)
Report.pdf full write-up: methodology, results, ablations, XAI evaluation
| Layer | Tool |
|---|---|
| Entity linking | ReFinED (Wikipedia QIDs) |
| Embeddings | BGE-large-en-v1.5 |
| Knowledge graph | NetworkX (in-memory, no external DB) |
| Re-ranker | R-GCN (torch_geometric) |
| Retriever-side XAI | GNNExplainer + reasoning-path extraction |
| Reader-side XAI | ERASER (sufficiency / comprehensiveness / necessity) |
| LLM reader | Qwen (served locally via Ollama) |
| Backend | FastAPI |
| Frontend | Vanilla JS + D3 v7 (force-directed graph) |
Built as the final project for Current Trends in Machine Learning. See
Report.pdf for the full academic write-up.
