教程|用 HKVM-RAG 思路自建证据组织层:多跳问答 F1 提升 5-10 个点
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图
2. 检索时走超图
def hypergraph_rag(query, k=5):
# 提取 query 实体
query_entities = extract_entities(query)
# 在图上做 PPR(personalized PageRank)
seed = {e: 1.0 for e in query_entities}
ppr = nx.pagerank(graph, personalization=seed, alpha=0.85)
# 拉 top 文档
doc_scores = {}
for node, score in ppr.items():
for neighbor in graph.neighbors(node):
doc_id = graph[node][neighbor].get("doc_id")
if doc_id is not None:
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + score
top_docs = sorted(doc_scores.items(), key=lambda x: -x[1])[:k]
context = "
".join([documents[i] for i, _ in top_docs])
# 生成
return llm_call(f"基于:
{context}
回答:{query}")
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图
简化版实现
from openai import OpenAI
import networkx as nx
client = OpenAI()
graph = nx.Graph()
# 1. 离线建图:对每个 passage 让 LLM 提取 (entity, relation, entity) 三元组
def extract_tuples(text):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"提取文本中的实体关系三元组:
{text}
输出 JSON: [[e1, r, e2], ...]"}]
)
return json.loads(resp.choices[0].message.content)
for i, doc in enumerate(documents):
for e1, r, e2 in extract_tuples(doc):
graph.add_edge(e1, e2, relation=r, doc_id=i)
2. 检索时走超图
def hypergraph_rag(query, k=5):
# 提取 query 实体
query_entities = extract_entities(query)
# 在图上做 PPR(personalized PageRank)
seed = {e: 1.0 for e in query_entities}
ppr = nx.pagerank(graph, personalization=seed, alpha=0.85)
# 拉 top 文档
doc_scores = {}
for node, score in ppr.items():
for neighbor in graph.neighbors(node):
doc_id = graph[node][neighbor].get("doc_id")
if doc_id is not None:
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + score
top_docs = sorted(doc_scores.items(), key=lambda x: -x[1])[:k]
context = "
".join([documents[i] for i, _ in top_docs])
# 生成
return llm_call(f"基于:
{context}
回答:{query}")
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图
HKVM-RAG 的设计
- Key:passage-level LLM evidence tuples → 超边(答案路径)
- Value:原始 passage 文本
- 检索:用超图打分,召回答案链
简化版实现
from openai import OpenAI
import networkx as nx
client = OpenAI()
graph = nx.Graph()
# 1. 离线建图:对每个 passage 让 LLM 提取 (entity, relation, entity) 三元组
def extract_tuples(text):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"提取文本中的实体关系三元组:
{text}
输出 JSON: [[e1, r, e2], ...]"}]
)
return json.loads(resp.choices[0].message.content)
for i, doc in enumerate(documents):
for e1, r, e2 in extract_tuples(doc):
graph.add_edge(e1, e2, relation=r, doc_id=i)
2. 检索时走超图
def hypergraph_rag(query, k=5):
# 提取 query 实体
query_entities = extract_entities(query)
# 在图上做 PPR(personalized PageRank)
seed = {e: 1.0 for e in query_entities}
ppr = nx.pagerank(graph, personalization=seed, alpha=0.85)
# 拉 top 文档
doc_scores = {}
for node, score in ppr.items():
for neighbor in graph.neighbors(node):
doc_id = graph[node][neighbor].get("doc_id")
if doc_id is not None:
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + score
top_docs = sorted(doc_scores.items(), key=lambda x: -x[1])[:k]
context = "
".join([documents[i] for i, _ in top_docs])
# 生成
return llm_call(f"基于:
{context}
回答:{query}")
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图
为什么需要证据组织层?
多跳问答 RAG 的常见瓶颈:
- 每段独立打分,检索到好段但组织不出答案
- 图记忆实体关系,多跳证据碎片化
- 读者模型被过多无关段落干扰
HKVM-RAG 的设计
- Key:passage-level LLM evidence tuples → 超边(答案路径)
- Value:原始 passage 文本
- 检索:用超图打分,召回答案链
简化版实现
from openai import OpenAI
import networkx as nx
client = OpenAI()
graph = nx.Graph()
# 1. 离线建图:对每个 passage 让 LLM 提取 (entity, relation, entity) 三元组
def extract_tuples(text):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"提取文本中的实体关系三元组:
{text}
输出 JSON: [[e1, r, e2], ...]"}]
)
return json.loads(resp.choices[0].message.content)
for i, doc in enumerate(documents):
for e1, r, e2 in extract_tuples(doc):
graph.add_edge(e1, e2, relation=r, doc_id=i)
2. 检索时走超图
def hypergraph_rag(query, k=5):
# 提取 query 实体
query_entities = extract_entities(query)
# 在图上做 PPR(personalized PageRank)
seed = {e: 1.0 for e in query_entities}
ppr = nx.pagerank(graph, personalization=seed, alpha=0.85)
# 拉 top 文档
doc_scores = {}
for node, score in ppr.items():
for neighbor in graph.neighbors(node):
doc_id = graph[node][neighbor].get("doc_id")
if doc_id is not None:
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + score
top_docs = sorted(doc_scores.items(), key=lambda x: -x[1])[:k]
context = "
".join([documents[i] for i, _ in top_docs])
# 生成
return llm_call(f"基于:
{context}
回答:{query}")
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图
本周 arXiv 2606.07218 提出的 HKVM-RAG 给了我们一个思路:把”证据组织”从”段落匹配”中分离出来。本教程演示落地。
为什么需要证据组织层?
多跳问答 RAG 的常见瓶颈:
- 每段独立打分,检索到好段但组织不出答案
- 图记忆实体关系,多跳证据碎片化
- 读者模型被过多无关段落干扰
HKVM-RAG 的设计
- Key:passage-level LLM evidence tuples → 超边(答案路径)
- Value:原始 passage 文本
- 检索:用超图打分,召回答案链
简化版实现
from openai import OpenAI
import networkx as nx
client = OpenAI()
graph = nx.Graph()
# 1. 离线建图:对每个 passage 让 LLM 提取 (entity, relation, entity) 三元组
def extract_tuples(text):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"提取文本中的实体关系三元组:
{text}
输出 JSON: [[e1, r, e2], ...]"}]
)
return json.loads(resp.choices[0].message.content)
for i, doc in enumerate(documents):
for e1, r, e2 in extract_tuples(doc):
graph.add_edge(e1, e2, relation=r, doc_id=i)
2. 检索时走超图
def hypergraph_rag(query, k=5):
# 提取 query 实体
query_entities = extract_entities(query)
# 在图上做 PPR(personalized PageRank)
seed = {e: 1.0 for e in query_entities}
ppr = nx.pagerank(graph, personalization=seed, alpha=0.85)
# 拉 top 文档
doc_scores = {}
for node, score in ppr.items():
for neighbor in graph.neighbors(node):
doc_id = graph[node][neighbor].get("doc_id")
if doc_id is not None:
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + score
top_docs = sorted(doc_scores.items(), key=lambda x: -x[1])[:k]
context = "
".join([documents[i] for i, _ in top_docs])
# 生成
return llm_call(f"基于:
{context}
回答:{query}")
效果
在 HotpotQA、2WikiMultiHopQA 上:
- 纯 dense retriever:F1 55-60%
- 加图记忆:F1 65-70%
- 加 HKVM 风格超图:F1 73-78%
局限
- 建图需要 LLM 调用,成本不低
- 图质量决定上限,bad tuple 拖累整体
- 动态文档(每天新增)需要增量更新图