我将 Formula 1 结果数据集存储在图形数据库和 SQL 数据库中,然后使用各种大型语言模型 (LLM) 通过检索增强生成 (RAG) 方法回答有关数据的问题。通过在两个系统中使用相同的数据集和问题,我评估了哪种数据库范式提供更准确和更有洞察力的结果。
检索增强生成 (RAG) 是一个人工智能框架,它通过让大型语言模型 (LLM) 在生成答案之前检索相关的外部信息来增强它们。RAG 不是仅仅依赖于模型的训练内容,而是动态查询知识源(在本文中是 SQL 或图形数据库),并将这些结果集成到其响应中。RAG 简介可以在这里找到。
SQL 数据库将数据组织到由行和列组成的表中。每行代表一条记录,每列代表一个属性。表之间的关系使用键和联接定义,所有数据都遵循固定的架构。SQL 数据库非常适合一致性和精度很重要的结构化事务性数据,例如财务、库存或患者记录。
图形数据库将数据存储为节点(实体)和边(关系),并附加了可选属性。它们不是连接表,而是直接表示关系,允许快速遍历连接的数据。图数据库非常适合对网络和关系进行建模,例如社交图谱、知识图谱或分子相互作用图谱,其中连接与实体本身一样重要。
数据
我用来比较 RAG 性能的数据集包含 1950 年至 2024 年的一级方程式结果。它包括车手和车队(车队)比赛的详细结果,涵盖排位赛、冲刺赛、正赛,甚至单圈时间和进站时间。每场比赛后车手和车队冠军的排名也包括在内。
SQL 模式
此数据集已构建为带有键的表,以便可以轻松设置 SQL 数据库。数据库的架构如下所示:

比赛是与所有类型的结果以及赛季和赛道等附加信息相关联的中心表格。结果表还与车手表和制造商表相关联,以记录每场比赛的结果。每场比赛后的冠军积分榜存储在Driver_standings和Constructor_standings表中。
图形架构
图数据库的模式如下图所示:

