A comparative study of retrieval architectures for multi-hop question answering
CS564 (Database Management Systems) Final Project, University of New Mexico Alekh Pandey, Scott Bing
Standard RAG embeds the question and pulls back the top-k most similar chunks from a vector store. That works when one document holds the answer. It breaks down on multi-hop questions, where the answer is only found by connecting facts spread across several documents. For example, "Who is the CEO of the company that Paradigm invested in?" needs Paradigm → INVESTED_IN → FTX, then SBF → CEO_OF → FTX.
This project builds two retrieval pipelines over the same news corpus and compares them head to head on the MultiHop-RAG benchmark:
| Vector RAG (baseline) | Graph RAG | |
|---|---|---|
| Store | ChromaDB | Neo4j knowledge graph |
| Index | text-embedding-3-small chunk embeddings |
6,935 nodes / 21,625 typed edges extracted with GPT-4o |
| Retrieval | Single-pass similarity search | Deterministic 5-stage Cypher pipeline |
| Generator | GPT-4o-mini | GPT-4o-mini (same prompt) |
Both systems use the same LLM and the same answer prompt, so the retrieval method is the only variable being tested.
Evaluated on 200 questions, 50 from each of the four MultiHop-RAG categories.
| Metric | Vector RAG | Graph RAG |
|---|---|---|
| Accuracy | 79.5% (159/200) | 82.5% (165/200) |
| Miss rate (says "Unknown" when an answer exists) | 18.7% | 4.7% |
| Hallucination rate (answers a null query) | 6.0% | 14.0% |
| Retrieval recall | 42.9% | 53.7% |
| Retrieval precision | 57.7% | 35.0% |
| Mean / median latency | 0.86s / 0.65s | 2.02s / 1.93s |
| Category | Vector RAG | Graph RAG | Δ |
|---|---|---|---|
| Inference | 94.0% | 90.0% | −4.0 |
| Comparison | 70.0% | 84.0% | +14.0 |
| Temporal | 60.0% | 70.0% | +10.0 |
| Null | 94.0% | 86.0% | −8.0 |
- Graph RAG wins where multi-hop reasoning matters. Comparison and temporal questions ask what publication A said versus publication B. The graph's
REPORTED_BYedges act as a structural index from entities to specific outlets, which similarity search can't provide. - The precision-recall paradox. Vector RAG has higher retrieval precision and F1, yet Graph RAG answers more questions correctly. When Graph RAG misses the exact ground-truth document, the knowledge-graph triples still give the LLM a path to reason along. When Vector RAG's top-k misses, the LLM has nothing to work with, which explains its 18.7% miss rate.
- Graph RAG is better at finding answers but also more willing to make them up. Fuzzy entity matching sometimes latches onto a node for a question that has no answer in the corpus, so it hallucinates more on null queries.
- Latency costs about 2.3×. Graph RAG adds an entity-extraction LLM call plus several sequential Cypher queries.
- For context, Tang & Yang report 56% accuracy for GPT-4 with retrieved chunks and 89% with ground-truth chunks on this benchmark. At 82.5%, Graph RAG closes most of that retrieval gap.
flowchart LR
Q[Question] --> V1[Embed query] --> V2[(ChromaDB<br/>top-k chunks)] --> G[GPT-4o-mini<br/>answer]
Q --> S1[1. LLM entity<br/>extraction + aliases]
S1 --> S2[2. Fuzzy match<br/>to Neo4j nodes]
S2 --> S3[3. Publication-aware<br/>2-hop traversal]
S3 --> S4[4. Relevance filter<br/>KEY / BRIDGE / DIRECT]
S4 --> S5[5. Triples + source<br/>excerpts]
S5 --> G
- Data-driven schema. We analyzed the benchmark queries and found that 84% name a specific publication and 54% name two or more. From that we designed 9 node types (Person, Organization, Publication, Product, CreativeWork, Location, Event, LegalCharge, Award) and 19 specific edge types (
REPORTED_BY,CEO_OF,INVESTED_IN,SUED,CHARGED_WITH,TESTIFIED_IN, …). The schema has no catch-all edges such asASSOCIATED_WITH. Seesrc/scripts/schema_v2.json. - Metadata-enriched chunking. Each 1,000-character chunk (150 overlap) is prefixed with
[Source | Title | Published]so the extractor can emitREPORTED_BYedges. - Schema-enforced extraction. LangChain's
LLMGraphTransformerruns GPT-4o restricted to the allowed labels, and the full node and edge descriptions are passed as additional instructions. - Post-ingestion enrichment. A publication-edge safety net, entity deduplication, publication merging, and a temporal layer of
Datenodes.
Retrieval uses fixed, deterministic Cypher templates rather than LLM-generated Cypher.
- Entity extraction. GPT-4o-mini pulls out proper nouns and aliases, e.g.
Sam Bankman-Fried → [SBF]. - Fuzzy matching. A three-tier score (exact, then prefix, then substring) plus a coverage threshold of 30% or more, which stops matches like "Hype" → "Hyperscalers".
- Publication-aware traversal. For a Publication node, only entities that also connect to another query entity are returned, so the traversal doesn't pull in everything TechCrunch ever covered. Other nodes get a standard two-hop neighborhood.
- Relevance filtering. Triples are capped at 60 and ranked as key (entity↔entity, ≤10), bridging (≤30), or direct (≤20).
- Answer generation. The prompt combines graph facts (tagged
[KEY]) with document excerpts reached throughMENTIONSedges.
- LLM-generated Cypher (
GraphCypherQAChain) reached about 10% accuracy, and over 90% of its answers were "Unknown". The LLM kept writingWHERE d.text CONTAINS 'keyword', which treats the graph as a text search engine instead of traversing it. - Generic LLM-proposed schema. Catch-all edges swallowed most relationships. Amazon ended up labeled as Organization, Concept, Product, Service, and Location all at once.
- Edge labels without descriptions. The extractor kept confusing
CEO_OFwithWORKS_FORandINVESTED_INwithOWNS. - No Publication node. Without it, the 84% of queries that name an outlet were effectively unanswerable.
.
├── run_rag.py # Runs Vector / Graph / Hybrid RAG over the test set
├── evaluate_results.py # Accuracy, hallucination, miss rate, P/R/F1, latency
├── exp.ipynb # Experiments and analysis notebook
├── populate_vectors.ipynb # Builds the ChromaDB vector store (notebook version)
├── data/
│ └── sample_queries.json # The 200 evaluation questions (50 per category)
├── results/
│ ├── final.json # Per-question answers, latencies, retrieved titles
│ └── evaluation.json # Aggregated metrics (source of the tables above)
├── src/
│ ├── configs/config.py # Pydantic settings (reads .env)
│ ├── db/ # ChromaDB and Neo4j connection singletons
│ ├── bots/
│ │ ├── models.py # Vector RAG (single-pass)
│ │ ├── graph_retrieval_v3.py # Graph RAG, 5-stage retriever
│ │ └── hybrid_retrieval.py # Graph-guided vector search (extra experiment)
│ └── scripts/
│ ├── schema_v2.json # Final 9-node / 19-edge graph schema
│ ├── prepare_evidence_corpus.py
│ ├── graph_transformer_v2.py # KG extraction pipeline (GPT-4o)
│ ├── retry_failed_chunks.py
│ ├── merge_duplicate_publications.py
│ ├── enrich_node_properties.py
│ ├── add_temporal_edges.py
│ └── build_knowledge_vector.py
└── multihoprag/ # Early prototype: Neo4j vector index + Streamlit UI
Prerequisites: Python 3.11+, a running Neo4j 5.x instance, and an OpenAI API key.
git clone https://github.com/CodeAlekh/<repo-name>.git
cd <repo-name>
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # then fill in your keys1. Get the data. Download corpus.json and MultiHopRAG.json from yixuantt/MultiHopRAG into data/. The 200-question evaluation sample is already in data/sample_queries.json.
2. Build the vector store (ChromaDB, persisted to db/):
python -m src.scripts.build_knowledge_vector3. Build the knowledge graph in Neo4j. This calls GPT-4o on every chunk, so it costs money.
(cd src/scripts && python prepare_evidence_corpus.py) # -> data/evidence_corpus.json
python -m src.scripts.graph_transformer_v2 # extraction + publication edges + dedup
python -m src.scripts.retry_failed_chunks # optional: re-run rate-limited chunks
python -m src.scripts.merge_duplicate_publications
python -m src.scripts.add_temporal_edges4. Run and evaluate.
python run_rag.py # fills answers into results/test_set.json
python evaluate_results.py --input results/final.json --output results/evaluation.json- Embedding-based entity deduplication instead of substring matching
- Use the temporal
Datelayer directly for date-aware retrieval - Confidence thresholds on entity matches to lower the null-query hallucination rate
- Explore traversals deeper than 2 hops, and graph-guided hybrid retrieval
- Y. Tang and Y. Yang, MultiHop-RAG: Benchmarking Retrieval-Augmented Generation for Multi-Hop Queries, 2024. arXiv:2401.15391
- D. Edge et al., From Local to Global: A GraphRAG Approach to Query-Focused Summarization, 2024. arXiv:2404.16130
- Y. Gao et al., Retrieval-Augmented Generation for Large Language Models: A Survey, 2023. arXiv:2312.10997