Skip to main content

Ontotext GraphDB

Ontotext GraphDB 是一个图形数据库和知识发现工具,符合 RDFSPARQL 标准。

本笔记本展示了如何使用 LLM 提供自然语言查询(NLQ 到 SPARQL,也称为 text2sparql)功能,以供 Ontotext GraphDB 使用。

GraphDB LLM 功能

GraphDB 支持一些 LLM 集成功能,如下所述 here:

gpt-queries

  • 魔法谓词用于请求 LLM 提供文本、列表或表格,使用来自知识图谱 (KG) 的数据
  • 查询解释
  • 结果解释、总结、改写、翻译

retrieval-graphdb-connector

  • 在向量数据库中对 KG 实体进行索引
  • 支持任何文本嵌入算法和向量数据库
  • 使用与 GraphDB 为 Elastic、Solr、Lucene 使用的相同强大连接器(索引)语言
  • 自动同步 RDF 数据的更改到 KG 实体索引
  • 支持嵌套对象(GraphDB 版本 10.5 中没有 UI 支持)
  • 将 KG 实体序列化为文本,如下所示(例如,对于一个葡萄酒数据集):
Franvino:
- is a RedWine.
- made from grape Merlo.
- made from grape Cabernet Franc.
- has sugar dry.
- has year 2012.

talk-to-graph

  • 使用定义的 KG 实体索引的简单聊天机器人

在本教程中,我们将不使用 GraphDB LLM 集成,而是使用 NLQ 生成 SPARQL。我们将使用 Star Wars API (SWAPI) 本体和数据集,您可以在 here 查看。

设置

您需要一个正在运行的 GraphDB 实例。本教程展示了如何使用 GraphDB Docker 镜像 在本地运行数据库。它提供了一个 Docker Compose 配置,能够使用《星球大战》数据集填充 GraphDB。所有必要的文件,包括此笔记本,可以从 GitHub 仓库 langchain-graphdb-qa-chain-demo 下载。

docker build --tag graphdb .
docker compose up -d graphdb

您需要等待几秒钟,直到数据库在 http://localhost:7200/ 上启动。《星球大战》数据集 starwars-data.trig 会自动加载到 langchain 仓库中。可以使用本地 SPARQL 端点 http://localhost:7200/repositories/langchain 运行查询。您还可以从您喜欢的网页浏览器打开 GraphDB 工作台 http://localhost:7200/sparql,在其中可以交互式地进行查询。

  • 设置工作环境

如果您使用 conda,请创建并激活一个新的 conda 环境(例如 conda create -n graph_ontotext_graphdb_qa python=3.9.18)。

安装以下库:

pip install jupyter==1.0.0
pip install openai==1.6.1
pip install rdflib==7.0.0
pip install langchain-openai==0.0.2
pip install langchain>=0.1.5

使用以下命令运行 Jupyter:

jupyter notebook

指定本体

为了让 LLM 能够生成 SPARQL,它需要知道知识图谱的架构(本体)。可以通过 OntotextGraphDBGraph 类的两个参数之一来提供:

  • query_ontology:在 SPARQL 端点上执行的 CONSTRUCT 查询,返回 KG 架构语句。我们建议将本体存储在自己的命名图中,这样可以更容易地获取相关语句(如下例所示)。不支持 DESCRIBE 查询,因为 DESCRIBE 返回对称简明边界描述(SCBD),即也包括传入的类链接。在具有百万实例的大型图中,这样做效率不高。请查看 https://github.com/eclipse-rdf4j/rdf4j/issues/4857
  • local_file:本地 RDF 本体文件。支持的 RDF 格式有 TurtleRDF/XMLJSON-LDN-TriplesNotation-3TrigTrixN-Quads

在任何情况下,本体转储应:

  • 包含关于类、属性、属性与类的关联(使用 rdfs:domain、schema:domainIncludes 或 OWL 限制)以及分类法(重要个体)的足够信息。
  • 不包含过于冗长和无关的定义和示例,这些内容对 SPARQL 构建没有帮助。
from langchain_community.graphs import OntotextGraphDBGraph

# feeding the schema using a user construct query

