開源 AI 食譜文件
使用知識圖譜增強 RAG 推理能力
並獲得增強的文件體驗
開始使用
使用知識圖譜增強 RAG 推理能力
知識圖譜提供了一種以人類和機器都能理解的格式來建模和儲存相互關聯資訊的方法。這些圖由 *節點* 和 *邊* 組成,分別代表實體及其關係。與傳統資料庫不同,圖固有的表達能力可以實現更豐富的語義理解,同時提供了適應新實體型別和關係的靈活性,而不受固定模式的限制。
透過將知識圖譜與嵌入 (向量搜尋) 相結合,我們可以利用 *多跳連線* 和 *資訊的上下文理解* 來增強大語言模型 (LLM) 的推理和可解釋性。
本筆記本探討了這種方法的實際實現,演示瞭如何:
- 使用合成數據集在 Neo4j 中構建一個與研究出版物相關的知識圖譜,
- 使用 嵌入模型 將我們的資料欄位子集投影到高維向量空間中,
- 在這些嵌入上構建向量索引以實現相似性搜尋,以及
- 透過使用 LangChain 將使用者查詢輕鬆轉換為 Cypher 語句,從而用自然語言從我們的圖譜中提取見解。
初始化
%pip install neo4j langchain langchain_openai langchain-community python-dotenv --quiet
設定 Neo4j 例項
我們將使用 Neo4j 建立我們的知識圖譜,它是一個專門從事圖資料庫技術的開源資料庫管理系統。
為了快速簡便地進行設定,您可以在 Neo4j Aura 上啟動一個免費例項。
然後,您可以使用一個 .env
檔案將 NEO4J_URI
、NEO4J_USERNAME
和 NEO4J_PASSWORD
設定為環境變數。
import dotenv
dotenv.load_dotenv(".env", override=True)
Langchain 提供了 Neo4jGraph
類來與 Neo4j 互動。
import os
from langchain_community.graphs import Neo4jGraph
graph = Neo4jGraph(
url=os.environ["NEO4J_URI"],
username=os.environ["NEO4J_USERNAME"],
password=os.environ["NEO4J_PASSWORD"],
)
將資料集載入到圖譜中
下面的示例建立了與我們的 Neo4j
資料庫的連線,並用包含研究文章及其作者的 合成數據 填充它。
實體有:
- 研究員 (Researcher)
- 文章
- 主題
關係有:
- 研究員 —[發表了]—> 文章
- 文章 —[屬於主題]—> 主題
from langchain_community.graphs import Neo4jGraph
graph = Neo4jGraph()
q_load_articles = """
LOAD CSV WITH HEADERS
FROM 'https://raw.githubusercontent.com/dcarpintero/generative-ai-101/main/dataset/synthetic_articles.csv'
AS row
FIELDTERMINATOR ';'
MERGE (a:Article {title:row.Title})
SET a.abstract = row.Abstract,
a.publication_date = date(row.Publication_Date)
FOREACH (researcher in split(row.Authors, ',') |
MERGE (p:Researcher {name:trim(researcher)})
MERGE (p)-[:PUBLISHED]->(a))
FOREACH (topic in [row.Topic] |
MERGE (t:Topic {name:trim(topic)})
MERGE (a)-[:IN_TOPIC]->(t))
"""
graph.query(q_load_articles)
讓我們檢查一下節點和關係是否已正確初始化。
>>> graph.refresh_schema()
>>> print(graph.get_schema)
Node properties: Article {title: STRING, abstract: STRING, publication_date: DATE, embedding: LIST} Researcher {name: STRING} Topic {name: STRING} Relationship properties: The relationships: (:Article)-[:IN_TOPIC]->(:Topic) (:Researcher)-[:PUBLISHED]->(:Article)
我們的知識圖譜可以在 Neo4j 工作區中進行檢查。
構建向量索引
現在我們構建一個向量索引,以便根據 *主題、標題和摘要* 高效地搜尋相關的 *文章* 。該過程涉及使用這些欄位計算每篇文章的嵌入。在查詢時,系統透過採用相似性度量 (例如餘弦距離) 來找到與使用者輸入最相似的文章。
from langchain_community.vectorstores import Neo4jVector
from langchain_openai import OpenAIEmbeddings
vector_index = Neo4jVector.from_existing_graph(
OpenAIEmbeddings(),
url=os.environ["NEO4J_URI"],
username=os.environ["NEO4J_USERNAME"],
password=os.environ["NEO4J_PASSWORD"],
index_name="articles",
node_label="Article",
text_node_properties=["topic", "title", "abstract"],
embedding_node_property="embedding",
)
注意:要訪問 OpenAI 嵌入模型,您需要建立一個 OpenAI 帳戶,獲取一個 API 金鑰,並將 OPENAI_API_KEY
設定為環境變數。您可能還會發現嘗試使用其他 嵌入模型 整合也很有用。
基於相似性的問答
Langchain RetrievalQA
使用上述向量索引作為檢索器建立一個問答 (QA) 鏈。
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
vector_qa = RetrievalQA.from_chain_type(llm=ChatOpenAI(), chain_type="stuff", retriever=vector_index.as_retriever())
讓我們問一下 “*哪些文章討論了人工智慧可能如何影響我們的日常生活?*”
>>> r = vector_qa.invoke(
... {
... "query": "which articles discuss how AI might affect our daily life? include the article titles and abstracts."
... }
... )
>>> print(r["result"])
The articles that discuss how AI might affect our daily life are: 1. **The Impact of AI on Employment: A Comprehensive Study** *Abstract:* This study analyzes the potential effects of AI on various job sectors and suggests policy recommendations to mitigate negative impacts. 2. **The Societal Implications of Advanced AI: A Multidisciplinary Analysis** *Abstract:* Our study brings together experts from various fields to analyze the potential long-term impacts of advanced AI on society, economy, and culture. These two articles would provide insights into how AI could potentially impact our daily lives from different perspectives.
遍歷知識圖譜進行推理
知識圖譜非常適合建立實體之間的聯絡,從而能夠提取模式和發現新的見解。
本節演示瞭如何實現這一過程,並使用自然語言查詢將結果整合到 LLM 管道中。
使用 LangChain 的 Graph-Cypher-Chain
為了構建富有表現力和高效的查詢,Neo4j
使用者使用 Cypher
,這是一種受 SQL 啟發的宣告式查詢語言。LangChain
提供了 GraphCypherQAChain
包裝器,這是一個抽象層,允許使用自然語言查詢圖資料庫,從而更容易將基於圖的資料檢索整合到 LLM 管道中。
實際上,GraphCypherQAChain
會:
- 應用上下文學習 (提示工程),從使用者輸入 (自然語言) 生成 Cypher 語句 (用於 Neo4j 等圖資料庫的查詢),
- 針對圖資料庫執行所述語句,並且
- 將結果作為上下文提供,以使 LLM 的響應基於準確、最新的資訊。
注意: 此實現涉及執行模型生成的圖查詢,這帶來了固有的風險,例如對資料庫中敏感資料的意外訪問或修改。為了減輕這些風險,請確保您的資料庫連線許可權受到儘可能嚴格的限制,以滿足您的鏈/代理的特定需求。雖然這種方法降低了風險,但並不能完全消除它。
from langchain.chains import GraphCypherQAChain
from langchain_openai import ChatOpenAI
graph.refresh_schema()
cypher_chain = GraphCypherQAChain.from_llm(
cypher_llm=ChatOpenAI(temperature=0, model_name="gpt-4o"),
qa_llm=ChatOpenAI(temperature=0, model_name="gpt-4o"),
graph=graph,
verbose=True,
)
使用自然語言的查詢示例
在下面的示例中請注意,Cypher 查詢執行的結果是如何作為上下文提供給 LLM 的。
“ Emily Chen 發表了多少篇文章?”
在這個例子中,我們的問題“*Emily Chen 發表了多少篇文章?*” 將被翻譯成 Cypher 查詢:
MATCH (r:Researcher {name: "Emily Chen"})-[:PUBLISHED]->(a:Article)
RETURN COUNT(a) AS numberOfArticles
該查詢匹配標籤為 Author
且姓名為 ‘Emily Chen’ 的節點,並遍歷 PUBLISHED
關係到 Article
節點。然後,它計算與 ‘Emily Chen’ 連線的 Article
節點的數量。
>>> # the answer should be '7'
>>> cypher_chain.invoke({"query": "How many articles has published Emily Chen?"})
[1m> Entering new GraphCypherQAChain chain...[0m Generated Cypher: [32;1m[1;3mcypher MATCH (r:Researcher {name: "Emily Chen"})-[:PUBLISHED]->(a:Article) RETURN COUNT(a) AS numberOfArticles [0m Full Context: [32;1m[1;3m[{'numberOfArticles': 7}][0m [1m> Finished chain.[0m
“ 有沒有哪對研究人員一起發表了超過三篇文章?”
在這個例子中,查詢“*有沒有哪對研究人員一起發表了超過三篇文章?*”會生成以下 Cypher 查詢:
MATCH (r1:Researcher)-[:PUBLISHED]->(a:Article)<-[:PUBLISHED]-(r2:Researcher)
WHERE r1 <> r2
WITH r1, r2, COUNT(a) AS sharedArticles
WHERE sharedArticles > 3
RETURN r1.name, r2.name, sharedArticles
該查詢會從 Researcher
節點遍歷到 PUBLISHED
關係以找到連線的 Article
節點,然後再遍歷回來以找到 Researcher
對。
>>> # the answer should be David Johnson & Emily Chen, Robert Taylor & Emily Chen
>>> cypher_chain.invoke(
... {"query": "are there any pair of researchers who have published more than three articles together?"}
... )
[1m> Entering new GraphCypherQAChain chain...[0m Generated Cypher: [32;1m[1;3mcypher MATCH (r1:Researcher)-[:PUBLISHED]->(a:Article)<-[:PUBLISHED]-(r2:Researcher) WHERE r1 <> r2 WITH r1, r2, COUNT(a) AS sharedArticles WHERE sharedArticles > 3 RETURN r1.name, r2.name, sharedArticles [0m Full Context: [32;1m[1;3m[{'r1.name': 'David Johnson', 'r2.name': 'Emily Chen', 'sharedArticles': 4}, {'r1.name': 'Robert Taylor', 'r2.name': 'Emily Chen', 'sharedArticles': 4}, {'r1.name': 'Emily Chen', 'r2.name': 'David Johnson', 'sharedArticles': 4}, {'r1.name': 'Emily Chen', 'r2.name': 'Robert Taylor', 'sharedArticles': 4}][0m [1m> Finished chain.[0m
“ 哪位研究員與最多的同行合作過?”
讓我們找出與最多同行合作的研究員是誰。我們的查詢“*哪位研究員與最多的同行合作過?*”現在會生成以下 Cypher:
MATCH (r:Researcher)-[:PUBLISHED]->(:Article)<-[:PUBLISHED]-(peer:Researcher)
WITH r, COUNT(DISTINCT peer) AS peerCount
RETURN r.name AS researcher, peerCount
ORDER BY peerCount DESC
LIMIT 1
在這裡,我們需要從所有 Researcher
節點開始,遍歷它們的 PUBLISHED
關係以找到連線的 Article
節點。對於每個 Article
節點,Neo4j 隨後會遍歷回來,找到也發表了同一篇文章的其他 Researcher
節點 (同行)。
>>> # the answer should be 'David Johnson'
>>> cypher_chain.invoke({"query": "Which researcher has collaborated with the most peers?"})
[1m> Entering new GraphCypherQAChain chain...[0m Generated Cypher: [32;1m[1;3mcypher MATCH (r1:Researcher)-[:PUBLISHED]->(:Article)<-[:PUBLISHED]-(r2:Researcher) WHERE r1 <> r2 WITH r1, COUNT(DISTINCT r2) AS collaborators RETURN r1.name AS researcher, collaborators ORDER BY collaborators DESC LIMIT 1 [0m Full Context: [32;1m[1;3m[{'researcher': 'David Johnson', 'collaborators': 6}][0m [1m> Finished chain.[0m
< > 在 GitHub 上更新