数据截至 (上游 commit c617143f0147)
在线检索:事实种子与个性化 PageRank
本章讲什么:
retrieve(query)的四步——事实打分、识别记忆过滤、图上 PPR 扩散、排段落,以及"没事实就降级"的兜底。这是 HippoRAG 区别于普通向量 RAG 的核心。入口HippoRAG.retrieve(src/hipporag/HippoRAG.py:413)。
1. 先看主循环
每个问题,retrieve 只做四件事(HippoRAG.py:459-480):
① get_fact_scores 问题向量 · 所有事实向量 → 每条事实一个分
② rerank_facts 取 top-5 候选,交大模型过滤 → top_k_facts
│
len==0 ? ──是──► dense_passage_retrieval 纯向量检索兜 底,直接返回
│否
③ graph_search_with_fact_entities 事实→种子权重→跑 PPR
④ _build_retrieval_result 取 PPR 排名前 num_to_retrieve 段
下面逐步拆。
2. 第①步:事实打分
思路
不是拿问题直接和"段落"比(那是普通 DPR),而是先拿问题和每一条三元组事实比相似度。为什么?因为事实是"结构化的关系陈述",和"多跳问题里隐含的关系"更容易对上。
实现
问题用两套指令分别编码(get_query_embeddings, HippoRAG.py:1391):一套 query_to_fact(对事实)、一套 query_to_passage(对段落)。指令文本见 prompts/linking.py:1:
query_to_fact: "Given a question, retrieve relevant triplet facts that matches this question."
query_to_passage: "Given a question, retrieve relevant documents that best answer the question."
打分就是点积 + min-max 归一化(get_fact_scores, HippoRAG.py:1427):
# 示意,非源码(对照 HippoRAG.py:1466-1468)
scores = fact_embeddings @ query_embedding.T # 每条事实一个相似度
scores = min_max_normalize(scores) # 压到 [0,1]
3. 第②步:识别记忆(大模型过滤事实)
要解决的小问题
向量相似 ≠ 真相关。分最高的几条事实里,往往混着"词面像、逻辑上没用"的噪声。HippoRAG 借"海马体识别记忆"的隐喻,再加一道大模型过滤:从候选里挑出真正对回答有用的(rerank_facts, HippoRAG.py:1659)。
怎么做
- 按分取 top
linking_top_k(默认 5)条候选事实(HippoRAG.py:1683-1693)。 - 交给
DSPyFilter(rerank.py:15),它用一段 DSPy 优化过的 few-shot 提示 让大模型输出"过滤后"的事实子集,最多留 4 条。 - 大模型可能改写事实文本,所以用
difflib.get_close_matches模糊匹配回原候选,还原成真实索引(rerank.py:122-125)。