graph = OntotextGraphDBGraph(
query_endpoint="http://localhost:7200/repositories/langchain",
query_ontology="CONSTRUCT {?s ?p ?o} FROM <https://swapi.co/ontology/> WHERE {?s ?p ?o}",
)
# feeding the schema using a local RDF file

graph = OntotextGraphDBGraph(
query_endpoint="http://localhost:7200/repositories/langchain",
local_file="/path/to/langchain_graphdb_tutorial/starwars-ontology.nt", # change the path here
)

无论哪种方式,本体(架构)以 Turtle 格式提供给 LLM,因为带有适当前缀的 Turtle 是最紧凑且最容易让 LLM 记住的。

《星球大战》的本体有点不寻常,因为它包含了很多关于类的具体三元组,例如物种 :Aleena 生活在 <planet/38>,它们是 :Reptile 的子类,具有某些典型特征(平均身高、平均寿命、皮肤颜色),并且特定个体(角色)是该类的代表:

@prefix : <https://swapi.co/vocabulary/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:Aleena a owl:Class, :Species ;
rdfs:label "Aleena" ;
rdfs:isDefinedBy <https://swapi.co/ontology/> ;
rdfs:subClassOf :Reptile, :Sentient ;
:averageHeight 80.0 ;
:averageLifespan "79" ;
:character <https://swapi.co/resource/aleena/47> ;
:film <https://swapi.co/resource/film/4> ;
:language "Aleena" ;
:planet <https://swapi.co/resource/planet/38> ;
:skinColor "blue", "gray" .

...

为了保持本教程的简单性,我们使用未加密的 GraphDB。如果 GraphDB 是加密的,您应该在初始化 OntotextGraphDBGraph 之前设置环境变量 'GRAPHDB_USERNAME' 和 'GRAPHDB_PASSWORD'。

os.environ["GRAPHDB_USERNAME"] = "graphdb-user"
os.environ["GRAPHDB_PASSWORD"] = "graphdb-password"

graph = OntotextGraphDBGraph(
query_endpoint=...,
query_ontology=...
)

针对 StarWars 数据集的问题回答

我们现在可以使用 OntotextGraphDBQAChain 来问一些问题。

import os

from langchain.chains import OntotextGraphDBQAChain
from langchain_openai import ChatOpenAI

# 我们将使用一个需要 OpenAI API 密钥的 OpenAI 模型。
# 不过,也可以使用其他模型:
# https://python.langchain.com/docs/integrations/chat/

# 将环境变量 `OPENAI_API_KEY` 设置为您的 OpenAI API 密钥
os.environ["OPENAI_API_KEY"] = "sk-***"

# 这里可以使用任何可用的 OpenAI 模型。
# 我们使用 'gpt-4-1106-preview' 是因为它具有更大的上下文窗口。
# 'gpt-4-1106-preview' 模型名称将来会被弃用,并将更改为 'gpt-4-turbo' 或类似名称,
# 因此请务必咨询 OpenAI API https://platform.openai.com/docs/models 以获取正确的名称。

chain = OntotextGraphDBQAChain.from_llm(
ChatOpenAI(temperature=0, model_name="gpt-4-1106-preview"),
graph=graph,
verbose=True,
)

让我们问一个简单的问题。

chain.invoke({chain.input_key: "What is the climate on Tatooine?"})[chain.output_key]


> Entering new OntotextGraphDBQAChain chain...
Generated SPARQL:
PREFIX : <https://swapi.co/vocabulary/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?climate
WHERE {
?planet rdfs:label "Tatooine" ;
:climate ?climate .
}

> Finished chain.
'塔图因的气候是干旱的。'

还有一个稍微复杂一点的问题。

chain.invoke({chain.input_key: "What is the climate on Luke Skywalker's home planet?"})[
chain.output_key
]


> Entering new OntotextGraphDBQAChain chain...
Generated SPARQL:
PREFIX : <https://swapi.co/vocabulary/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?climate
WHERE {
?character rdfs:label "Luke Skywalker" .
?character :homeworld ?planet .
?planet :climate ?climate .
}

> Finished chain.
"卢克·天行者的家乡星球的气候是干旱的。"

我们还可以问更复杂的问题,比如

