HippoRAG — Hippocampus-Inspired Memory via Personalised PageRank¶
What problem does this solve?¶
Multi-hop questions are structurally hard for vector retrieval. "Which experimental technique that uses Cooper pairs powers MRI machines?" requires linking Cooper pairs → Josephson junctions → SQUID → magnetometry → MRI. No single chunk contains this whole chain; vector retrieval finds chunks near "Cooper pairs" or "MRI" but not the bridges between them. HippoRAG (OSU, NeurIPS 2024) borrows from neuroscience: the hippocampus retrieves memories via associative activation spreading from cue entities. Translated to RAG: extract entities from the query, seed personalised PageRank over the knowledge graph, return the highest-scored nodes plus the chunks they came from. Bridge nodes naturally surface because PageRank assigns importance through the graph's structure.
Where it came from¶
HippoRAG was published at NeurIPS 2024 by Gutiérrez et al. (Ohio State). The paper showed multi-hop benchmarks (MuSiQue, 2WikiMultiHopQA) improved by 6-20 points over vanilla RAG. HippoRAG 2 followed in 2025 with a learned scoring head; the cookbook uses the original PageRank-only variant for clarity. The neuroscience framing was more than metaphor — the paper argued PageRank diffusion behaves like associative recall in the hippocampus, which makes the technique a structural fit for multi-hop. By 2026 HippoRAG has become the default choice for multi-hop-heavy workloads. The cookbook composes it with GraphRAG-style graph construction so the underlying graph can serve both kinds of queries; the per-query strategy is what differs.
Where it fits in the RAG landscape¶
Three graph-traversal RAG variants to know:
- GraphRAG (Recipe 31). Communities + summaries. Good for synthesis.
- LightRAG (Recipe 32). Dual-level views. Cheap, balanced.
- HippoRAG (this recipe). PageRank from query entities. Best for multi-hop.
All three share the underlying knowledge graph; the difference is in retrieval strategy. Production systems often build the graph once and route between strategies per query.
When to use it (and when not to)¶
Use HippoRAG when your queries are multi-hop. Research questions that span topics, comparative questions, anything that requires linking facts across documents. Skip it for factoid queries. Vanilla RAG is faster. Skip it when the corpus has no graph structure. A pile of FAQ answers has no edges to walk. Skip it when entity extraction is unreliable. The technique seeds PageRank on extracted entities; bad extraction means bad seeds means bad walks.
The intuition¶
Three intuitions to carry:
Seeds matter more than the algorithm. PageRank with good seeds finds bridge nodes. PageRank with bad seeds returns random structurally-popular entities. Spend time on entity extraction.
Bridge nodes are the win. Nodes connecting query entities are exactly what multi-hop questions need. PageRank's diffusion process surfaces them naturally.
alpha controls spread. PageRank's damping factor controls how far the walk travels. Low alpha (0.3) stays near seeds; high alpha (0.85) spreads broadly. The cookbook default is 0.4.
The chunks behind the nodes matter. PageRank returns entities. Map back to the source chunks to feed the generator. The graph remembers which chunk introduced each node.
Architecture¶
flowchart TB Q[Question] --> EE[LLM: extract
entities] EE --> S[Seed nodes] G[(Knowledge Graph)] --> PR[Personalised PageRank
from seeds] S --> PR PR --> R[Ranked nodes] R --> CH[Map nodes to
source chunks] G --> CH CH --> A[LLM answers]
References¶
- 📄 HippoRAG — Neurobiologically Inspired Long-Term Memory for LLMs (Gutiérrez et al., 2024) — The NeurIPS 2024 paper.
- 💻 OSU-NLP-Group/HippoRAG reference implementation — The paper's code.
- 📄 HippoRAG 2 (2025) — The follow-up with a learned scoring head.
- 📄 Personalised PageRank — Haveliwala et al., 2002 — The PageRank variant we use.
- 📄 GraphRAG (Recipe 31) — Cousin technique for global synthesis.
- 💻 MuSiQue multi-hop benchmark — The benchmark where HippoRAG shines.
Setup¶
Pick a provider via the PROVIDER env var; everything below is provider-agnostic. The default is Nebius. Tracing is off by default in published notebooks so the outputs are clean — flip COOKBOOK_TRACING=phoenix to send spans to a local Phoenix UI.
import os
os.environ.setdefault('PROVIDER', 'nebius')
os.environ.setdefault('COOKBOOK_TRACING', 'off')
from cookbook.providers import LLMClient
from cookbook.tracing import init_tracing
client = LLMClient()
print(f'Provider: {client.provider} | Chat model: {client.chat_model}')
print(init_tracing())
Provider: nebius | Chat model: meta-llama/Llama-3.3-70B-Instruct Tracing disabled.
Build the Pipeline, Step by Step¶
Step 1 — Build the knowledge graph¶
Same graph construction as GraphRAG and LightRAG.
from cookbook.corpora import load_wikipedia_superconductors
from cookbook.chunkers import sentence_window
from cookbook.graphs import extract_triples, build_graph, personalized_pagerank
docs = list(load_wikipedia_superconductors())[:14]
chunks = sentence_window(docs, sentences_per_chunk=4)[:80]
triples = extract_triples([(c.chunk_id, c.text) for c in chunks], client.chat)
g = build_graph(triples)
print(f'Graph: {g.number_of_nodes()} nodes, {g.number_of_edges()} edges.')
17:54:39 - LiteLLM:WARNING: common_utils.py:979 - litellm: could not pre-load bedrock-runtime response stream shape — Bedrock event-stream decoding will be unavailable. Error: No module named 'botocore'
17:54:39 - LiteLLM:WARNING: common_utils.py:24 - litellm: could not pre-load sagemaker-runtime response stream shape — SageMaker event-stream decoding will be unavailable. Error: No module named 'botocore'
Graph: 171 nodes, 134 edges.
Step 2 — Build the entity extractor¶
For each query, ask the LLM to list the entities or concepts mentioned. These become PageRank seeds.
import re
def query_entities(question: str) -> list[str]:
raw = client.chat(
'List, one per line, the named entities or concepts in this question. '
'Use lowercase and keep them short.\n\n' + question
)
out = []
for line in raw.splitlines():
cleaned = re.sub(r'[^a-z0-9 \-]', '', line.strip().lower()).strip()
if cleaned:
out.append(cleaned)
return out
for q in [
'How is BCS theory connected to superconducting magnets used in MRI?',
'What materials show flux pinning?',
]:
print(f'Q: {q}')
print(f' entities: {query_entities(q)}')
print()
Q: How is BCS theory connected to superconducting magnets used in MRI?
entities: ['bcs theory', 'superconducting magnets', 'mri'] Q: What materials show flux pinning?
entities: ['materials', 'flux pinning']
Step 3 — Run personalised PageRank¶
cookbook.graphs.personalized_pagerank seeds the walk with query entities and runs PageRank. The result is a score per node; we pick the top.
q = 'Which experimental phenomena connect Cooper pairs to SQUID measurements?'
seeds = query_entities(q)
print(f'Seeds: {seeds}')
scores = personalized_pagerank(g, seeds, alpha=0.4)
top_nodes = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:10]
for node, sc in top_nodes:
print(f' {sc:.4f} {node}')
Seeds: ['cooper pairs', 'squid', 'measurements', 'phenomena']
0.7143 cooper pairs 0.1428 lattice 0.1428 no resistance 0.0000 d-wave quantum inc. 0.0000 cuprates 0.0000 critical point 0.0000 superconductor 0.0000 helium-3 0.0000 condensation 0.0000 flux tubes
Step 4 — Build the HippoRAG answer function¶
Use the top nodes' neighbourhoods as context for the answer LLM.
def hippo(question: str, top_k: int = 6) -> tuple[str, list[str]]:
seeds = query_entities(question)
scores = personalized_pagerank(g, seeds, alpha=0.4)
top_nodes = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_k]
rendered = []
for node, sc in top_nodes:
neighbours = list(g.neighbors(node))[:4]
rendered.append(f'{node} (score {sc:.4f}) connects to: {neighbours}')
ctx = '\n'.join(rendered)
answer = client.chat(
'Use this graph-walk context to answer.\n' + ctx + f'\nQuestion: {question}\nAnswer:'
)
return answer, rendered
ans, _ = hippo('Which experimental phenomena connect Cooper pairs to SQUID measurements?')
print(ans[:400])
To answer this question, we need to follow the connections from Cooper pairs to find a path that leads to SQUID measurements. Starting from Cooper pairs, we see it connects to 'lattice' and 'no resistance'. Neither 'lattice' nor 'no resistance' directly connects to other concepts that could lead us to SQUID measurements based on the provided graph. However, we know from general knowledge that Co
Step 5 — Wrap as answer_question¶
Standard contract.
def answer_question(question: str) -> tuple[str, list[str]]:
return hippo(question)
ans, _ = answer_question('How does BCS theory connect to applications in MRI?')
print(ans[:400])
To connect BCS theory to applications in MRI, we need to follow a series of steps through the graph. 1. **BCS Theory**: BCS theory is connected to 'thermodynamic properties of superconductors' and 'electromagnetic properties of superconductors'. 2. **Superconductors in MRI**: Superconductors are crucial in MRI (Magnetic Resonance Imaging) technology because they are used to create the strong ma
Look Inside¶
Inspect — bridge nodes for a multi-hop query¶
For a multi-hop question, the top PageRank nodes should include intermediate entities not explicitly named in the query. Those are the bridges.
q = 'How does BCS theory connect to applications in MRI?'
seeds = query_entities(q)
print(f'Seeds (explicitly named): {seeds}')
scores = personalized_pagerank(g, seeds, alpha=0.4)
for node, sc in sorted(scores.items(), key=lambda x: x[1], reverse=True)[:8]:
is_seed = node in seeds
print(f' {sc:.4f} {node:35s} {"(seed)" if is_seed else "(bridge)"}')
Seeds (explicitly named): ['bcs theory', 'mri', 'applications'] 0.7143 bcs theory (seed) 0.1428 thermodynamic properties of superconductors (bridge) 0.1428 electromagnetic properties of superconductors (bridge) 0.0000 d-wave quantum inc. (bridge) 0.0000 cuprates (bridge) 0.0000 critical point (bridge) 0.0000 superconductor (bridge) 0.0000 helium-3 (bridge)
Inspect — alpha (damping factor) sweep¶
Low alpha stays near seeds; high alpha spreads broadly. Look at how the top-5 changes.
import pandas as pd
rows = []
for alpha in (0.15, 0.3, 0.5, 0.7, 0.85):
sc = personalized_pagerank(g, seeds, alpha=alpha)
top = sorted(sc.items(), key=lambda x: x[1], reverse=True)[:3]
rows.append({'alpha': alpha, 'top3': [t[0] for t in top]})
pd.DataFrame(rows)
| alpha | top3 | |
|---|---|---|
| 0 | 0.15 | [bcs theory, thermodynamic properties of super... |
| 1 | 0.30 | [bcs theory, thermodynamic properties of super... |
| 2 | 0.50 | [bcs theory, thermodynamic properties of super... |
| 3 | 0.70 | [bcs theory, thermodynamic properties of super... |
| 4 | 0.85 | [bcs theory, thermodynamic properties of super... |
Inspect — what happens with no extracted entities?¶
If the entity extractor returns nothing, PageRank falls back to uniform distribution over all nodes. The cookbook handles this gracefully.
scores = personalized_pagerank(g, [], alpha=0.4)
top = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:5]
print('With empty seeds (uniform fallback), top-5:')
for node, sc in top:
print(f' {sc:.4f} {node}')
With empty seeds (uniform fallback), top-5: 0.0175 d-wave quantum inc. 0.0125 critical point 0.0125 cuprates 0.0115 flux tubes 0.0111 superconductor
Inspect — cost¶
HippoRAG adds one LLM call per query (entity extraction) on top of the answer. The PageRank itself is cheap (NetworkX, < 1 s on most graphs).
import time
t0 = time.perf_counter()
_ = personalized_pagerank(g, ['cooper pairs', 'squid'], alpha=0.4)
pr_ms = (time.perf_counter() - t0) * 1000
print(f'PageRank: {pr_ms:.1f} ms')
print('Per-query cost: 1 entity-extraction LLM call + 1 answer LLM call.')
PageRank: 11.9 ms Per-query cost: 1 entity-extraction LLM call + 1 answer LLM call.
Run It¶
End-to-end on a multi-hop question.
ans, _ = answer_question('What phenomena link Cooper pairs to the operation of MRI scanners and particle accelerators?')
print('=== HippoRAG answer ===')
print(ans)
=== HippoRAG answer === Cooper pairs are linked to the operation of MRI scanners and particle accelerators through the phenomenon of superconductivity, which is characterized by 'no resistance'. This is because superconducting materials, which exhibit zero electrical resistance when cooled below a certain critical temperature, are crucial components in the operation of both MRI scanners (for generating strong magnetic fields) and particle accelerators (for efficient acceleration of particles over long distances). The connection to 'lattice' is also relevant, as the crystal lattice structure of superconducting materials plays a significant role in their superconducting properties.
Side by Side: Vanilla Baseline vs This Technique¶
Vanilla vs HippoRAG on a multi-hop question.
from cookbook.baselines import vanilla_pipeline
q = 'What phenomena link Cooper pairs to the operation of MRI scanners?'
base = vanilla_pipeline(q, corpus='wikipedia-superconductors', top_k=5)
ours_a, _ = answer_question(q)
import pandas as pd
pd.DataFrame([
{'pipeline': 'vanilla', 'preview': base.answer[:160]},
{'pipeline': 'hipporag', 'preview': ours_a[:160]},
])
C:\Users\faree\Desktop\rag\rag-cookbook-2026\.venv\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
| pipeline | preview | |
|---|---|---|
| 0 | vanilla | The phenomena that link Cooper pairs to the op... |
| 1 | hipporag | To answer this question, we need to understand... |
Knobs to Turn¶
Six knobs in priority order:
- Entity extractor prompt. The seeds are the technique. Tune; bad seeds produce bad walks.
- alpha (PageRank damping). 0.4 is the cookbook default. Lower stays near seeds, higher spreads more.
- top_k nodes. We use 6. Higher gathers more context but inflates the prompt.
- Neighbour count per node. "4 neighbours" is the cookbook default in the answer prompt; can be increased.
- Compose with the graph. GraphRAG and HippoRAG can share the same underlying graph; route per query.
- Source-chunk recall. Map PageRank-winning nodes back to their source chunks for the answer prompt — adds grounding.
Evaluate on a Slice¶
Run the recipe's answer_question over a small slice of the hand-curated eval set. Full RAGAS metrics are exercised in recipes/09-evaluation-and-production/ragas-triad-eval.ipynb; here we just print a quick spot-check table so you can eyeball whether the technique is on track.
from cookbook.corpora import load_eval_questions
from cookbook.eval import EvalSample
qs = load_eval_questions()
qs = [q for q in qs if q['corpus'] == 'wikipedia-superconductors']
samples = []
for row in qs[:5]:
answer, contexts = answer_question(row['question'])
samples.append({
'question': row['question'],
'expected': row['answer'],
'actual': answer[:200],
'contexts_retrieved': len(list(contexts)),
})
import pandas as pd
pd.DataFrame(samples)
| question | expected | actual | contexts_retrieved | |
|---|---|---|---|---|
| 0 | Who first observed superconductivity, and in w... | Heike Kamerlingh Onnes observed it in mercury ... | The provided graph-walk context does not direc... | 6 |
| 1 | What is the Meissner effect? | The complete expulsion of magnetic flux from a... | The Meissner effect is related to superconduct... | 6 |
| 2 | Distinguish Type-I from Type-II superconductors. | Type-I has a single critical field above which... | Type-I and Type-II superconductors can be dist... | 6 |
| 3 | What does BCS theory explain? | It explains conventional superconductivity thr... | BCS theory explains the thermodynamic and elec... | 6 |
| 4 | What is a Cooper pair? | Two electrons bound together by phonon exchang... | A Cooper pair is a concept related to supercon... | 6 |
Closing Thoughts¶
Three failure modes:
- Bad entity extraction. If the extractor produces vague seeds or misses key entities, PageRank walks the wrong neighbourhoods. Tune the extractor.
- Disconnected components. PageRank within a disconnected component can't reach the other component. Build a better graph or treat components separately.
- alpha mistuning. Too low and you don't explore. Too high and you get noise. Sweep.
Compose with GraphRAG (Recipe 31) for global queries and HippoRAG for multi-hop; route per query. Compose with LightRAG (Recipe 32) for cheap factoid queries.