級RAG實戰(zhàn))
最近在調(diào)研企業(yè)級知識庫的構(gòu)建方案時發(fā)現(xiàn)傳統(tǒng)的向量檢索RAG在面對復(fù)雜、結(jié)構(gòu)化知識時常常顯得力不從心。檢索結(jié)果要么過于零散缺乏上下文關(guān)聯(lián)要么無法理解概念間的層級與邏輯關(guān)系導(dǎo)致回答缺乏深度和準(zhǔn)確性。如果你也遇到過類似問題那么騰訊近期開源的一個名為YouToGraphRAG的框架或許能帶來新的思路。它并非簡單的向量檢索增強(qiáng)而是創(chuàng)新性地將知識圖譜、多層聚類樹狀結(jié)構(gòu)與智能體Agent檢索深度融合旨在構(gòu)建一個更接近人類認(rèn)知方式的“理解-推理”型知識庫系統(tǒng)。本文將深入拆解 YouToGraphRAG 的核心架構(gòu)與實戰(zhàn)應(yīng)用。無論你是正在尋找下一代企業(yè)知識庫解決方案的架構(gòu)師還是對RAG進(jìn)階技術(shù)感興趣的開發(fā)者都能通過本文掌握其從環(huán)境搭建、知識處理到智能檢索的全流程。我們將從零開始手把手帶你體驗如何將非結(jié)構(gòu)化文檔轉(zhuǎn)化為一個具備語義理解和邏輯推理能力的智能知識庫。1. 背景與核心概念為什么需要“圖譜化”的RAG在深入 YouToGraphRAG 之前我們有必要厘清幾個核心概念以及當(dāng)前RAG面臨的挑戰(zhàn)。RAG檢索增強(qiáng)生成已成為連接大模型與私有知識的主流范式。其標(biāo)準(zhǔn)流程通常為文檔切片 - 向量化 - 存入向量數(shù)據(jù)庫 - 用戶提問時進(jìn)行向量相似度檢索 - 將檢索到的文本片段注入大模型上下文以生成答案。這個流程簡單有效但也存在明顯短板“碎片化”檢索文檔被切分成獨立的片段chunk檢索時可能只返回某個孤立的片段丟失了原文中跨片段的重要邏輯關(guān)系和上下文。缺乏語義關(guān)聯(lián)向量相似度主要衡量文本表面的語義相似性難以捕捉“蘋果公司”和“iPhone”之間的“生產(chǎn)”關(guān)系或者“Java”和“面向?qū)ο蟆敝g的“是一種”關(guān)系。無法進(jìn)行多跳推理對于“張三的部門的經(jīng)理是誰”這類問題標(biāo)準(zhǔn)RAG需要恰好有一個片段包含了“張三是A部門員工”和“李四是A部門經(jīng)理”的全部信息否則無法回答。這正是知識圖譜Knowledge Graph可以大顯身手的地方。知識圖譜以實體關(guān)系實體的三元組形式組織知識顯式地定義了概念間的關(guān)聯(lián)。它擅長表達(dá)復(fù)雜的結(jié)構(gòu)關(guān)系并支持多跳推理。YouToGraphRAG 的核心思想可以概括為“從文本到圖譜再從圖譜到智能檢索”。它不再將文檔視為一維的文本流而是試圖從中抽取出結(jié)構(gòu)化的知識網(wǎng)絡(luò)并利用這個網(wǎng)絡(luò)來增強(qiáng)檢索的精度和深度。其引入的“多層知識圖譜聚類樹狀結(jié)構(gòu)”和“智能體檢索”是兩個關(guān)鍵創(chuàng)新點多層知識圖譜聚類樹狀結(jié)構(gòu)這并非一個單一的知識圖譜。它可能包含多個層次例如基礎(chǔ)實體層從文檔中提取出的原始實體和關(guān)系。主題聚類層通過聚類算法如社區(qū)發(fā)現(xiàn)、層次聚類將關(guān)聯(lián)緊密的實體聚合成主題簇形成“子樹”。這有助于從宏觀上把握知識領(lǐng)域。抽象模式層對高頻出現(xiàn)的知識模式進(jìn)行抽象形成某種“元知識”或“規(guī)則”。 這種樹狀結(jié)構(gòu)使得知識庫既能進(jìn)行細(xì)粒度的實體查詢也能進(jìn)行粗粒度的主題導(dǎo)航和探索。智能體檢索檢索不再是一個簡單的相似度匹配函數(shù)。它被設(shè)計成一個或多個具有特定能力的“智能體Agent”。例如向量檢索智能體負(fù)責(zé)傳統(tǒng)的語義相似性查找。圖譜遍歷智能體負(fù)責(zé)在知識圖譜上執(zhí)行路徑查詢、多跳推理。決策智能體根據(jù)用戶問題的特點如是否包含明確實體、是否需要推理決定調(diào)用哪個或哪幾個檢索智能體并對它們的結(jié)果進(jìn)行融合與重排序。簡單來說YouToGraphRAG 的目標(biāo)是構(gòu)建一個既能“理解”文本語義又能“理解”知識結(jié)構(gòu)并能“智能”選擇最佳檢索策略的系統(tǒng)。2. 環(huán)境準(zhǔn)備與項目搭建由于 YouToGraphRAG 是一個較新的開源框架其具體實現(xiàn)可能快速迭代。以下環(huán)境準(zhǔn)備基于常見的RAG與知識圖譜技術(shù)棧旨在提供一個可復(fù)現(xiàn)的、概念驗證型的實戰(zhàn)環(huán)境。我們將使用Python作為主要語言并結(jié)合Neo4j圖數(shù)據(jù)庫、Milvus向量數(shù)據(jù)庫以及LangChain生態(tài)來模擬其核心流程。2.1 基礎(chǔ)環(huán)境與依賴確保你的開發(fā)環(huán)境滿足以下要求操作系統(tǒng)Linux / macOS / Windows (WSL2推薦)Python版本 3.8 - 3.11包管理工具pip 或 condaDocker Docker Compose用于快速啟動數(shù)據(jù)庫服務(wù)強(qiáng)烈推薦首先創(chuàng)建一個新的項目目錄并初始化虛擬環(huán)境mkdir youtograph-rag-demo cd youtograph-rag-demo python -m venv venv # Linux/macOS source venv/bin/activate # Windows venv\Scripts\activate安裝核心的 Python 依賴庫。這里我們安裝用于知識圖譜構(gòu)建、向量化、智能體編排的常用庫pip install langchain langchain-community langchain-experimental pip install openai # 或其它LLM API如 zhipuai, qianfan pip install sentence-transformers # 用于本地文本向量化 pip install networkx py2neo # 用于知識圖譜操作與Neo4j連接 pip install pymilvus # Milvus客戶端 pip install scikit-learn # 用于聚類算法 pip install beautifulsoup4 markdown # 用于文檔解析示例2.2 啟動后端服務(wù)Neo4j 與 Milvus我們將使用 Docker Compose 一鍵啟動所需的圖數(shù)據(jù)庫和向量數(shù)據(jù)庫服務(wù)。在項目根目錄創(chuàng)建docker-compose.yml文件version: 3.8 services: neo4j: image: neo4j:5-community container_name: neo4j-kg ports: - 7474:7474 # HTTP瀏覽器界面 - 7687:7687 # Bolt協(xié)議端口 environment: - NEO4J_AUTHneo4j/youtograph123 # 用戶名/密碼 - NEO4J_PLUGINS[apoc, graph-data-science] # 安裝常用插件 volumes: - neo4j_data:/data - neo4j_logs:/logs - neo4j_import:/var/lib/neo4j/import restart: unless-stopped milvus: image: milvusdb/milvus:v2.4.0-rc.1 container_name: milvus-vector ports: - 19530:19530 - 9091:9091 environment: - ETCD_ENDPOINTSetcd:2379 volumes: - milvus_data:/var/lib/milvus depends_on: - etcd - minio restart: unless-stopped etcd: image: quay.io/coreos/etcd:v3.5.5 container_name: milvus-etcd environment: - ETCD_AUTO_COMPACTION_MODErevision - ETCD_QUOTA_BACKEND_BYTES4294967296 volumes: - etcd_data:/etcd command: etcd -advertise-client-urlshttp://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd restart: unless-stopped minio: image: minio/minio:RELEASE.2023-03-20T20-16-18Z container_name: milvus-minio environment: - MINIO_ACCESS_KEYminioadmin - MINIO_SECRET_KEYminioadmin volumes: - minio_data:/data command: minio server /data --console-address :9090 ports: - 9090:9090 restart: unless-stopped volumes: neo4j_data: neo4j_logs: neo4j_import: milvus_data: etcd_data: minio_data:運(yùn)行以下命令啟動服務(wù)docker-compose up -d等待片刻后你可以通過以下方式驗證服務(wù)Neo4j: 瀏覽器打開http://localhost:7474使用neo4j/youtograph123登錄。Milvus: 可以通過docker logs milvus-vector查看啟動日志或后續(xù)用Python客戶端連接測試。3. 核心流程拆解從文檔到智能檢索YouToGraphRAG 的完整流程可以分解為以下幾個核心階段我們將逐一實現(xiàn)其簡化版本。3.1 階段一文檔解析與知識抽取這是構(gòu)建知識圖譜的起點。我們需要從非結(jié)構(gòu)化文本如PDF、Word、Markdown中提取出實體和關(guān)系。我們以一個簡單的技術(shù)文檔片段為例演示如何使用LangChain的文本分割器和OpenAI的函數(shù)調(diào)用功能進(jìn)行信息抽取。首先準(zhǔn)備一個示例文檔sample_doc.txt騰訊公司于1998年11月在深圳成立由馬化騰、張志東、許晨曄、陳一丹、曾李青五位創(chuàng)始人共同創(chuàng)立。該公司是中國最大的互聯(lián)網(wǎng)綜合服務(wù)提供商之一。其主要產(chǎn)品包括微信和QQ兩大社交平臺。微信團(tuán)隊由張小龍領(lǐng)導(dǎo)是一款集即時通訊、社交、支付于一體的應(yīng)用。騰訊云是騰訊公司推出的云計算服務(wù)平臺為企業(yè)提供計算、存儲、網(wǎng)絡(luò)等基礎(chǔ)設(shè)施服務(wù)。然后編寫知識抽取腳本01_knowledge_extraction.pyimport os from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate import json from py2neo import Graph, Node, Relationship # 1. 配置LLM和Neo4j連接 os.environ[OPENAI_API_KEY] your-openai-api-key # 請?zhí)鎿Q為你的密鑰 llm ChatOpenAI(modelgpt-4-turbo-preview) graph Graph(bolt://localhost:7687, auth(neo4j, youtograph123)) # 2. 讀取并分割文檔 with open(sample_doc.txt, r, encodingutf-8) as f: text f.read() text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) chunks text_splitter.split_text(text) print(f文檔被分割成 {len(chunks)} 個片段。) # 3. 定義知識抽取的Prompt和函數(shù)調(diào)用Schema extraction_prompt ChatPromptTemplate.from_messages([ (system, 你是一個精準(zhǔn)的知識抽取專家。從給定的文本中抽取出明確的實體、實體類型以及實體之間的關(guān)系。只輸出JSON格式的結(jié)果。), (human, 文本內(nèi)容{text}) ]) extraction_function { name: extract_knowledge_triplets, description: 從文本中抽取實體關(guān)系實體形式的三元組知識。, parameters: { type: object, properties: { triplets: { type: array, items: { type: object, properties: { head: {type: string, description: 頭實體}, relation: {type: string, description: 關(guān)系}, tail: {type: string, description: 尾實體}, head_type: {type: string, description: 頭實體類型如Person, Company, Product}, tail_type: {type: string, description: 尾實體類型} }, required: [head, relation, tail, head_type, tail_type] } } }, required: [triplets] } } # 4. 對每個文本片段進(jìn)行知識抽取并存入Neo4j for i, chunk in enumerate(chunks): print(f\n--- 處理片段 {i1} ---) # 綁定函數(shù)調(diào)用 llm_with_tools llm.bind(functions[extraction_function], function_call{name: extract_knowledge_triplets}) # 構(gòu)造消息 messages extraction_prompt.format_messages(textchunk) # 調(diào)用LLM response llm_with_tools.invoke(messages) # 解析返回的JSON if response.additional_kwargs and function_call in response.additional_kwargs: args json.loads(response.additional_kwargs[function_call][arguments]) triplets args.get(triplets, []) for trip in triplets: print(f抽取到三元組: ({trip[head]}) -[{trip[relation]}]- ({trip[tail]})) # 創(chuàng)建或獲取頭實體節(jié)點 head_node Node(trip[head_type], nametrip[head]) graph.merge(head_node, trip[head_type], name) # 創(chuàng)建或獲取尾實體節(jié)點 tail_node Node(trip[tail_type], nametrip[tail]) graph.merge(tail_node, trip[tail_type], name) # 創(chuàng)建關(guān)系 rel Relationship(head_node, trip[relation], tail_node) graph.merge(rel) print(\n知識抽取完成數(shù)據(jù)已存入Neo4j。)運(yùn)行此腳本后登錄Neo4j瀏覽器 (http://localhost:7474)執(zhí)行MATCH (n) RETURN n可以看到初步構(gòu)建的知識圖譜。3.2 階段二構(gòu)建多層聚類樹狀結(jié)構(gòu)在基礎(chǔ)圖譜之上我們需要構(gòu)建更上層的抽象。這里我們演示如何對圖譜中的實體進(jìn)行社區(qū)發(fā)現(xiàn)聚類以形成主題簇。編寫腳本02_clustering_and_hierarchy.pyfrom py2neo import Graph import networkx as nx from networkx.algorithms import community from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.cluster import KMeans import numpy as np graph Graph(bolt://localhost:7687, auth(neo4j, youtograph123)) # 1. 從Neo4j中提取所有實體及其關(guān)聯(lián)的文本描述這里用相鄰關(guān)系名模擬 query MATCH (e) OPTIONAL MATCH (e)-[r]-(o) WITH e, collect(type(r)) as rels RETURN id(e) as node_id, e.name as name, e.__type__ as label, rels data graph.run(query).data() # 為每個實體生成一個特征文本名稱關(guān)系類型 entity_features [] entity_info [] for record in data: feature_text record[name] .join(record[rels]) entity_features.append(feature_text) entity_info.append({ node_id: record[node_id], name: record[name], label: record[label] }) # 2. 使用TF-IDF將文本特征向量化 vectorizer TfidfVectorizer(max_features50) X vectorizer.fit_transform(entity_features) # 3. 使用K-Means進(jìn)行聚類 (假設(shè)我們聚成3類) num_clusters 3 kmeans KMeans(n_clustersnum_clusters, random_state42) clusters kmeans.fit_predict(X) # 4. 將聚類結(jié)果作為“主題”節(jié)點插入Neo4j并與實體連接 for i, info in enumerate(entity_info): cluster_id int(clusters[i]) topic_name fTopic_Cluster_{cluster_id} # 創(chuàng)建或獲取主題節(jié)點 topic_node Node(Topic, nametopic_name, cluster_idcluster_id) graph.merge(topic_node, Topic, name) # 找到對應(yīng)的實體節(jié)點 entity_node graph.nodes.match(info[label], nameinfo[name]).first() if entity_node: # 創(chuàng)建 BELONGS_TO 關(guān)系 rel_query MATCH (e) WHERE id(e) $entity_id MATCH (t:Topic {name: $topic_name}) MERGE (e)-[:BELONGS_TO]-(t) graph.run(rel_query, entity_identity_node.identity, topic_nametopic_name) print(聚類完成已在Neo4j中創(chuàng)建 Topic 節(jié)點和 BELONGS_TO 關(guān)系。) # 5. 可選進(jìn)一步構(gòu)建層次對主題進(jìn)行更高層次的聚類 # 這里可以計算主題之間的相似度例如基于其下屬實體的向量中心再次聚類形成樹狀結(jié)構(gòu)。 print(\n你可以通過以下Cypher查詢查看層級結(jié)構(gòu)) print(MATCH (e)-[:BELONGS_TO]-(t:Topic) RETURN e.name, t.name LIMIT 20;)這個腳本實現(xiàn)了從圖譜中提取實體及其上下文特征。使用K-Means對實體進(jìn)行聚類每個簇代表一個“主題”。在 Neo4j 中創(chuàng)建Topic節(jié)點并通過BELONGS_TO關(guān)系將實體與主題關(guān)聯(lián)。這構(gòu)成了一個簡單的兩層結(jié)構(gòu)實體層 - 主題簇層。你可以遞歸地應(yīng)用此過程在主題之上構(gòu)建更抽象的主題從而形成樹狀結(jié)構(gòu)。3.3 階段三向量索引與智能體檢索策略現(xiàn)在我們擁有一個結(jié)構(gòu)化的知識圖譜。接下來需要實現(xiàn)混合檢索既支持傳統(tǒng)的向量語義檢索也支持圖譜的關(guān)系檢索。我們將引入“智能體”的概念來協(xié)調(diào)這兩種檢索方式。首先將文檔片段向量化并存入 Milvus。創(chuàng)建腳本03_vector_indexing.pyfrom pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility from sentence_transformers import SentenceTransformer import hashlib # 1. 連接 Milvus connections.connect(hostlocalhost, port19530) # 2. 定義集合Collection模式 collection_name youtograph_docs if utility.has_collection(collection_name): utility.drop_collection(collection_name) fields [ FieldSchema(nameid, dtypeDataType.VARCHAR, is_primaryTrue, max_length64), FieldSchema(nametext, dtypeDataType.VARCHAR, max_length4096), FieldSchema(nameembedding, dtypeDataType.FLOAT_VECTOR, dim384) # 使用 all-MiniLM-L6-v2 模型 ] schema CollectionSchema(fields, descriptionDocument chunks for vector search) collection Collection(namecollection_name, schemaschema) # 3. 創(chuàng)建索引 index_params { index_type: IVF_FLAT, metric_type: L2, params: {nlist: 128} } collection.create_index(field_nameembedding, index_paramsindex_params) print(f集合 {collection_name} 創(chuàng)建成功索引已建立。) # 4. 加載嵌入模型 embedder SentenceTransformer(all-MiniLM-L6-v2) # 5. 準(zhǔn)備數(shù)據(jù)并插入 (這里復(fù)用之前分割的chunks) # 假設(shè) chunks 變量仍然可用或者重新讀取 with open(sample_doc.txt, r, encodingutf-8) as f: text f.read() from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) chunks text_splitter.split_text(text) data [] for i, chunk in enumerate(chunks): # 生成唯一ID chunk_id hashlib.md5(chunk.encode()).hexdigest() # 生成向量 vector embedder.encode(chunk).tolist() data.append([chunk_id, chunk, vector]) # 6. 插入數(shù)據(jù) insert_result collection.insert(data) collection.load() # 將集合加載到內(nèi)存 print(f成功插入 {len(data)} 條文本片段到 Milvus。)接下來實現(xiàn)一個簡單的智能體檢索協(xié)調(diào)器04_agentic_retriever.pyfrom pymilvus import Collection from sentence_transformers import SentenceTransformer from py2neo import Graph from langchain_openai import ChatOpenAI import json class HybridRetrievalAgent: def __init__(self): # 初始化組件 self.vector_collection Collection(youtograph_docs) self.vector_collection.load() self.embedder SentenceTransformer(all-MiniLM-L6-v2) self.graph Graph(bolt://localhost:7687, auth(neo4j, youtograph123)) self.llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) def _vector_retrieve(self, query: str, top_k: int 3): 向量檢索智能體 query_vec self.embedder.encode(query).tolist() search_params {metric_type: L2, params: {nprobe: 10}} results self.vector_collection.search( data[query_vec], anns_fieldembedding, paramsearch_params, limittop_k, output_fields[text] ) return [hit.entity.get(text) for hit in results[0]] def _graph_retrieve(self, query: str): 圖譜檢索智能體嘗試識別實體并進(jìn)行圖譜查詢 # 簡單實體識別實際應(yīng)用可用NER模型 prompt f 從以下問題中提取出可能的人名、公司名、產(chǎn)品名等實體。只輸出JSON數(shù)組。 問題{query} 示例輸出{{entities: [騰訊, 微信]}} resp self.llm.invoke(prompt) try: entities json.loads(resp.content).get(entities, []) except: entities [] graph_results [] for ent in entities: # 查詢與該實體直接相關(guān)的知識 cypher_query MATCH (e {name: $entity_name})-[r]-(o) RETURN e.name as head, type(r) as relation, o.name as tail UNION MATCH (e {name: $entity_name})-[r]-(o) RETURN o.name as head, type(r) as relation, e.name as tail LIMIT 5 data self.graph.run(cypher_query, entity_nameent).data() for record in data: graph_results.append(f{record[head]} {record[relation]} {record[tail]}) return list(set(graph_results)) # 去重 def _decide_strategy(self, query: str) - dict: 決策智能體分析問題類型決定檢索策略權(quán)重 analysis_prompt f 分析以下用戶問題判斷其更適合哪種檢索方式向量語義搜索 / 知識圖譜關(guān)系查詢。 問題{query} 請按以下JSON格式輸出分析結(jié)果 {{ need_factual_detail: 0-1的分?jǐn)?shù), // 需要事實細(xì)節(jié)的程度 need_relationship: 0-1的分?jǐn)?shù), // 需要關(guān)系推理的程度 primary_method: vector 或 graph // 主要檢索方法 }} resp self.llm.invoke(analysis_prompt) try: strategy json.loads(resp.content) return strategy except: return {primary_method: hybrid, need_factual_detail: 0.5, need_relationship: 0.5} def retrieve(self, query: str) - str: 主檢索入口協(xié)調(diào)多個智能體 print(f[決策智能體] 分析問題: {query}) strategy self._decide_strategy(query) print(f[決策智能體] 策略決策: {strategy}) vector_results [] graph_results [] # 根據(jù)決策調(diào)用相應(yīng)的檢索智能體 if strategy[primary_method] in [vector, hybrid]: print([向量檢索智能體] 開始工作...) vector_results self._vector_retrieve(query, top_k3) if strategy[primary_method] in [graph, hybrid]: print([圖譜檢索智能體] 開始工作...) graph_results self._graph_retrieve(query) # 結(jié)果融合與重排序這里簡單拼接實際可加權(quán)打分 combined_context if vector_results: combined_context 【相關(guān)文檔片段】\n \n---\n.join(vector_results) \n\n if graph_results: combined_context 【知識圖譜關(guān)系】\n \n.join(graph_results) \n\n return combined_context.strip() # 使用示例 if __name__ __main__: agent HybridRetrievalAgent() test_queries [ 騰訊的主要產(chǎn)品有哪些, # 偏向向量檢索 微信的負(fù)責(zé)人是誰, # 需要圖譜關(guān)系 介紹一下騰訊云。, # 偏向向量檢索 ] for q in test_queries: print(f\n{*50}) print(f用戶問題: {q}) context agent.retrieve(q) print(f檢索到的上下文:\n{context}) print(*50)這個HybridRetrievalAgent類模擬了 YouToGraphRAG 中智能體檢索的核心思想決策智能體 (_decide_strategy)分析用戶問題判斷其更適合向量檢索事實細(xì)節(jié)還是圖譜檢索關(guān)系推理。向量檢索智能體 (_vector_retrieve)執(zhí)行傳統(tǒng)的語義相似度搜索。圖譜檢索智能體 (_graph_retrieve)嘗試從問題中提取實體并在知識圖譜中查詢與之相關(guān)的關(guān)系路徑。協(xié)調(diào)檢索 (retrieve)根據(jù)決策結(jié)果調(diào)用相應(yīng)的智能體并將它們的結(jié)果融合成最終的上下文。4. 完整實戰(zhàn)構(gòu)建問答系統(tǒng)現(xiàn)在我們將上述所有組件串聯(lián)起來構(gòu)建一個完整的、基于 YouToGraphRAG 理念的問答系統(tǒng)。創(chuàng)建05_qa_system.pyfrom langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from .agentic_retriever import HybridRetrievalAgent # 假設(shè)將之前的類放在此模塊中 import sys import os sys.path.append(os.path.dirname(os.path.abspath(__file__))) class YouToGraphQASystem: def __init__(self): self.retriever_agent HybridRetrievalAgent() self.llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0.2) self.parser StrOutputParser() # 定義生成答案的Prompt self.qa_prompt ChatPromptTemplate.from_messages([ (system, 你是一個專業(yè)的助手請嚴(yán)格根據(jù)提供的上下文信息來回答問題。 如果上下文中的信息足以回答問題請基于這些信息組織語言生成準(zhǔn)確、流暢的答案。 如果上下文信息不足或與問題無關(guān)請直接回答“根據(jù)現(xiàn)有知識庫我無法回答這個問題?!?上下文信息 {context} ), (human, 問題{question}) ]) self.chain self.qa_prompt | self.llm | self.parser def answer(self, question: str) - str: 核心問答流程 print(f\n[系統(tǒng)] 接收到問題: {question}) # 1. 智能體檢索上下文 print([系統(tǒng)] 啟動智能體檢索流程...) context self.retriever_agent.retrieve(question) if not context: return 抱歉未能檢索到相關(guān)信息。 print(f[系統(tǒng)] 檢索到 {len(context.splitlines())} 行上下文。) # 2. 將上下文和問題送入LLM生成答案 print([系統(tǒng)] 正在生成答案...) answer self.chain.invoke({context: context, question: question}) return answer # 運(yùn)行示例 if __name__ __main__: qa_system YouToGraphQASystem() questions [ 騰訊公司是哪一年成立的, 誰創(chuàng)立了騰訊, 微信和QQ是什么關(guān)系, 張小龍在騰訊負(fù)責(zé)什么, 騰訊云提供哪些服務(wù), ] for q in questions: print(\n *60) print(fQ: {q}) a qa_system.answer(q) print(fA: {a}) print(*60)運(yùn)行這個腳本你將看到系統(tǒng)如何協(xié)同工作對于“騰訊公司是哪一年成立的”決策智能體可能判斷為需要事實細(xì)節(jié)主要調(diào)用向量檢索智能體從文檔片段中找到成立時間。對于“張小龍在騰訊負(fù)責(zé)什么”決策智能體識別出“張小龍”是實體且問題涉及“負(fù)責(zé)”關(guān)系會主要調(diào)用圖譜檢索智能體從知識圖譜中查找(張小龍)-[:LEADS]-(微信團(tuán)隊)這樣的關(guān)系。檢索到的混合上下文文檔片段知識三元組被送入大模型生成最終答案。5. 常見問題與排查思路在實現(xiàn)和運(yùn)行上述流程時你可能會遇到一些典型問題。以下是一些常見問題及其解決方案問題現(xiàn)象可能原因排查與解決思路Neo4j 連接失敗1. Docker 服務(wù)未啟動。2. 認(rèn)證信息錯誤。3. 防火墻阻止了端口 7687。1. 運(yùn)行docker-compose ps檢查服務(wù)狀態(tài)。2. 確認(rèn)docker-compose.yml中的密碼與連接代碼一致。3. 嘗試在瀏覽器訪問http://localhost:7474進(jìn)行驗證。Milvus 插入或搜索報錯1. 集合未正確加載 (load())。2. 向量維度與集合定義不匹配。3. 索引未創(chuàng)建或類型不匹配。1. 插入數(shù)據(jù)后務(wù)必執(zhí)行collection.load()。2. 檢查SentenceTransformer模型輸出的維度是否與FieldSchema中定義的dim一致。3. 使用utility.list_collections()和collection.index()檢查集合和索引狀態(tài)。知識抽取效果差1. LLM 提示詞 (Prompt) 不夠精確。2. 文本分割過碎丟失上下文。3. 實體/關(guān)系類型定義模糊。1. 優(yōu)化 Prompt提供更明確的指令和輸出格式示例。2. 調(diào)整RecursiveCharacterTextSplitter的chunk_size和chunk_overlap參數(shù)。3. 在系統(tǒng)指令中預(yù)定義清晰的實體類型如 Person, Organization, Product和關(guān)系類型。圖譜檢索返回空結(jié)果1. 實體識別 (NER) 失敗未從問題中提取出正確實體名。2. 圖譜中實體名稱與識別出的名稱不完全匹配如簡稱、別稱。1. 使用更專業(yè)的 NER 模型或 API 替代簡單的 LLM 抽取。2. 在圖譜中建立同義詞索引或在查詢時使用模糊匹配、別名映射。決策智能體策略不準(zhǔn)1. 決策 Prompt 過于簡單。2. 問題類型復(fù)雜單一策略權(quán)重不夠。1. 豐富決策邏輯例如加入問題分類事實型、關(guān)系型、比較型、因果型。2. 實現(xiàn)更復(fù)雜的融合策略如根據(jù)need_factual_detail和need_relationship的分?jǐn)?shù)動態(tài)調(diào)整兩種檢索結(jié)果的權(quán)重和排序。系統(tǒng)響應(yīng)速度慢1. 每次檢索都實時調(diào)用 LLM 進(jìn)行決策和實體識別。2. 圖譜查詢或向量搜索未優(yōu)化。1. 對決策和實體識別結(jié)果進(jìn)行緩存。2. 為圖譜中的實體名稱建立索引。對 Milvus 集合使用更高效的索引類型如HNSW??紤]批量處理查詢。6. 最佳實踐與工程建議將 YouToGraphRAG 理念應(yīng)用于生產(chǎn)環(huán)境需要考慮更多的工程細(xì)節(jié)和優(yōu)化策略。1. 知識抽取的工業(yè)化專用模型對于垂直領(lǐng)域如醫(yī)療、法律訓(xùn)練或微調(diào)專用的命名實體識別NER和關(guān)系抽取RE模型比通用LLM更準(zhǔn)確、更經(jīng)濟(jì)。增量更新設(shè)計知識圖譜的增量更新機(jī)制避免每次全量重建。監(jiān)聽數(shù)據(jù)源變化只對新增或修改的文檔進(jìn)行抽取和融合。質(zhì)量校驗建立三元組的質(zhì)量校驗流程包括自動規(guī)則如關(guān)系合理性和人工抽樣審核確保圖譜數(shù)據(jù)的準(zhǔn)確性。2. 圖譜與向量存儲的優(yōu)化圖數(shù)據(jù)庫優(yōu)化索引為實體的name、type等高頻查詢屬性創(chuàng)建索引。冗余設(shè)計對于頻繁查詢的多跳關(guān)系可以物化預(yù)計算并存儲一些路徑以空間換時間。分片超大規(guī)模圖譜需考慮按業(yè)務(wù)域分片存儲。向量數(shù)據(jù)庫優(yōu)化索引選擇根據(jù)數(shù)據(jù)規(guī)模和查詢延遲要求選擇索引如IVF_FLAT,HNSW,SCANN。分區(qū)可以按文檔類型、時間、主題對向量集合進(jìn)行分區(qū)提高查詢效率。標(biāo)量過濾結(jié)合 Milvus 的標(biāo)量過濾功能在向量搜索前先按元數(shù)據(jù)如文檔ID、主題過濾縮小搜索范圍。3. 智能體檢索的進(jìn)階設(shè)計多智能體協(xié)作除了向量和圖譜智能體可以引入更多關(guān)鍵詞檢索智能體處理包含明確術(shù)語的查詢。摘要檢索智能體當(dāng)問題寬泛時返回主題的摘要性描述。元數(shù)據(jù)過濾智能體根據(jù)用戶身份、查詢歷史動態(tài)過濾結(jié)果。精細(xì)化決策決策智能體可以基于更豐富的特征如查詢長度、疑問詞、實體數(shù)量、歷史會話上下文等進(jìn)行綜合判斷。學(xué)習(xí)型重排序收集用戶對答案的反饋如點擊、采納訓(xùn)練一個重排序模型對初步融合的結(jié)果進(jìn)行最終排序。4. 系統(tǒng)可觀測性與維護(hù)全鏈路日志記錄每個智能體的輸入、輸出、耗時以及決策邏輯便于問題追蹤和效果分析。效果評估指標(biāo)定義并監(jiān)控關(guān)鍵指標(biāo)如檢索召回率、答案準(zhǔn)確率、響應(yīng)延遲、用戶滿意度等。知識圖譜可視化提供管理界面可視化展示知識圖譜的結(jié)構(gòu)、聚類情況支持人工干預(yù)和修正。5. 安全與權(quán)限數(shù)據(jù)訪問控制在圖數(shù)據(jù)庫和向量數(shù)據(jù)庫層面實施基于角色的訪問控制確保用戶只能檢索其有權(quán)訪問的知識子圖。內(nèi)容審核在答案生成前對檢索到的上下文和生成的答案進(jìn)行內(nèi)容安全審核防止產(chǎn)生有害信息。推理可解釋性對于基于圖譜的推理應(yīng)能向用戶展示得出答案所依據(jù)的關(guān)系路徑增強(qiáng)可信度。通過以上實踐你可以將一個概念驗證的 YouToGraphRAG demo逐步演進(jìn)為一個健壯、高效、可維護(hù)的企業(yè)級知識庫與智能問答系統(tǒng)。其核心價值在于通過結(jié)構(gòu)化的知識組織和智能化的檢索策略讓大模型不僅能“看到”文本更能“理解”文本背后的復(fù)雜網(wǎng)絡(luò)從而給出更精準(zhǔn)、更深入、更具邏輯性的回答。