不久前,基于知識的問答(Knowledge-based QnA,簡稱 KBQA)還是一種新鮮事物。 如今,借助 檢索增強生成(Retrieval Augmented Generation,簡稱 RAG), KBQA 已經成為任何 AI 愛好者的“家常便飯”。 令人著迷的是,隨著大語言模型(LLMs)的發展, 自然語言處理(NLP)的可能性正在迅速擴展, 并且每天都在變得更好。 研究智能體:應對大規模文本語料問答的挑戰我創建了一個 自主 AI 研究智能體(Autonomous AI Research Agent), 它能夠憑借 深度多跳推理能力 來回答復雜問題。 ?? [1] 有不少人嘗試了該方法并給我反饋。 感謝大家的意見! 我收集了這些建議,并對代碼進行了改進, 以解決原始實現中的一些問題。 我計劃寫一篇獨立的文章來介紹這些改進。 在本文中, 我想分享另一個想法: 當它與遞歸式 RAG 結合時, 可能有助于創建一個更強大的研究型智能體。 這個想法來源于我在小型 LLM 上進行的遞歸 RAG 實驗, 以及在 Medium 上閱讀的一些思路, 特別是 知識圖譜增強生成(Knowledge-Graph Augmented Generation)。 摘要知識圖譜(Knowledge Graph,簡稱 KG)或任何圖結構, 由 節點(Nodes) 和 邊(Edges) 組成。 ·每個 節點 代表一個概念·每條 邊 表示一對概念之間的關系 在本文中, 我將分享一種方法, 可以將任意文本語料轉換為 概念圖(Graph of Concepts,GC)。 我在這里將“概念圖(GC)”和“知識圖譜(KG)”交替使用, 以更好地描述我要演示的內容。 本實現中使用的所有組件都可以在本地搭建, 因此該項目能夠輕松在個人電腦上運行。 我采取了一種 不依賴 GPT 的方法, 因為我更傾向于使用小型開源模型。 在這里, 我使用了強大的 Mistral 7B OpenOrca instruct 和 Zephyr 模型。 這些模型可以通過 Ollama 在本地運行。 像 Neo4j 這樣的數據庫, 可以輕松存儲和檢索圖數據。 但在這里,為了保持簡單, 我使用了 Pandas 內存數據框 和 NetworkX Python 庫。 本文目標·將任意文本語料轉換為概念圖(GC)·將其可視化,就像本文橫幅圖片中那樣美觀·支持交互操作:拖動節點和邊、縮放視圖、修改圖的物理屬性 ?? GitHub 項目頁面(效果展示): https://rahulnyk./knowledge_graph/ 在開始介紹方法之前, 我們需要先理解 知識圖譜的基本思想,以及我們為什么需要它。 如果你已經熟悉這些概念, 可以跳過下一節。 知識圖譜示例來看以下文本: Mary had a little lamb, You’ve heard this tale before; But did you know she passed her plate, And had a little more!
下面是該文本作為知識圖譜的一種可能表示: 下面這篇來自 IBM 的文章,非常貼切地解釋了知識圖譜的基本概念: 什么是知識圖譜? | IBM[2] 了解知識圖譜:語義元數據網絡,用來表示一組相互關聯的實體。 引用文章中的一段話來總結知識圖譜的核心思想:知識圖譜(Knowledge Graph),又稱語義網絡(Semantic Network), 表示由現實世界中的實體(即對象、事件、情境或概念)組成的網絡, 并說明它們之間的關系。 這些信息通常存儲在圖數據庫中,并以圖結構的形式可視化, 因此被稱為“圖譜”。
為什么需要知識圖譜?知識圖譜的用途非常廣泛。 ·我們可以運行圖算法,計算任意節點的中心性, 以理解某個概念(節點)在整體工作中的重要性。·我們可以分析相連或不相連的概念集合, 或計算概念的社群(communities), 從而對主題有更深入的理解。·我們可以理解看似無關的概念之間的聯系。 此外,知識圖譜還可以用來實現 圖檢索增強生成(Graph Retrieval Augmented Generation,簡稱 GRAG 或 GAG), 讓我們能夠“和文檔對話”。 這比傳統的 RAG 效果更好,因為傳統 RAG 存在一些缺陷。 例如,僅依賴語義相似度來檢索最相關的上下文并不總是有效: ·當查詢沒有提供足夠的上下文來表達真實意圖時;·當相關上下文分散在龐大的語料庫中時; RAG 就可能難以發揮作用。 舉個例子假設我們有這樣一個問題: 請告訴我在《百年孤獨》一書中,José Arcadio Buendía 的家族譜系。
這本書記錄了 José Arcadio Buendía 家族的 7 代人, 而且其中有一半的人物都叫 José Arcadio Buendía。 在這種情況下,想要用一個簡單的 RAG 流程回答這個問題,幾乎是不可能的挑戰。 RAG 并不能告訴你該問什么問題。 然而,很多時候問對問題比得到答案更重要。 圖增強生成(Graph Augmented Generation,GAG) 在一定程度上可以解決這些問題。 更進一步,我們還可以結合兩者, 構建一個 圖增強的檢索增強生成(Graph Augmented RAG) 流程, 從而獲得兩者的優勢。 總結·圖譜不僅有趣,而且非常有用。·它能帶來更強大的信息分析與推理能力。·并且,它們的可視化效果往往非常美觀。
創建概念圖(Graph of Concepts)如果你問 GPT:“如何從給定文本中創建一個知識圖譜?” 它可能會建議如下流程: 1.提取文本中的概念和實體 —— 這些就是節點(nodes);2.提取概念之間的關系 —— 這些就是邊(edges);3.將節點(概念)和邊(關系)存儲到圖數據結構或圖數據庫中;4.可視化 —— 即使只是為了美觀。 步驟 3 和 4 很容易理解。 但 步驟 1 和 2 該如何實現呢? 方法流程圖下面是我設計的一個方法流程圖,用來從任意文本語料中提取概念圖。 它與上面的方法類似,但有一些細微差別。 主要步驟:1.將文本語料分割為若干塊(chunks),并為每個塊分配一個 chunk_id 。2.對每個文本塊,使用 LLM 提取概念及其語義關系。·給這種關系分配權重 W1。·相同的一對概念之間可以有多種關系。·每種關系都表示為一條邊。3.考慮上下文鄰近性:同一文本塊中出現的概念,默認也存在一定關系。·給這種“上下文關系”分配權重 W2。·注意:相同的概念對可能出現在多個塊中。4.合并相似的概念對:·累加它們的權重;·合并它們的關系;·最終,每對不同概念之間只保留一條邊,邊上既有權重,又有關系描述。 ?? 本方法的 Python 實現代碼可以在本文分享的 GitHub 倉庫中查看。 接下來,我們將簡要走讀實現的關鍵思想。 示例語料為了演示方法,這里我選用了一篇 在 PubMed/Cureus 上發表的綜述文章(遵循 Creative Commons 署名協議)。 作者的署名在本文末尾致謝。 印度應對醫療衛生人力資源挑戰的機遇 | Cureus[3] 印度的健康指標近年來有所改善,但仍落后于同類國家……
使用 Mistral 模型與提示詞在上面流程圖中的 步驟 1 很容易: Langchain 提供了豐富的 文本分割器(text splitters), 我們可以直接用來將文本分割為塊。 真正有趣的是 步驟 2。 為了提取概念及其關系,我使用了 Mistral 7B 模型。 在最終確定最佳變體之前,我嘗試了以下幾種: ·Mistral Instruct·Mistral OpenOrca·Zephyr(Hugging Face 上基于 Mistral 的衍生模型) 我使用了這些模型的 4-bit 量化版本 —— 這樣我的 Mac 就不會“崩潰”了 ?? —— 并通過 Ollama 在本地運行。 ?? Ollama 官網[4] 一個可以在本地快速運行大語言模型的平臺。
這些模型都是 指令微調(instruction-tuned) 模型, 包含系統提示(system prompt)和用戶提示(user prompt)。 只要我們要求,它們通常能很好地遵循指令,并將結果整齊地格式化為 JSON。 經過多次嘗試,我最終選擇了 Zephyr 模型,并使用如下提示詞: SYS_PROMPT =( 'You are a network graph maker who extracts terms and their relations from a given context. ' 'You are provided with a context chunk (delimited by ```) Your task is to extract the ontology ' 'of terms mentioned in the given context. These terms should represent the key concepts as per the context. \n' 'Thought 1: While traversing through each sentence, Think about the key terms mentioned in it.\n' '\tTerms may include object, entity, location, organization, person, \n' '\tcondition, acronym, documents, service, concept, etc.\n' '\tTerms should be as atomistic as possible\n\n' 'Thought 2: Think about how these terms can have one on one relation with other terms.\n' '\tTerms that are mentioned in the same sentence or the same paragraph are typically related to each other.\n' '\tTerms can be related to many other terms\n\n' 'Thought 3: Find out the relation between each such related pair of terms. \n\n' 'Format your output as a list of json. Each element of the list contains a pair of terms' 'and the relation between them, like the follwing: \n' '[\n' ' {\n' ' 'node_1': 'A concept from extracted ontology',\n' ' 'node_2': 'A related concept from extracted ontology',\n' ' 'edge': 'relationship between the two concepts, node_1 and node_2 in one or two sentences'\n' ' }, {...}\n' ']' )
USER_PROMPT = f'context: ```{input}``` \n\n output: '
如果我們把之前那首小詩丟進提示詞中, 模型輸出的結果如下: [ { 'node_1':'Mary', 'node_2':'lamb', 'edge':'owned by' }, { 'node_1':'plate', 'node_2':'food', 'edge':'contained' }, ... ]
請注意,模型甚至推斷出了 “food(食物)” 這個概念, 雖然在原始文本片段中并沒有明確提到。 是不是很神奇! 轉換為 Pandas DataFrame 如果我們將示例文章的每個文本塊都跑一遍, 然后把得到的 JSON 轉換為 Pandas DataFrame, 結果大致如下: 
這里 每一行 都表示一對概念之間的一種關系。 在圖中,每一行對應 兩個節點之間的一條邊;同一對概念之間可以存在多條邊/多種關系。 上面數據框中的 count 列,是我任意設為 4 的權重。 上下文鄰近性我假設:在文本語料中彼此位置接近出現的概念是相關的。 我們把這種關系稱為 “上下文鄰近性(contextual proximity)”。 為了計算“上下文鄰近性”的邊: 1.melt 數據框: 將 node_1 與 node_2 “熔化”為同一列,使節點落到一個統一的列中。2.自連接(self-join): 以 chunk_id 作為鍵,對上述數據框做自連接; 這樣,相同 chunk_id 的節點會兩兩成對,形成行(即潛在的邊)。3.移除自環(self-loop): 這一步也會生成“節點與自身配對”的行(自環), 即邊的起點和終點是同一節點。 為了去除自環,我們刪除所有 node_1 == node_2 的行。 最終,我們得到的這個數據框,與最初的語義關系數據框在結構上非常相似。 ·count:node_1 與 node_2 共同出現的文本塊(chunk)數量。·chunk_id:包含了所有這些共同出現的 chunk 列表。 到目前為止,我們有了兩個數據框: 1.語義關系(semantic relation)的數據框;2.上下文鄰近性(contextual proximity)關系的數據框(基于同塊共現)。 我們可以將兩者合并,以形成網絡圖的數據框。 可視化目標至此,我們已經為文本構建好了概念圖(Graph of Concepts)。 但如果就到這里戛然而止,未免意猶未盡。 我們的目標是將這個圖可視化——就像本文開頭的主圖那樣。 好消息是:我們離這個目標,已經不遠了。
創建概念網絡NetworkX 是一個 Python 庫,使得圖的處理變得非常簡單。 如果你還不熟悉這個庫,可以點擊下方鏈接了解更多: ?? NetworkX 官方文檔[5] 將 DataFrame 轉換為 NetworkX 圖把我們之前得到的數據框(DataFrame)加入到 NetworkX 圖里,只需要幾行代碼。 import networkx as nx
# 創建一個空圖 G = nx.Graph()
# 添加節點 for node in nodes: G.add_node(str(node))
# 添加邊 for index, row in dfg.iterrows(): G.add_edge( str(row['node_1']), str(row['node_2']), title=row['edge'],# 邊的關系描述 weight=row['count']# 邊的權重(出現次數/強度) )
NetworkX 自帶了大量可直接調用的網絡算法。 可在此查看算法清單與用法: ?? Algorithms - NetworkX 3.2.1 文檔[6] 這里我使用社區發現算法給節點分組并著色。 社區指的是:與圖中其他節點相比,內部連接更緊密的一組節點。 在概念圖中,社區往往對應文本中被討論的主題簇,能幫助我們把握宏觀主題。 我對本文示例的綜述文章運行 Girvan–Newman 算法后,檢測到 17 個概念社區。 下面是其中一個社區的示例: [ 'digital technology', 'EVIN', 'medical devices', 'online training management information systems', 'wearable, trackable technology' ]
這立刻讓我們對該綜述論文中健康技術相關的宏觀主題有了直觀認識,并且還能據此提出更有針對性的問題,再用我們的 RAG 流程來回答。是不是很棒??? 接下來計算圖中每個概念(節點)的度(degree)。 節點度指的是一個節點連接的邊的總數。 在我們的場景里,度越高,說明該概念在整篇文本的主題中越居于中心。 在可視化中,我們將用節點度作為節點大小的依據(度越高,節點越大)。 圖可視化可視化是這項工作的最有趣的部分,它帶來一種藝術層面的滿足感。 我使用 PyVis 庫來創建交互式網絡圖。 PyVis 是一個用于網絡可視化的 Python 庫[7]。 PyVis 內置了 NetworkX Helper,可以把我們的 NetworkX 圖直接轉換成 PyVis 對象, 因此幾乎不需要額外編碼——太省心啦! 回顧一下,我們已經準備好了以下用于可視化的要素: ·邊的權重:用于控制邊的粗細;·節點的社區:用于控制節點的顏色;·節點的度:用于控制節點的大小。 把這些“鈴鐺與口哨”(bells and whistles)都裝上,我們的圖就呈現在眼前了。 ?? 點擊查看互動圖譜[8] 在這里,我們可以自由縮放,并隨意拖動節點和邊。 在頁面底部還有一個滑塊面板,用來調整圖的物理效果。 通過這種方式,我們不僅能更好地理解主題, 還能幫助我們提出正確的問題,從而更深入地研究內容。
GitHub 倉庫源碼與實現細節見: ?? GitHub - rahulnyk/knowledge_graph[9]
貢獻與致謝歡迎大家提出意見與建議! 本代碼演示使用的文章: Saxena S G, Godfrey T (2023年6月11日) 《India’s Opportunity to Address Human Resource Challenges in Healthcare》 Cureus 15(6): e40274. DOI: 10.7759/cureus.40274[10]https://medium.com/data-science/how-to-convert-any-text-into-a-graph-of-concepts-110844f22a1a
References[1] :https:///the-research-agent-4ef8e6f1b741/?source=post_page-----110844f22a1a---------------------------------------
[2] 什么是知識圖譜? | IBM:https://www.ibm.com/think/topics/knowledge-graph?source=post_page-----110844f22a1a---------------------------------------
[3] 印度應對醫療衛生人力資源挑戰的機遇 | Cureus:https://www./articles/158868-indias-opportunity-to-address-human-resource-challenges-in-healthcare?source=post_page-----110844f22a1a---------------------------------------#!/
[4] Ollama 官網:https://
[5] NetworkX 官方文檔:https:///?source=post_page-----110844f22a1a---------------------------------------
[6] Algorithms - NetworkX 3.2.1 文檔:https:///documentation/stable/reference/algorithms/index.html?source=post_page-----110844f22a1a---------------------------------------
[7] PyVis 是一個用于網絡可視化的 Python 庫:https://github.com/WestHealth/pyvis/tree/master#pyvis---a-python-library-for-visualizing-networks
[8] 點擊查看互動圖譜:https://rahulnyk./knowledge_graph/
[9] GitHub - rahulnyk/knowledge_graph:https://github.com/rahulnyk/knowledge_graph
[10] 10.7759/cureus.40274: https:///10.7759/cureus.40274
|