由于图形数据库可以在节点和关系中存储信息,因此它只需要 6 个节点,而 SQL 数据库需要 14 个表。Car 节点是一个中间节点,用于模拟车手在特定比赛中驾驶构造车的汽车。由于车手 - 构造车手配对会随着时间的推移而变化,因此需要为每场比赛定义这种关系。比赛结果存储在关系中,例如 :RACED 在 Car 和 Race 之间。 而 :STOOD_AFTER 关系包含每场比赛后的车手和车队冠军排名。
查询数据库
我使用 LangChain 为这两种数据库类型构建了一个 RAG 链,该链根据用户问题生成查询,运行查询,并将查询结果转换为对用户的答案。代码可以在此存储库中找到。我定义了一个通用系统提示,可用于生成任何 SQL 或图形数据库的查询。通过将自动生成的数据库架构插入提示,包含唯一特定于数据的信息。系统提示可以在这里找到。
这是一个如何初始化模型链并提出问题的示例:“哪个车手赢得了比利时的 92 年大奖赛?
from langchain_community.utilities import SQLDatabase
from langchain_openai import ChatOpenAI
from qa_chain import GraphQAChain
from config import DATABASE_PATH
# connect to database
connection_string = f"sqlite:///{DATABASE_PATH}"
db = SQLDatabase.from_uri(connection_string)
# initialize LLM
llm = ChatOpenAI(temperature=0, model="gpt-5")
# initialize qa chain
chain = GraphQAChain(llm, db, db_type='SQL', verbose=True)
# ask a question
chain.invoke("What driver won the 92 Grand Prix in Belgium?")
返回:
{'write_query': {'query': "SELECT d.forename, d.surname
FROM results r
JOIN races ra ON ra.raceId = r.raceId
JOIN drivers d ON d.driverId = r.driverId
WHERE ra.year = 1992
AND ra.name = 'Belgian Grand Prix'
AND r.positionOrder = 1
LIMIT 10;"}}
{'execute_query': {'result': "[('Michael', 'Schumacher')]"}}
{'generate_answer': {'answer': 'Michael Schumacher'}}
SQL 查询联接 Results、Races 和 Drivers 表,选择 1992 年比利时大奖赛的比赛和获得第一名的车手。LLM 将 92 年转换为 1992 年,比赛名称从“比利时大奖赛”转换为“比利时大奖赛”。它从数据库架构派生了这些转换,其中包括每个表的三个示例行。查询结果是“Michael Schumacher”,LLM 返回该结果作为答案。
评估
现在我想回答的问题是,LLM 在查询 SQL 还是图形数据库方面做得更好。我定义了三个难度级别(简单、中等和困难),其中简单的问题可以通过仅从一个表或节点查询数据来回答,中等的问题是需要表或节点之间的一两个链接的问题,困难的问题需要更多的链接或子查询。对于每个难度级别,我定义了五个问题。此外,我还定义了五个无法用数据库中的数据回答的问题。
我用三个 LLM 模型(GPT-5、GPT-4 和 GPT-3.5-turbo)回答了每个问题,以分析是否需要最先进的模型,或者更旧且更便宜的模型也可以产生令人满意的结果。如果一个模型给出了正确的答案,它得 1 分,如果它回答说它无法回答问题,它得 0 分,如果它给出了错误的答案,它得 -1 分。此处列出了所有问题和答案。以下是所有模型和数据库类型的分数:

更高级的模型优于更简单的模型,这很了不起:GPT-3-turbo 答错了大约一半的问题,GPT-4 答错了 2 到 3 个问题,但无法回答 6 到 7 个问题,而 GPT-5 除了一个问题之外,所有问题都答对了。更简单的模型似乎在 SQL 上比在图形数据库上表现得更好,而 GPT-5 在任一数据库上都获得了相同的分数。
GPT-5 使用 SQL 数据库出错的唯一问题是“哪位车手赢得世界冠军最多?”刘易斯·汉密尔顿,拥有 7 次世界冠军“的答案不正确,因为刘易斯·汉密尔顿和迈克尔·舒马赫赢得了 7 次世界冠军。生成的 SQL 查询按车手汇总了冠军数量,按降序排序,仅选择第一行,而第二行的车手拥有相同数量的冠军。
使用图数据库,GPT-5 唯一做错的问题是“谁在 2017 年赢得了二级方程式冠军”,回答时回答为“刘易斯·汉密尔顿”(刘易斯·汉密尔顿当年赢得了一级方程式冠军,但没有赢得二级方程式冠军)。这是一个棘手的问题,因为数据库只包含一级方程式,而不包含二级方程式结果。预期的答案是回答,根据提供的数据无法回答这个问题。但是,考虑到系统提示中没有包含任何关于数据集的具体信息,这个问题没有被正确回答是可以理解的。
有趣的是,使用 SQL 数据库 GPT-5 给出了正确答案“Charles Leclerc”。生成的 SQL 查询仅在驱动程序表中搜索名称“Charles Leclerc”。在这里,法学硕士一定已经认识到数据库不包含二级方程式的结果,并从其常识中回答了这个问题。尽管这导致了正确答案,但在这种情况下,当 LLM 不使用提供的数据来回答问题时,可能会很危险。降低此风险的一种方法是在系统提示中明确说明数据库必须是回答问题的唯一来源。
结论
使用 Formula 1 结果数据集对 RAG 性能进行比较表明,最新的 LLM 表现异常出色,无需任何额外的提示工程即可生成高度准确且上下文感知的答案。虽然更简单的模型举步维艰,但像 GPT-5 这样的新模型可以以近乎完美的精度处理复杂的查询。重要的是,图形和 SQL 数据库方法在性能上没有显着差异——用户可以简单地选择最适合其数据结构的数据库范式。
此处使用的数据集仅作为说明性示例;使用其他数据集时,结果可能会有所不同,尤其是那些需要专业领域知识或访问非公共数据源的数据集。总体而言,这些发现凸显了检索增强法学硕士在将结构化数据与自然语言推理相结合方面取得了多大的进步。
