作者 | 崔皓
審校 | 重樓
摘要
本文探討了知識圖譜與大型語言模型如何聯手提升行業應用。你將了解知識圖譜的開發流程,尤其是實體識別、關系抽取和圖的構建三個關鍵環節。通過實戰示例,文章將展示如何利用自然語言處理(NLP)和大型語言模型生成知識圖譜。此外,文章還將介紹一個開源的知識圖譜項目GraphGPT。
開篇
眾所周知,知識圖譜是一種以圖結構組織和表示信息或知識的方式。在這樣的結構中,節點表示實體(如人、地點、事物等),邊則代表實體之間的各種關系。知識圖譜能夠幫助我們更有效地組織和檢索信息,從而在搜索、推薦系統、自然語言理解和多種應用場景中發揮關鍵作用。隨著大模型發展愈來愈快,利用大模型生成知識圖譜的方式也悄然興起。本文通過實戰的方式帶大家利用大語言模型生成知識圖譜。
知識圖譜的應用與開發
知識圖譜的應用
說起知識圖譜可能大家并不陌生,它在各個領域都發揮著重要的作用。
1. 醫療健康
疾病診斷與治療: 通過分析疾病、癥狀、藥物之間的關系,知識圖譜可以幫助醫生做出更準確的診斷和治療方案。
藥物研發: 知識圖譜可以整合各種生物醫學信息,加速新藥的研發過程。
2. 金融行業
風險管理與評估: 知識圖譜能夠整合個人或企業的多維度信息,從而更準確地評估貸款或投資的風險。
反欺詐: 通過分析交易模式和行為,知識圖譜可以有效地檢測和預防欺詐活動。
3. 電商和推薦系統
個性化推薦:知識圖譜可以根據用戶行為和偏好,以及商品屬性進行更精準的個性化推薦。
供應鏈優化: 通過分析供應鏈中各環節的數據,知識圖譜可以幫助企業優化存貨管理和物流。
知識圖譜的開發
知識圖譜通過連接龐大且復雜的數據點,為多個行業提供了高度相關和實用的洞見。這使得它成為現代信息時代不可或缺的一部分。
知識圖譜開發過程也比較繁瑣,需要經過如下步驟:
數據收集: 從各種來源(如文本、數據庫、網站等)收集原始數據。
數據清洗: 對收集的數據進行預處理,包括去除噪聲、標準化等。
實體識別: 識別文本中的重要實體(如名詞或專有名詞)。
關系抽取: 確定實體之間的關系(如“是”、“有”、“屬于”等)。
構建圖: 使用識別出的實體和關系構建知識圖譜。
驗證與更新: 通過人工或自動方式對知識圖譜進行驗證和動態更新。
三元組
雖然上述過程的每個步驟都很重要,但是“實體識別”,“關系抽取”,“構建圖”這三個步驟是整個開發過程的重中之重。我們需要使用三元組的方式完成識別,抽取和構建。
在大語言模型如GPT或BERT出現之前,知識圖譜主要依賴于規則匹配、詞性標注、依存解析和各類機器學習方法來抽取三元組(實體1、關系、實體2)。這些傳統方法各有優缺點,如需大量人工規則、標記數據或計算資源,泛化能力和準確性也有限。
例如:對下面三句話進行三元組的抽取
1. 小紅是我的同學。
2. 小紅是小明的鄰居。
3. 小明是我的籃球隊隊友。
我可以使用NLP方式對其進行處理,代碼如下:
from snownlp import SnowNLP
# 初始化三元組列表
triplets = []
# 待處理的文本列表
sentences = [
"小紅是我的同學。",
"小紅是小明的鄰居。",
"小明是我的籃球隊隊友。"
]
# 遍歷每個句子進行處理
for sentence in sentences:
# 使用SnowNLP進行自然語言處理
s = SnowNLP(sentence)
# 從句子中抽取名詞和動詞
words = [word for word, tag in s.tags if tag in ('nr', 'n', 'v')]
# 假設我們的三元組格式為: (實體1, 關系, 實體2)
# 在這個簡單的例子里,我們只取前兩個名詞作為實體1和實體2,動詞作為關系
if len(words) >= 3:
triplets.Append((words[0], words[2], words[1]))
# 輸出抽取出來的三元組
print(triplets)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
這里對代碼稍微做一下解釋:
- 先初始化一個空的triplets列表,用于存放抽取出來的三元組。
- 然后,定義了一個sentences列表,包含三個待處理的句子。
- 使用for循環遍歷這些句子。
- 使用SnowNLP對每個句子進行自然語言處理。
- 通過s.tags獲取詞性標注,并抽取出名詞('n')和人名('nr')以及動詞('v')。
- 如果一個句子中包含至少三個這樣的詞(兩個實體和一個關系),則形成一個三元組并添加到triplets列表中。
上述代碼結果如下:
[('是', '鄰居', '小明'), ('小明', '籃球隊', '是')]
- 1.
通過結果可以看出自然語言處理(NLP)任務存在的問題:
1. 三元組的構造不準確:例如第一個三元組`('是', '鄰居', '小明')`,其中“是”并不是一個實體,而應該是一個關系。
2. 丟失了一些關鍵信息:例如第三個句子"我和小明是籃球隊的隊友"并沒有正確抽取為三元組。
這些問題揭示了一般NLP任務(尤其是基于規則或淺層NLP工具的任務)存在的一些局限性:
1. 詞性標注和句法分析的不準確性:依賴于詞性標注和句法分析工具的準確性,一旦工具出錯,后續的信息抽取也會受到影響。
2. 缺乏深度語義理解:僅僅通過詞性標注和淺層句法分析,難以準確地抽取復雜或模糊的關系。
3. 泛化能力差:對于不同類型或結構的句子,可能需要不斷地調整規則或模型。
4. 對上下文信息的利用不足:這種方法通常只考慮單個句子內的信息,而忽視了上下文信息,這在復雜文本中是非常重要的。
大語言模型如何助力知識圖譜
大語言模型,如GPT或BERT,是基于深度學習的自然語言處理模型,具有出色的文本理解和生成能力。它們能夠理解自然語言,從而使復雜的查詢和推理變得更加簡單。相比于傳統方法,大模型有以下幾點優勢:
- 文本理解能力:可以準確地抽取和理解更復雜、模糊或多義的實體和關系。
- 上下文敏感性:大模型能夠理解詞語在不同上下文中的不同含義,這對于精準抽取實體和關系至關重要。這種上下文敏感性讓模型能夠理解復雜和模糊的句子結構。
- 強大的泛化能力:由于在大量多樣化數據上進行了訓練,這些模型能夠很好地泛化到新的、未見過的數據。這意味著即使面對具有復雜結構或不常見表達方式的文本,它們也能準確地進行實體和關系抽取。
同樣的例子,我們看看大模型是如何做的。代碼如下:
from snownlp import SnowNLP
# 初始化三元組列表
triplets = []
# 待處理的文本列表
from langchAIn.llms import OpenAI
llm = OpenAI(model_name="gpt-3.5-turbo")
texts = '''小紅是我的同學。小紅是小明的鄰居。小明是我的籃球隊隊友。'''
#知識圖譜索引創建
from langchain.indexes import GraphIndexCreator
#知識圖譜問答的chain
from langchain.chains import GraphQAChain
#知識圖譜三元素的一個類。 三元素:主 謂 賓。
from langchain.graphs.NETworkx_graph import KnowledgeTriple
#創建圖譜的索引,解析文本內容
index_creator = GraphIndexCreator(llm=llm)
#創建圖譜的索引,顯示對象之間的關系
f_index_creator = GraphIndexCreator(llm=llm)
final_graph = f_index_creator.from_text('')
#對文本進行切割
for text in texts.split("."):
#將切割以后的文本生成三元組
triples = index_creator.from_text(text)
for (node1, node2, relation) in triples.get_triples():
#將三元組的信息放到final_graph中用以顯示
final_graph.add_triple(KnowledgeTriple(node1, node2,relation ))
print("=================")
print(node1)
print(relation)
print(node2)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
上面這段代碼用于構建知識圖譜。它用到了三個主要的模塊:`OpenAI`、`GraphIndexCreator` 和 `GraphQAChain`,以及一個輔助類:`KnowledgeTriple`。主要內容包括:
- OpenAI 初始化:`llm = OpenAI(model_name="gpt-3.5-turbo")` 。初始化了 `gpt-3.5-turbo` 的大型語言模型(LLM)。
- 輸入文本:`texts = '小紅是我的同學。小紅是小明的鄰居。小明是我的籃球隊隊友。'` 定義要處理的文本,其中包含多個句子。
- 創建圖譜索引:`index_creator = GraphIndexCreator(llm=llm)` 使用 `GraphIndexCreator` 類來創建一個圖索引生成器,它會用到先前初始化的大型語言模型。
- 初始化最終圖:`final_graph = f_index_creator.from_text('')` 初始化了一個空的知識圖譜,用于存放最終的三元組信息。
- 文本切割和三元組生成: `for text in texts.split("."):`這個循環通過句號切割文本,然后對每一個非空句子生成三元組。
- `triples = index_creator.from_text(text)`通過 `index_creator` 的 `from_text` 方法,為每個句子生成三元組。
- 三元組存儲和輸出:`final_graph.add_triple(KnowledgeTriple(node1, node2,relation ))`將生成的三元組添加到 `final_graph` 知識圖譜中。
下面是運行結果:
=================
小紅
是
我的同學
=================
小紅
是
小明的鄰居
=================
小明
是
我的籃球隊隊友
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
看起來是不是比上面NLP處理的結果要好些。
如果我們將texts變量進行修改:
texts = '''小鳥國,正式名稱飛禽國度(ISO:飛禽國度),是位于新世界南部的國家。它以領土面積而言是世界第七大國家;是人口最多的國家,一直是世界上人口最多的民主國家。小鳥國南臨翡翠海,西南瀕臨藍色海洋,東南瀕臨碧玉海,與翼足國家在西部接壤;北部與巨翼國、鳴蟲國和象牙國相鄰;東部與彩虹國和翡翠國接壤。在翡翠海中,小鳥國位于雙島國家和翡翠群島,與彩虹國、碧玉國和綠洲國共享海上邊界。翡翠海是7大文明遺跡之一,在天門東邊'''
- 1.
用一個特別復雜的例子來表示,這個例子是我們虛擬的一個國家,并且描述了和這個國家相關的一些其他國家,看上去比較復雜。此時,我們加入圖表的方式,通過節點和邊展示這樣的復雜關系。加入如下代碼:
import networkx as nx
import matplotlib.pyplot as plt
#創建一個空的有向圖
G = nx.DiGraph()
#將上面得到的三元組放到圖像的邊中
#source - node1 , target - node2 , relation - relation
G.add_edges_from((source, target, {'relation': relation}) for source, relation, target in final_graph.get_triples())
#指定圖像的大小和分辨率
plt.figure(figsize=(8,3), dpi=500)
#通過spring算法定義節點的布局
pos = nx.spring_layout(G, k=3, seed=0)
edge_labels = nx.get_edge_attributes(G, 'relation')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=8,font_family='simhei')
#定義顯示中文字體
nx.draw_networkx(G, font_family = 'simhei')
#關閉坐標軸顯示
plt.axis('off')
plt.show()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
這段代碼使用了`networkx`和`matplotlib.pyplot`庫來可視化一個有向圖(即知識圖譜),其中的節點和邊是從之前抽取的三元組(實體-關系-實體)中得到的。
1. 創建空的有向圖: `G = nx.DiGraph()`
2. 添加邊到圖中:
`G.add_edges_from((source, target, {'relation': relation}) for source, relation, target in final_graph.get_triples())`
把之前從文本中抽取出的三元組添加到圖`G`中作為邊。每一條邊都有一個起點(`source`),一個終點(`target`)以及一個表示兩者關系的標簽(`relation`)。
3. 設置圖像大小和分辨率:
`plt.figure(figsize=(8,3), dpi=500)`
設置了圖像的大小(8x3)和分辨率(500 DPI)。
4. 定義節點布局:
`pos = nx.spring_layout(G, k=3, seed=0)`
使用“spring”布局算法來確定圖中每個節點的位置。`k`是一個用于設置節點間距的參數,`seed`是隨機數生成器的種子。
5. 獲取邊標簽并繪制:
`edge_labels = nx.get_edge_attributes(G, 'relation')`
`nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=8, font_family='simhei')`
獲取了圖中每一條邊的標簽(即`relation`)并進行了繪制。
6. 繪制圖:
`nx.draw_networkx(G, font_family = 'simhei')`
繪制了整個圖,其中使用了`simhei`字體以支持中文字符。
7. 關閉坐標軸顯示并展示圖像:
`plt.axis('off')`
`plt.show()`
關閉了坐標軸的顯示,并展示了最終的圖像。
看看結果如何:
=================
小鳥國
是
新世界南部的國家
=================
小鳥國
以
領土面積而言是世界第七大國家
=================
小鳥國
是
人口最多的國家
=================
小鳥國
是
世界上人口最多的民主國家
=================
小鳥國
南臨
翡翠海
=================
小鳥國
西南瀕臨
藍色海洋
=================
小鳥國
東南瀕臨
碧玉海
=================
小鳥國
與翼足國家
在西部接壤
=================
小鳥國
北部與巨翼國、鳴蟲國和象牙國
相鄰
=================
小鳥國
東部與彩虹國和翡翠國
接壤
=================
小鳥國
在翡翠海中
位于雙島國家和翡翠群島
=================
小鳥國
與彩虹國、碧玉國和綠洲國
共享海上邊界
=================
翡翠海
是
7大文明遺跡之一
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
生成的知識圖譜圍繞著小鳥國把與之相關的地方都連接起來了。
接著針對上面的知識圖譜提出問題,如下代碼:
chain = GraphQAChain.from_llm(llm, graph=final_graph, verbose=True)
chain.run('翡翠海在哪里?')
- 1.
- 2.
結果返回:
> Entering new chain...
Entities Extracted:
翡翠海
Full Context:
翡翠海 7大文明遺跡之一 是
- 1.
- 2.
- 3.
- 4.
- 5.
知識圖譜通過三元組的方式告訴我們 “翡翠海”(實體1),“7大文明遺跡之一”(實體2),“是”(關系)。
開箱即用的GraphGPT
有了上面的實戰經驗,告訴我們利用大模型能夠更好地進行知識圖譜的處理,并且可以針對知識圖譜的內容進行提問。如果覺得自己開發這樣一套系統比較麻煩的同學,可以嘗試使用Github上面開源的GraphGPT。
我把地址放在這里,https://github.com/varunshenoy/GraphGPT
GraphGPT 是一個用于將非結構化自然語言轉換成知識圖譜的項目。它可以接受各種類型的輸入,例如電影劇情梗概、維基百科頁面或視頻轉錄,然后生成一個可視化圖表來展示實體(Entities)之間的關系。GraphGPT 支持連續的查詢,可以用于更新現有圖譜的狀態或創建全新的結構。
安裝步驟
下載依賴項
運行npm install 來下載所需的依賴,當前只需要react-graph-vis。
獲取OpenAI API密鑰
確保您擁有一個OpenAI API密鑰,這將用于在運行查詢時輸入。
啟動項目
運行npm run start,GraphGPT應該會在新的瀏覽器標簽頁中打開。
通過這些步驟,您應該能夠運行GraphGPT并開始將自然語言文本轉換為知識圖譜。
運行代碼
根據上面的步驟運行代碼之后,會在本地http://localhost:3000 打開一個網站,網站中需要輸入知識圖譜的文本,以及OpenAI 的Key。
我們嘗試輸入要生成知識圖譜的文字,然后點擊“Generate”按鈕,然后生成圖形的關系。
代碼描述
這個開源項目是通過js 實現了大模型的調用,從而生成知識圖譜。從下圖的代碼結構上看,主要的業務邏輯在App.js 文件和prompts 目錄下面。
在這個React應用中,主要的目的是通過GPT模型生成一個基于輸入自然語言的知識圖譜。我們把主要的函數(App.js)進行解釋:
- 導入依賴import './App.css'; // 導入CSS樣式import Graph from "react-graph-vis"; // 導入react-graph-vis庫,用于圖的可視化
import React, { useState } from "react"; // 導入React和useState鉤子 - 定義常量const DEFAULT_PARAMS = {...}; // GPT模型的默認參數
const SELECTED_PROMPT = "STATELESS"; // 默認使用的提示類型const options = {...}; // 圖的布局和樣式選項 - 主要函數組件 - Appfunction App() { const [graphState, setGraphState] = useState({...}); // 使用useState管理圖的狀態
const clearState = () => {...}; // 清除圖的狀態
const updateGraph = (updates) => {...}; // 更新圖的狀態
const queryStatelessPrompt = (prompt, apiKey) => {...}; // 查詢無狀態的提示
const queryStatefulPrompt = (prompt, apiKey) => {...}; // 查詢有狀態的提示
const queryPrompt = (prompt, apiKey) => {...}; // 根據選擇的提示類型進行查詢
const createGraph = () => {...}; // 創建圖 return (<div className='container'> ... </div>); // 返回應用的JSX結構
} - 清除圖的狀態 - clearStateconst clearState = () => {
setGraphState({
nodes: [],
edges: []
});
};
這個函數清除圖的所有節點和邊。 - 更新圖的狀態 - updateGraphconst updateGraph = (updates) => {
var current_graph = JSON.parse(JSON.stringify(graphState)); // 深拷貝當前圖的狀態
// ...
setGraphState(current_graph); // 設置新的圖狀態
};
這個函數負責根據提供的更新信息(節點、邊、顏色等)來更新圖的狀態。 - 與GPT API進行交互 - queryStatelessPrompt 和 queryStatefulPrompt這兩個函數與GPT模型進行交互,獲取模型生成的文本,并用這些信息更新圖。
- 創建圖 - createGraph
const createGraph = () => {
// ...
queryPrompt(prompt, apiKey); // 調用queryPrompt進行圖的生成
};
```
- 1.
- 2.
- 3.
- 4.
- 5.
這個函數獲取用戶輸入的提示和API密鑰,然后調用`queryPrompt`函數生成圖。
另外,又針對兩種prompt狀態生成兩種不同的prompt文件:stateful.prompt和stateless.prompt都用于處理知識圖譜中的實體和關系。stateful.prompt是狀態感知的,會根據當前圖的狀態來添加或修改節點和邊。適用于需要持續更新的場景。相對地,stateless.prompt是無狀態的,只根據給定的提示生成一系列更新,與當前圖的狀態無關。適用于一次性或獨立的更新任務。兩者主要的區別在于是否需要考慮圖的當前狀態。
總結
文章闡述了知識圖譜和大模型在現代信息處理和決策中無可替代的地位。從醫療診斷到金融風險評估,再到個性化推薦,知識圖譜展示了其強大的應用潛力。同時,大型語言模型如GPT也在知識圖譜的生成和查詢中扮演了關鍵角色。借助大語言模型可以高效地創建知識圖譜,還能靈活地進行實時更新和查詢。本文對于任何希望將大數據和AI技術融入實際應用的人來說,都具有指導意義。
作者介紹
崔皓,51CTO社區編輯,資深架構師,擁有18年的軟件開發和架構經驗,10年分布式架構經驗。