Amazon Neptune with SPARQL
Amazon Neptune 是一個高效能圖形分析和無伺服器資料庫,提供卓越的可擴展性和可用性。
此範例展示 QA 鏈,其使用
SPARQL
查詢語言查詢Amazon Neptune
圖形資料庫中的 Resource Description Framework (RDF) 資料,並傳回人類可讀的回應。SPARQL 是
RDF
圖形的標準查詢語言。
此範例使用 NeptuneRdfGraph
類別,其連接 Neptune 資料庫並載入其結構描述。create_neptune_sparql_qa_chain
用於連接圖形和 LLM,以詢問自然語言問題。
此筆記本示範使用組織資料的範例。
執行此筆記本的需求
- 可從此筆記本存取的 Neptune 1.2.x 叢集
- 具有 Python 3.9 或更高版本的核心
- 對於 Bedrock 存取,請確保 IAM 角色具有此政策
{
"Action": [
"bedrock:ListFoundationModels",
"bedrock:InvokeModel"
],
"Resource": "*",
"Effect": "Allow"
}
- 用於暫存範例資料的 S3 儲存桶。儲存桶應與 Neptune 位於相同的帳戶/區域。
設定
植入 W3C 組織資料
植入 W3C 組織資料、W3C 組織本體以及一些實例。
您將需要在與 Neptune 叢集相同的區域和帳戶中建立 S3 儲存桶。將 STAGE_BUCKET
設定為該儲存桶的名稱。
STAGE_BUCKET = "<bucket-name>"
%%bash -s "$STAGE_BUCKET"
rm -rf data
mkdir -p data
cd data
echo getting org ontology and sample org instances
wget http://www.w3.org/ns/org.ttl
wget https://raw.githubusercontent.com/aws-samples/amazon-neptune-ontology-example-blog/main/data/example_org.ttl
echo Copying org ttl to S3
aws s3 cp org.ttl s3://$1/org.ttl
aws s3 cp example_org.ttl s3://$1/example_org.ttl
我們將使用來自 graph-notebook
套件的 %load
magic 命令,將 W3C 資料插入 Neptune 圖形中。在執行 %load
之前,請使用 %%graph_notebook_config
設定圖形連線參數。
!pip install --upgrade --quiet graph-notebook
%load_ext graph_notebook.magics
%%graph_notebook_config
{
"host": "<neptune-endpoint>",
"neptune_service": "neptune-db",
"port": 8182,
"auth_mode": "<[DEFAULT|IAM]>",
"load_from_s3_arn": "<neptune-cluster-load-role-arn>",
"ssl": true,
"aws_region": "<region>"
}
大量載入 org ttl - 本體和實例。
%load -s s3://{STAGE_BUCKET} -f turtle --store-to loadres --run
%load_status {loadres['payload']['loadId']} --errors --details
設定鏈
!pip install --upgrade --quiet langchain-aws
** 重新啟動核心 **
準備範例
EXAMPLES = """
<question>
Find organizations.
</question>
<sparql>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX org: <http://www.w3.org/ns/org#>
select ?org ?orgName where {{
?org rdfs:label ?orgName .
}}
</sparql>
<question>
Find sites of an organization
</question>
<sparql>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX org: <http://www.w3.org/ns/org#>
select ?org ?orgName ?siteName where {{
?org rdfs:label ?orgName .
?org org:hasSite/rdfs:label ?siteName .
}}
</sparql>
<question>
Find suborganizations of an organization
</question>
<sparql>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX org: <http://www.w3.org/ns/org#>
select ?org ?orgName ?subName where {{
?org rdfs:label ?orgName .
?org org:hasSubOrganization/rdfs:label ?subName .
}}
</sparql>
<question>
Find organizational units of an organization
</question>
<sparql>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX org: <http://www.w3.org/ns/org#>
select ?org ?orgName ?unitName where {{
?org rdfs:label ?orgName .
?org org:hasUnit/rdfs:label ?unitName .
}}
</sparql>
<question>
Find members of an organization. Also find their manager, or the member they report to.
</question>
<sparql>
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
select * where {{
?person rdf:type foaf:Person .
?person org:memberOf ?org .
OPTIONAL {{ ?person foaf:firstName ?firstName . }}
OPTIONAL {{ ?person foaf:family_name ?lastName . }}
OPTIONAL {{ ?person org:reportsTo ??manager }} .
}}
</sparql>
<question>
Find change events, such as mergers and acquisitions, of an organization
</question>
<sparql>
PREFIX org: <http://www.w3.org/ns/org#>
select ?event ?prop ?obj where {{
?org rdfs:label ?orgName .
?event rdf:type org:ChangeEvent .
?event org:originalOrganization ?origOrg .
?event org:resultingOrganization ?resultingOrg .
}}
</sparql>
"""
建立 Neptune 資料庫 RDF 圖形
from langchain_aws.graphs import NeptuneRdfGraph
host = "<your host>"
port = 8182 # change if different
region = "us-east-1" # change if different
graph = NeptuneRdfGraph(host=host, port=port, use_iam_auth=True, region_name=region)
# Optionally, change the schema
# elems = graph.get_schema_elements
# change elems ...
# graph.load_schema(elems)
使用 Neptune SPARQL QA 鏈
此 QA 鏈使用 SPARQL 查詢 Neptune 圖形資料庫,並傳回人類可讀的回應。
from langchain_aws import ChatBedrockConverse
from langchain_aws.chains import create_neptune_sparql_qa_chain
MODEL_ID = "anthropic.claude-3-5-sonnet-20241022-v2:0"
llm = ChatBedrockConverse(
model_id=MODEL_ID,
temperature=0,
)
chain = create_neptune_sparql_qa_chain(
llm=llm,
graph=graph,
examples=EXAMPLES,
)
result = chain.invoke("How many organizations are in the graph?")
print(result["result"].content)
以下是一些更多提示,可在已擷取的圖形資料上嘗試。
result = chain.invoke("Are there any mergers or acquisitions?")
print(result["result"].content)
result = chain.invoke("Find organizations.")
print(result["result"].content)
result = chain.invoke("Find sites of MegaSystems or MegaFinancial.")
print(result["result"].content)
result = chain.invoke("Find a member who is a manager of one or more members.")
print(result["result"].content)
result = chain.invoke("Find five members and their managers.")
print(result["result"].content)
result = chain.invoke(
"Find org units or suborganizations of The Mega Group. What are the sites of those units?"
)
print(result["result"].content)
新增訊息歷史記錄
Neptune SPARQL QA 鏈能夠由 RunnableWithMessageHistory
包裝。這將訊息歷史記錄新增至鏈,讓我們能夠建立一個聊天機器人,在多次調用之間保留對話狀態。
首先,我們需要一種儲存和載入訊息歷史記錄的方法。為此,每個執行緒都將建立為 InMemoryChatMessageHistory
的實例,並儲存到字典中以供重複存取。
(另請參閱:https://langchain-python.dev.org.tw/docs/versions/migrating_memory/chat_history/#chatmessagehistory)
from langchain_core.chat_history import InMemoryChatMessageHistory
chats_by_session_id = {}
def get_chat_history(session_id: str) -> InMemoryChatMessageHistory:
chat_history = chats_by_session_id.get(session_id)
if chat_history is None:
chat_history = InMemoryChatMessageHistory()
chats_by_session_id[session_id] = chat_history
return chat_history
現在,QA 鏈和訊息歷史記錄儲存可用於建立新的 RunnableWithMessageHistory
。請注意,我們必須將 query
設定為輸入金鑰,以符合基礎鏈預期的格式。
from langchain_core.runnables.history import RunnableWithMessageHistory
runnable_with_history = RunnableWithMessageHistory(
chain,
get_chat_history,
input_messages_key="query",
)
在調用鏈之前,需要為新的 InMemoryChatMessageHistory
將記住的對話產生唯一的 session_id
。
import uuid
session_id = uuid.uuid4()
最後,使用 session_id
調用啟用訊息歷史記錄的鏈。
result = runnable_with_history.invoke(
{"query": "How many org units or suborganizations does the The Mega Group have?"},
config={"configurable": {"session_id": session_id}},
)
print(result["result"].content)
當繼續使用相同的 session_id
調用鏈時,回應將在對話中先前查詢的上下文中傳回。
result = runnable_with_history.invoke(
{"query": "List the sites for each of the units."},
config={"configurable": {"session_id": session_id}},
)
print(result["result"].content)