
GraphRAG:基于PolarDB+通義千問api+LangChain的知識圖譜定制實踐
(圖:廣義的RAG問答鏈路)除了傳統意義上的增強內容生成,RAG的理念還可以進一步泛化到鏈路的其他階段:
我們希望向大家分享一下:引入知識圖譜技術后,傳統RAG鏈路到Graph RAG鏈路會有什么樣的變化,如何兼容RAG中的向量數據庫(Vector Database)和圖數據庫(Graph Database)基座,以及螞蟻的Graph RAG開源技術方案和未來優化方向。
首先回顧一下傳統RAG的核心鏈路。
(圖:基于Vector的RAG鏈路)傳統RAG的核心鏈路分為三個階段:
傳統RAG希望通過知識庫的關聯知識增強大模型問答的上下文以提升生成內容質量,但也存在諸多問題。
(圖:傳統RAG的不足)論文[23]總結了傳統RAG的7個問題:
總的來看:
考慮到傳統RAG能力上的不足,Graph RAG從增強知識確定性角度做了進一步的改進,也就是最開始提到的知識內容增強的思路。相比于傳統的基于Vector格式的知識庫存儲,Graph RAG引入了知識圖譜技術,使用Graph格式存儲知識。正如論文[2]所闡述的:基于知識圖譜,可以為RAG提供高質量的上下文,以減輕模型幻覺。
Structured data, such as knowledge graphs (KGs), provide high-quality context and mitigate model hallucinations.
(圖:基于Graph的RAG鏈路)類似地,Graph RAG的核心鏈路分如下三個階段:
需要說明的是,從文本中提取三元組和關鍵詞借助了現有的文本大模型的能力,傳統的NLP技術如分詞、句法分析、實體識別等已經不再是SOTA。另外,借助于大模型微調技術,可以針對性的構建面向知識抽取、實體識別、自然語言翻譯的專有大模型。比如由螞蟻和浙大聯合研發的大模型知識抽取框架OneKE[38]在零樣本泛化性能上全面超過了現有模型。以及借助于Text2GQL、Text2Cypher技術微調的圖查詢語言專有模型,可以直接將自然語言轉換為圖查詢語言,代替基于關鍵詞中心的子圖搜索從而獲得更精確的圖譜數據。
(圖:OneKE知識抽取模型能力透視)
基于以上對傳統RAG和Graph RAG的能力介紹,我們可以發現兩種RAG架構的核心差異在于知識存儲格式的變化(從Vector到Graph),從而導致了RAG中索引、檢索和生成階段流轉數據格式的變化。而RAG的關鍵流程并未發生根本的改變,基于這個相似性前提,我完全可以抽象出一個更通用的RAG結構,以兼容向量索引和圖索引,甚至更多的索引格式(如全文索引等)。
于是一個兼容多種知識索引格式的通用RAG架構,可以按照如下方式設計。
(圖:通用RAG架構)
建模是架構落地的第一步,這里對通用RAG的核心設計做出說明:
(圖:通用RAG建模)
綜上所述,要構建一個完整的開源Graph RAG鏈路,離不開三個重要的子系統:一個可以支持RAG的AI工程框架,一個知識圖譜系統和一個圖存儲系統。開源的AI工程框架有諸多選型:LangChain、LlamaIndex、RAGFlow、DB-GPT等。知識圖譜系統有:Jena、RDF4J、Oxigraph、OpenSPG等。圖存儲系統有Neo4j、JanusGraph、NebulaGraph、TuGraph等。而作為螞蟻首個對外開源的Graph RAG框架,我們采用螞蟻全自主的開源產品:DB-GPT[50]?+ OpenSPG[42]?+ TuGraph[46]。
(圖:螞蟻Graph RAG開源方案)
DB-GPT是一個開源的AI原生數據應用開發框架,目的是構建大模型領域的基礎設施,通過開發多模型管理(SMMF)、Text2SQL效果優化、RAG框架以及優化、Multi-Agents框架協作、AWEL(智能體工作流編排)等多種技術能力,讓圍繞數據庫構建大模型應用更簡單,更方便。
(圖:DB-GPT技術架構)
OpenSPG是螞蟻集團結合多年金融領域多元場景知識圖譜構建與應用業務經驗的總結,并與OpenKG聯合推出的基于SPG(Semantic-enhanced Programmable Graph)框架研發的知識圖譜引擎。
(圖:OpenSPG技術架構)
TuGraph是螞蟻集團與清華大學聯合研發的大規模圖處理系統,構建了包含圖數據庫、圖計算引擎、圖機器學習、圖研發平臺的完善圖技術體系。支持海量多源的關聯數據的實時處理,顯著提升數據分析效率,支撐了螞蟻支付、安全、社交、公益、數據治理等300多個場景應用,多次打破圖數據庫性能基準測試LDBC-SNB世界紀錄,并躋身IDC中國圖數據庫市場領導者象限。
(圖:TuGraph技術架構)
在DB-GPT的v0.5.6[47]版本中,我們提供了完整的Graph RAG框架實現(PR 1506[48])。接下來我們結合這個PR,闡述Graph RAG的關鍵實現細節。
索引加工的統一抽象是TransformerBase接口,目前提供了嵌入、抽取、翻譯三類轉換器。而圖索引的構建,則通過三元組提取器TripletExtractor來實現。
(圖:TransformerBase接口的繼承樹)ExtractorBase接口負責信息提取的職責,當下已有的三元組提取器和關鍵詞提取器都依賴了大模型能力,所以抽象類LLExtractor負責與LLM交互的公共邏輯,具體的實現類只需要提供提示詞模板和結果解析即可。三元組提取器TripletExtractor的提示詞模板(受LlamaIndex啟發),核心理念是通過few-shot樣本引導大模型生成三元組結構。
TRIPLET_EXTRACT_PT = (
"Some text is provided below. Given the text, "
"extract up to knowledge triplets as more as possible "
"in the form of (subject, predicate, object).\n"
"Avoid stopwords.\n"
"---------------------\n"
"Example:\n"
"Text: Alice is Bob's mother.\n"
"Triplets:\n(Alice, is mother of, Bob)\n"
...TL;DR...
"Text: Philz is a coffee shop founded in Berkeley in 1982.\n"
"Triplets:(Philz, is, coffee shop)\n(Philz, founded in, Berkeley)\n(Philz, founded in, 1982)\n"
"---------------------\n"
"Text: {text}\n"
"Triplets:\n"
)
大模型讓三元組抽取變成了一件非常簡單的事情,但是要提高三元組的抽取質量也不是一件容易的事情。最簡單的是通過提示詞工程不斷優化提示詞模板,讓通用大模型給出更理想的答案。另外使用專有的知識抽取大模型(如OneKE)可以取得更好的效果,這部分工作還在進行中,我們期望看到OnekeExtractor的社區貢獻早日發布。
索引存儲的統一抽象是IndexStoreBase接口,目前提供了向量、圖、全文三類索引實現。知識圖譜接口KnowledgeGraphBase是Graph RAG的存儲底座,目前DB-GPT內置的BuiltinKnowledgeGraph實現就是基于文本大模型能力構建的,OpenSPG的接入工作已經在逐步推進。
(圖:IndexStoreBase接口的繼承樹)知識圖譜提供了和向量數據庫同樣的接口,讓知識的存取過程透明化。文檔內容經過三元組解析器_triplet_extractor解析后,直接寫入圖存儲_graph_store。
sync def aload_document(self, chunks: List[Chunk]) -> List[str]:
"""Extract and persist triplets to graph store.
Args:
chunks: List[Chunk]: document chunks.
Return:
List[str]: chunk ids.
"""
for chunk in chunks:
triplets = await self._triplet_extractor.extract(chunk.content)
for triplet in triplets:
self._graph_store.insert_triplet(*triplet)
logger.info(f"load {len(triplets)} triplets from chunk {chunk.chunk_id}")
return [chunk.chunk_id for chunk in chunks]
圖存儲接口GraphStoreBase提供統一的圖存儲抽象,目前內置了MemoryGraphStore和TuGraphStore的實現,分別用于本地測試和生產部署,并預留了Neo4jStore的擴展點。
(圖:GraphStoreBase接口的繼承樹)具體的圖存儲提供了三元組寫入的實現,一般會調用圖數據庫的查詢語言來完成。例如TuGraphStore會根據三元組生成具體的Cypher語句并執行。
def insert_triplet(self, subj: str, rel: str, obj: str) -> None:
"""Add triplet."""
...TL;DR...
subj_query = f"MERGE (n1:{self._node_label} {{id:'{subj}'}})"
obj_query = f"MERGE (n1:{self._node_label} {{id:'{obj}'}})"
rel_query = (
f"MERGE (n1:{self._node_label} {{id:'{subj}'}})"
f"-[r:{self._edge_label} {{id:'{rel}'}}]->"
f"(n2:{self._node_label} {{id:'{obj}'}})"
)
self.conn.run(query=subj_query)
self.conn.run(query=obj_query)
self.conn.run(query=rel_query)
接口ExtractorBase的另一個實現則是關鍵詞抽取器KeywordExtractor,負責提取用戶問題中涉及的實體關鍵詞,它也是借助大模型的能力實現的,同樣繼承于LLExtractor,提示詞模板如下。
KEYWORD_EXTRACT_PT = (
"A question is provided below. Given the question, extract up to "
"keywords from the text. Focus on extracting the keywords that we can use "
"to best lookup answers to the question.\n"
"Generate as more as possible synonyms or alias of the keywords "
"considering possible cases of capitalization, pluralization, "
"common expressions, etc.\n"
"Avoid stopwords.\n"
"Provide the keywords and synonyms in comma-separated format."
"Formatted keywords and synonyms text should be separated by a semicolon.\n"
"---------------------\n"
"Example:\n"
"Text: Alice is Bob's mother.\n"
"Keywords:\nAlice,mother,Bob;mummy\n"
"Text: Philz is a coffee shop founded in Berkeley in 1982.\n"
"Keywords:\nPhilz,coffee shop,Berkeley,1982;coffee bar,coffee house\n"
"---------------------\n"
"Text: {text}\n"
"Keywords:\n"
)
關鍵詞的抽取涉及到文本中實體識別技術,在構造提示詞時需要考慮單詞的大小寫、別稱、同義詞等情況,這部分還有很大的優化空間。另外,借助于模型微調直接翻譯自然語言到圖查詢語句也是值得探索的方向。圖存儲接口GraphStoreBase提供了基于關鍵詞的探索接口?explore,會根據抽取的關鍵詞召回局部子圖。
@abstractmethod
def explore(
self,
subs: List[str],
direct: Direction = Direction.BOTH,
depth: Optional[int] = None,
fan: Optional[int] = None,
limit: Optional[int] = None,
) -> Graph:
"""Explore on graph."""
這里對接口含義做補充說明:
返回值:Graph接口類型,表示搜索結果子圖,提供了便捷的點邊更新API。TuGraph的explore接口實現核心邏輯是將上述參數轉化為Cypher查詢語句,形如:
query = (
f"MATCH p=(n:{self._node_label})"
f"-[r:{self._edge_label}*1..{depth}]-(m:{self._node_label}) "
f"WHERE n.id IN {subs} RETURN p LIMIT {limit}"
)
和其他向量數據庫類似,BuiltinKnowledgeGraph同樣實現了IndexStoreBase的相似性查詢接口。
async def asimilar_search_with_scores(
self,
text,
topk,
score_threshold: float,
filters: Optional[MetadataFilters] = None,
) -> List[Chunk]:
"""Search neighbours on knowledge graph."""
if not filters:
logger.info("Filters on knowledge graph not supported yet")
# extract keywords and explore graph store
keywords = await self._keyword_extractor.extract(text)
subgraph = self._graph_store.explore(keywords, limit=topk)
logger.info(f"Search subgraph from {len(keywords)} keywords")
content = (
"The following vertices and edges data after [Subgraph Data] "
"are retrieved from the knowledge graph based on the keywords:\n"
f"Keywords:\n{','.join(keywords)}\n"
"---------------------\n"
"You can refer to the sample vertices and edges to understand "
"the real knowledge graph data provided by [Subgraph Data].\n"
"Sample vertices:\n"
"(alice)\n"
"Sample edges:\n"
"(alice)-[reward]->(alice)\n"
"---------------------\n"
f"Subgraph Data:\n{subgraph.format()}\n"
)
return [Chunk(content=content, metadata=subgraph.schema())]
關鍵詞通過關鍵詞抽取器_keyword_extractor完成,抽取到的關鍵詞傳遞給圖存儲對象_graph_store進行子圖探索,探索結果子圖直接格式化到提示詞上下文字符串content內。
細心的讀者可以發現,子圖探索的結果直接封裝為Graph接口類型,我們甚至還提供了一個MemoryGraph工具類實現。這樣實現圖探索接口時,就無需將查詢結果轉化為Path/Table等內存不友好的格式了,同時也降低了提示詞中編碼子圖數據的token開銷。當然這是建立大模型對Graph數據結構原生的理解基礎上,我們相信這是當下主流大模型的基本能力。
(圖:Graph接口的核心API)
我們使用《變形金剛》的故事材料tranformers_story.md[49]作為測試文本,驗證DB-GPT上Graph RAG的效果。具體操作手冊見DB-GPT的文檔《Graph RAG User Manual》[31]。
啟動DB-GPT后,新增Knowledge Space,選擇Knowledge Graph存儲類型。上傳tranformers_story.md后切片自動構建圖索引。
(圖:創建知識圖譜)構建好的知識圖譜支持快速預覽。
(圖:知識圖譜預覽)基于知識圖譜的對話測試。
(圖:知識圖譜對話)
其實大家在對DB-GPT上Graph RAG實現進行初步的測試后,會發現當下仍有不少體驗問題。不避諱的講,這里除了功能完善度的原因之外,還有Graph RAG自身設計上的不足,這也為后續的進一步優化方向提供了思路。文章[26]總結了Graph RAG的不足:
GraphRAG, like RAG, has clear limitations, which include how to form graphs, generate queries for querying these graphs, and ultimately decide how much information to retrieve based on these queries. The main challenges are ‘query generation’, ‘reasoning boundary’, and ‘information extraction’.
總的來看分為三大類:
像前邊提到的,知識抽取/關鍵詞/查詢語言的微調模型主要專注于信息抽取和查詢生成。另外,論文[24]實現的基于圖的推理增強框架(RoG)則是在推理邊界方向嘗試的創新(思路有點類似RAT):
(圖:RoG:基于圖的推理增強)當然上述三個階段也可以被簡化合并為兩個階段:內容索引階段和檢索生成階段。我們就這兩個大的階段分別討論Graph RAG后續可能的優化方向和思路。
6.1 內容索引階段
Graph RAG的內容索引階段主要目標便是構建高質量的知識圖譜,值得繼續探索的有以下方向:
(圖:混合檢索的Graph RAG)
6.2 檢索生成階段
Graph RAG的檢索生成階段主要目標便是從知識圖譜上召回高質量上下文,值得繼續探索的有以下方向:
通過以上介紹,相信大家對RAG到Graph RAG的技術演進有了更進一步的了解,并且基于RAG的索引、檢索、生成三個基本階段抽象出了通用的RAG框架,兼容了Vector、Graph、FullText等多種索引形式,最終在開源技術中完整落地。最后通過探討Graph RAG未來的優化與演進方向,總結了內容索引和檢索生成階段的不同改進思路,以及RAG向Agent架構的演化趨勢。Graph RAG是個相對新穎AI工程領域,需要探索和改進的工作還有很多要做,我們誠邀DB-GPT/OpenSPG/TuGraph的廣大開發者們一起參與共建。
前不久Jerry Liu(LlamaIndex CEO)在技術報告《Beyond RAG: Building Advanced Context-Augmented LLM Applications》中也拋出了“RAG的未來是Agent”相似觀點。所以,無論是“RAG for Agents”還是“Agents for RAG”,亦或是“從RAG到Graph RAG再到Agents”,目光可及的是智能體將是未來AI應用的主旋律。
參考資料:
文章轉自微信公眾號@阿里云開發者