chain.invoke(
{
chain.input_key: "What is the average box office revenue for all the Star Wars movies?"
}
)[chain.output_key]


> Entering new OntotextGraphDBQAChain chain...
Generated SPARQL:
PREFIX : <https://swapi.co/vocabulary/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT (AVG(?boxOffice) AS ?averageBoxOffice)
WHERE {
?film a :Film .
?film :boxOffice ?boxOfficeValue .
BIND(xsd:decimal(?boxOfficeValue) AS ?boxOffice)
}


> Finished chain.
'所有星球大战电影的平均票房收入约为 7.541 亿美元。'

链修饰符

Ontotext GraphDB QA 链允许对提示进行优化,以进一步改善您的 QA 链并提升您应用程序的整体用户体验。

"SPARQL 生成" 提示

该提示用于根据用户问题和知识图谱(KG)模式生成 SPARQL 查询。

  • sparql_generation_prompt

    默认值:

      GRAPHDB_SPARQL_GENERATION_TEMPLATE = """
    为查询图数据库编写 SPARQL SELECT 查询。
    以三重反引号分隔的本体模式(Turtle 格式)为:
    ```
    {schema}
    ```
    仅使用模式中提供的类和属性来构造 SPARQL 查询。
    不要使用在 SPARQL 查询中未明确提供的任何类或属性。
    包括所有必要的前缀。
    在您的响应中不要包含任何解释或道歉。
    不要将查询用反引号括起来。
    除生成的 SPARQL 查询外,不要包含任何文本。
    以三重反引号分隔的问题是:
    ```
    {prompt}
    ```
    """
    GRAPHDB_SPARQL_GENERATION_PROMPT = PromptTemplate(
    input_variables=["schema", "prompt"],
    template=GRAPHDB_SPARQL_GENERATION_TEMPLATE,
    )

"SPARQL 修复" 提示

有时,LLM 可能会生成带有语法错误或缺少前缀等的 SPARQL 查询。该链将尝试通过提示 LLM 修正该查询若干次。

  • sparql_fix_prompt

    默认值:

      GRAPHDB_SPARQL_FIX_TEMPLATE = """
    以下 SPARQL 查询由三重反引号分隔
    ```
    {generated_sparql}
    ```
    是无效的。
    由三重反引号分隔的错误是
    ```
    {error_message}
    ```
    请给我一个正确版本的 SPARQL 查询。
    不要改变查询的逻辑。
    在您的回答中不要包含任何解释或道歉。
    不要将查询用反引号包裹。
    不要包含除生成的 SPARQL 查询外的任何文本。
    由三重反引号分隔的本体模式为 Turtle 格式:
    ```
    {schema}
    ```
    """

    GRAPHDB_SPARQL_FIX_PROMPT = PromptTemplate(
    input_variables=["error_message", "generated_sparql", "schema"],
    template=GRAPHDB_SPARQL_FIX_TEMPLATE,
    )
  • max_fix_retries

    默认值: 5

"回答"提示

该提示用于根据从数据库返回的结果和初始用户问题回答问题。默认情况下,LLM 被指示仅使用返回结果中的信息。如果结果集为空,LLM 应告知无法回答该问题。

  • qa_prompt

    默认值:

      GRAPHDB_QA_TEMPLATE = """任务:根据 SPARQL 查询的结果生成自然语言响应。
    你是一个能够创建写得很好且易于理解的答案的助手。
    信息部分包含提供的信息,你可以使用这些信息来构建答案。
    提供的信息是权威的,你绝不能怀疑它或试图用你内部的知识来纠正它。
    让你的回答听起来像是来自 AI 助手的信息,但不要添加任何信息。
    如果没有可用的信息,不要使用内部知识来回答问题,只需说你不知道。
    信息:
    {context}

    问题:{prompt}
    有帮助的答案:"""
    GRAPHDB_QA_PROMPT = PromptTemplate(
    input_variables=["context", "prompt"], template=GRAPHDB_QA_TEMPLATE
    )

完成与 GraphDB 的 QA 交互后,可以通过在包含 Docker compose 文件的目录中运行 docker compose down -v --remove-orphans 来关闭 Docker 环境。


此页面是否有帮助?


您还可以留下详细的反馈 在 GitHub 上