实用笔记:图式RAG实战——为何传统RAG无法应对复杂查询
《实用笔记》操作指南:图解RAG应用——为何标准RAG无法处理复杂查询:面向采用该模式的团队提供的合同、校验规则以及可直接插入的代码模板。
可将此内容视为《Graph RAG in Action:为何标准RAG无法处理复杂查询(以及Graph RAG如何解决这一问题)》中理念面向操作人员的重构版本:包含清晰的阶段划分、有序的代码模块,以及便于交接时参考的恢复说明。 在“概览”阶段,若能将其视为可度量的界面来使用效果最佳。在扩大范围之前,先记录一份理想的处理过程、一个失败案例以及对应的回滚说明。 相较于庞大的脚本,应优先选择小型且可测试的单元。当某一步骤出现故障时,故障原因应能明确指向某个具体责任模块,而非整个复杂的流程链。
真正的问题:相互孤立的信息碎片
对于“真正的问题分离阶段”,在修改代码之前需明确输入内容、该步骤的负责人以及退出标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 应将此阶段视为输入与已验证输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分幻觉内容与索引缺失的问题。
Graph RAG的独特之处
在修改代码之前,需先明确What Graph RAG所执行阶段的输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境切换到共享环境时出现意外费用。必须注明实际用于生成答案的文本片段;若没有引用,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。
Feature | Vector RAG | Graph RAG
-------------------|---------------------|-------------------------
Storage unit | Text chunks | Entities + relationships
Retrieval method | Semantic similarity | Graph traversal
Best for | Direct lookup | Multi-hop reasoning
Context scope | Local fragment | Connected network
提取瓶颈
在“提取瓶颈”阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。 在“提取瓶颈”阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向单一责任模块,而非复杂的相互关联结构。
管道。Graph RAG管道的工作原理
在处理“Graph RAG如何工作”这一阶段时,首先需明确相关约定:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与经过验证的输出之间的契约。为相关产物命名,定义成功检测标准,并拒绝默许的部分完成情况。 在调整提示词之前,先使用固定的问题集来衡量召回率。仅仅更换提示词往往无法改善较差的检索效果。
flowchart LR
Q[User query] --> E[Entity extraction]
E --> G[Graph construction]
G --> T[Traversal + path ranking]
T --> C[Path context]
C --> L[LLM answer generation]
L --> R[Final response]
实现蓝图(概念验证)
在完成“实施蓝图概念验证”阶段时,首先需列出相关约定:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。 在调整提示词之前,先用固定的问题集测试召回率。仅仅更换提示词往往无法改善较差的检索效果。
1. 提取结构化事实
在完成“1. 提取结构化事实”这一阶段时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 在调整提示词之前,先使用固定的问题集来测试系统的召回率。仅仅更换提示词往往无法解决检索效果不佳的问题。 在完成“1. 提取结构化事实”这一阶段时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 相较于庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向某个具体的功能模块,而非整个复杂的处理流程。
import networkx as nx
SAMPLE_TRIPLES = [
("John Doe", "is CEO of", "Acme Corp"),
("Jane Smith", "sits on board of", "Acme Corp"),
("Jane Smith", "mentors", "John Doe"),
]
def build_graph(triples):
graph = nx.DiGraph()
for source, relation, target in triples:
graph.add_node(source)
graph.add_node(target)
graph.add_edge(source, target, relation=relation)
return graph
2. 寻找候选路径
在将“寻找候选路径”这一阶段视为可度量的工作面时,其效果最佳。在扩大范围之前,先收集一份理想的转录文本、一个失败案例以及回滚说明。 应将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,杜绝默许的不完整完成。 需将分块策略与检索策略分开处理。当质量指标发生变化时,调整其中一项不应强制要求重新编写另一项。
def traverse_graph(graph, seeds, depth=2):
paths = []
seen = set()
undirected = graph.to_undirected()
for seed in seeds:
for target in graph.nodes:
if seed == target:
continue
for path in nx.all_simple_paths(undirected, source=seed, target=target, cutoff=depth):
canonical = tuple(path) if tuple(path) <= tuple(reversed(path)) else tuple(reversed(path))
if canonical in seen:
continue
seen.add(canonical)
paths.append(path)
return paths
3. 为路径评分
将“3个得分路径”阶段视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解这些成本,就能避免在路径从演示环境转移到共享环境时出现意外费用。应将分块策略与检索策略分开,当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
def score_path(graph, path, query):
query_tokens = set(tokenize(query))
path_nodes = [node.lower() for node in path]
path_rels = []
for i in range(len(path) - 1):
rel, _ = get_edge_relation(graph, path[i], path[i + 1])
path_rels.append(rel.lower())
path_text = " ".join(path_nodes + path_rels)
overlap_score = len(query_tokens.intersection(set(tokenize(path_text)))) * 10
node_score = sum(1 for node in path_nodes if any(token in node for token in query_tokens)) * 5
rel_score = sum(1 for rel in path_rels if any(token in rel for token in query_tokens)) * 8
length_penalty = max(0, len(path) - 2) * 2
connection_bonus = sum(len(node.split()) for node in path_nodes)
return overlap_score + node_score + rel_score + connection_bonus - length_penalty
4. 将最佳路径转化为上下文
将“4个转换最佳阶段”视为可测量的对象时,其效果最为理想。在扩大范围之前,需记录一份最佳处理方案、一个失败案例以及回滚说明。 应将配置与应用程序代码分开。环境文件、密钥存储和功能标志应集中存放于一处,以便操作人员无需查看整个系统结构即可进行审计。 应将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。 将“4个转换最佳阶段”视为可测量的对象时,其效果最为理想。在扩大范围之前,需记录一份最佳处理方案、一个失败案例以及回滚说明。 相比庞大的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障应指向单一责任模块,而非复杂的处理流程。
def path_to_text(graph, path):
lines = []
for i in range(len(path) - 1):
source = path[i]
target = path[i + 1]
relation, reversed_edge = get_edge_relation(graph, source, target)
if reversed_edge:
lines.append(f"{target} {relation} {source}.")
else:
lines.append(f"{source} {relation} {target}.")
return " ".join(lines)
5. 按选定路径向大语言模型提问
在“5. 提问大语言模型”阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 当下一步操作是编写代码或调用工具时,优先选择具有结构化格式且经过模式验证的输出,而非自由形式的文字描述。
def generate_llm_answer(query, context):
prompt = (
"You are a helpful assistant. Use only the graph facts below to answer the query clearly. "
"Do not introduce any new information. "
f"If the answer is not directly supported by these facts, say you don't know.\n\n"
f"Question: {query}\n\n"
"Graph facts:\n"
f"{context}\n\n"
"Answer with a short explanation of the supporting facts:"
)
response = client.responses.create(
model=config["deployment_name"],
input=prompt,
max_output_tokens=250,
temperature=0.1,
)
return response.output_text.strip()
6. 以演示 API 的形式将其公开
对于6个需要分阶段展示的案例,在修改代码之前需明确输入参数、各步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行相应步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解这些成本信息,可避免在从演示环境过渡到共享环境时出现意外费用。必须注明支撑答案的具体内容,否则操作人员就无法区分是虚假信息还是索引缺失导致的错误。
@app.post("/query")
def query_graph_rag(request: QueryRequest):
query = request.query.strip()
graph = build_graph(SAMPLE_TRIPLES)
answer, path, context, ranked_paths = answer_query(query, graph)
return {
"query": query,
"answer": answer,
"reasoning_path": context,
"path_nodes": path,
"ranked_paths": ranked_paths,
}
从原型到生产环境:规模扩展
在将桥接原型过渡到生产环境之前,应在修改代码前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是虚假信息还是索引缺失导致的错误。 在将桥接原型过渡到生产环境之前,应在修改代码前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤出现故障时,故障原因应能指向单一的责任主体。
而非错综复杂的管道。1. 自动提取流程(真正的瓶颈)
在处理“自动提取”阶段时,首先明确合同条款:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约。为相关成果命名,定义成功检测标准,并拒绝默许的部分完成。 在调整提示词之前,先使用固定的问题集来衡量召回率。仅仅更换提示词很难改善较差的检索效果。
2. 持久化的企业图存储
在处理“2个持久化企业图谱”阶段时,首先需记录相关契约:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。 在调整提示词之前,先使用固定的问题集测试召回率。仅仅更换提示词往往无法改善较差的检索效果。
3. 优化后的检索与延迟管理
在实施“优化检索延迟”的三个阶段时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 应将配置信息置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。 在调整提示词之前,先使用固定的问题集来测试召回率。仅仅更换提示词很难解决检索效果不佳的问题。 在实施“优化检索延迟”的三个阶段时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 相比庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向某个具体的功能模块,而非整个复杂的流程。
4. 实施与安全
将“实施安全”这一阶段视为可测量的指标体系,效果最佳。在扩大范围之前,需记录一份标准范本、一个故障案例以及回滚说明。 应将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,杜绝默许的半完成状态。 需将分块策略与检索策略分开处理。当质量指标发生变化时,调整其中一项不应强制要求重新编写另一项。
架构概要
将“概要架构”阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,先记录一份优秀的测试用例、一个故障案例以及回滚说明。在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解这些成本,就能避免在系统从演示环境过渡到共享环境时出现意外费用。应将分块策略与检索策略分开,当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
POC系统设计概览
在当前阶段,将POC系统设计视为可度量的对象最为有效。在扩大范围之前,需记录一份理想的处理结果、一个故障案例以及回滚说明。 应将配置与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放,以便操作人员无需查看整个系统结构即可进行审计。 需将分块策略与检索策略区分开来。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。 在当前阶段,将POC系统设计视为可度量的对象最为有效。在扩大范围之前,需记录一份理想的处理结果、一个故障案例以及回滚说明。 相比庞大的脚本,更应采用小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向单一责任模块,而非复杂的流程链。
结果
在“结果”阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与已验证输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分幻觉内容与索引缺失的情况。
何时使用向量RAG与图RAG
在确定何时使用向量阶段时,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。必须引用实际作为答案依据的段落;没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。
为何这很重要
在“为何重要”这一阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个流程即可进行审计。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是虚假信息还是索引缺失导致的问题。 在“为何重要”这一阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向某个特定功能,而非整个复杂的流程。
资源
在处理“资源”阶段时,首先写下合同条款:所需的输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功标准,杜绝无声的半完成状态。 在调整提示词之前,先使用固定的问题集来测试召回率。仅仅更换提示词很难改善较差的检索效果。
你的看法是什么?
在“你的看法”阶段工作时,首先写下接口规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。
操作检查清单
在“操作检查清单”阶段工作时,首先写下接口规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。
同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理方式都是产品的一部分,而非后续需要补充的内容。
在调整提示词之前,先在固定的问题集上测试召回率。频繁更换提示词很难改善较差的检索效果。
锁定依赖版本,并记录用于演示的图像摘要。可重复性比经验知识更重要。
优先选择小型、易于测试的单元,而非庞大的脚本。当某个步骤出错时,错误应指向单一责任点,而非复杂的流程链。
在调整提示词之前,先在固定的问题集上测试召回率。频繁更换提示词很难改善较差的检索效果。
在推广整个技术栈之前,先冻结版本,为关键路径保存标准记录,并确认回滚步骤。共享环境需要设置速率限制、租户检查机制,以及明确的密钥轮换负责人。与其追求花哨的一次性演示,不如注重扎实的可靠性。
关于8e81aec03ffd的批处理说明:不要将提供者密钥放入代码仓库,为每个会话设置令牌上限,并将转录内容存储在评估测试用例的旁边,以便后续更换模型时仍能保持可比性。