Github 上 Star 數最多的大模型應用基礎服務 Dify 深度解讀(一)

背景介紹

接觸過大模型應用開發的研發同學應該都或多或少地聽過 Dify 這個大模型應用基礎服務,這個項目自從 2023 年上線以來,截止目前(2024-6)已經獲得了 35k 多的 star,是目前大模型應用基礎服務中最熱門的項目之一。這篇文章對 Dify 中核心的基礎模塊 RAG 服務進行深入解讀,后續可能會更新其他模塊的內容。

Dify 簡介

Dify 是一個 LLMOps 服務, 涵蓋了大語言模型(如GPT系列)開發、部署、維護和優化的一整套實踐和流程。可以大幅簡化大模型應用的開發。

基于 Dify 可以在不需要太多開發的情況下,快速搭建一個大模型應用。應用中可以調用 Dify 中內置的大量基礎能力,比如知識庫檢索 RAG,大模型調用。通過可插拔式的組合構建大模型應用。一個典型的應用如下所示:
請添加圖片描述

上面的場景中使用分類場景,RAG 服務以及大模型調用的基礎模塊,組合生成一個大模型應用。

RAG 核心流程

RAG 服務的基礎流程在之前的 搭建離線私有大模型知識庫 文章中已經介紹過了。RAG 服務的開源框架 有道 QAnything 和 Ragflow 也都解讀過基礎的 RAG 流程了,這部分就不詳細展開了。一般情況下,RAG 服務會包含如下所示的功能模塊:

  • 文件加載的支持;
  • 文件的預處理策略;
  • 文件檢索的支持;
  • 檢索結果的重排;
  • 大模型的處理;

因為 RAG 服務只是 Dify 中的一個基礎模塊,官方沒有過多強調 RAG 服務的獨特設計,但是依舊可以看到一個獨特點:

  1. 支持 Q&A 模式,與上述普通的「Q to P」(問題匹配文本段落)匹配模式不同,它是采用「Q to Q」(問題匹配問題)匹配工作;
  2. 豐富的召回模式,支持 N 選 1 召回多路召回

下面的部分會對獨特之處進行詳細展開。

核心模塊解讀

之前介紹過來自中科院的 RAG 服務 GoMate 采取的是模塊化設計,方便進行上層應用的組合。從目前的實現來看,Dify 的 RAG 設計也是采用模塊化設計,RAG 的代碼實現都在 api/core/rag 中,從代碼結構上也很容易理解各個模塊的作用:

請添加圖片描述

深入來看代碼的實現質量也比較高,對 RAG 的模塊化設計感興趣的可以深入了解下實現細節。

文件加載

Dify 的文件加載都是在 api/core/rag/extractor/extract_processor.py 中實現的,主要的文件解析是基于 unstructured 實現,另外基于其他第三方庫實現了特定格式文件的處理

比如對于 pdf 文件,會基于 pypdfium2 進行解析,html 是基于 BeautifulSoup 進行解析,這部分代碼實現都比較簡單,就不展開介紹了。

文件預處理

加載的模型中的內容可能會存在一些問題,比如多余的無用字符,編碼錯誤或其他的一些問題,因此需要對文件解析的內容進行必要的清理,這部分代碼實現在 api/core/rag/cleaner 中。實際的清理都是基于 unstructured cleaning 實現的,Dify 主要就是將不同的清理策略封裝為同樣的接口,方便應用層自由選擇。這部分實現也比較簡單,感興趣可以自行了解下。

Q&A 模式

Q&A 分段模式功能,與上述普通的「Q to P」(問題匹配文本段落)匹配模式不同,它是采用「Q to Q」(問題匹配問題)匹配工作,在文檔經過分段后,經過總結為每一個分段生成 Q&A 匹配對,當用戶提問時,系統會找出與之最相似的問題,然后返回對應的分段作為答案,實際的流程如下所示:

請添加圖片描述

從上面的流程可以看到,Q&A 模式下會根據原始文檔生成問答對,實現實現是在 api/core/llm_generator/llm_generator.py 中:

# 構造 promptGENERATOR_QA_PROMPT = ('<Task> The user will send a long text. Generate a Question and Answer pairs only using the knowledge in the long text. Please think step by step.''Step 1: Understand and summarize the main content of this text.\n''Step 2: What key information or concepts are mentioned in this text?\n''Step 3: Decompose or combine multiple pieces of information and concepts.\n''Step 4: Generate questions and answers based on these key information and concepts.\n''<Constraints> The questions should be clear and detailed, and the answers should be detailed and complete. ''You must answer in {language}, in a style that is clear and detailed in {language}. No language other than {language} should be used. \n''<Format> Use the following format: Q1:\nA1:\nQ2:\nA2:...\n''<QA Pairs>'
)def generate_qa_document(cls, tenant_id: str, query, document_language: str):prompt = GENERATOR_QA_PROMPT.format(language=document_language)model_manager = ModelManager()model_instance = model_manager.get_default_model_instance(tenant_id=tenant_id,model_type=ModelType.LLM,)# 拼接出完整的調用 promptprompt_messages = [SystemPromptMessage(content=prompt),UserPromptMessage(content=query)]# 調用大模型直接生成問答對response = model_instance.invoke_llm(prompt_messages=prompt_messages,model_parameters={'temperature': 0.01,"max_tokens": 2000},stream=False)answer = response.message.contentreturn answer.strip()

可以看到就是通過一個 prompt 就完成了原始文檔到問答對的轉換,可以看到大模型確實可以幫助實現業務所需的基礎能力。

文件檢索

知識庫的檢索是在 api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py 中實現的,與常規的 RAG 存在明顯不同之處在于支持了豐富的召回模式。

豐富的召回模式

用戶可以自由選擇所需的召回模式:

請添加圖片描述

  • N 選 1 召回:先根據用戶輸入的意圖選擇合適的知識庫,然后從知識庫檢索所需的文檔,適用于知識庫彼此隔離,不需要互相聯合查詢的場景;
  • 多路召回:此時會同時從多個知識庫檢索,然后進行重新排序,適用于知識庫需要聯合查詢的場景。

常規的 RAG 服務需要先手工選擇知識庫,然后從對應的知識庫進行檢索,無法支持跨庫檢索。相對而言,Dify 的這個設計還是要更方便一些。下面以 N 選 1 召回 為例介紹下文件的檢索,對應的流程如下所示:

請添加圖片描述

N 選 1 召回 的知識庫選擇是基于用戶問題與知識庫描述的語義匹配性來進行選擇,存在 Function Call/ReAct 兩種模式,實現代碼在 api/core/rag/retrieval/dataset_retrieval.py 中,具體如下所示:

tools = []
# 根據用戶輸入的意圖,使用知識庫的描述構造 promptfor dataset in available_datasets:description = dataset.descriptionif not description:description = 'useful for when you want to answer queries about the ' + dataset.namedescription = description.replace('\n', '').replace('\r', '')message_tool = PromptMessageTool(name=dataset.id,description=description,parameters={"type": "object","properties": {},"required": [],})tools.append(message_tool)# 支持 ReAct 模式if planning_strategy == PlanningStrategy.REACT_ROUTER:react_multi_dataset_router = ReactMultiDatasetRouter()dataset_id = react_multi_dataset_router.invoke(query, tools, model_config, model_instance,user_id, tenant_id)
# 支持 Function Call 模式elif planning_strategy == PlanningStrategy.ROUTER:function_call_router = FunctionCallMultiDatasetRouter()dataset_id = function_call_router.invoke(query, tools, model_config, model_instance)
  • Function Call 模式就是構造了一個 prompt,讓大模型根據描述選擇合適的知識庫,實現比較簡單
  • ReAct 模式則是基于 ReAct , 通過推理 + 任務的結合選擇正確的知識庫

知識庫檢索

在前面根據模式選擇了對應的知識庫之后,就可以在單個知識庫內進行檢索,目前支持的檢索方式包含下面三種:

  • 向量檢索,通過生成查詢嵌入并查詢與其向量表示最相似的文本分段。
  • 全文檢索,索引文檔中的所有詞匯,從而允許用戶查詢任意詞匯,并返回包含這些詞匯的文本片段。
  • 混合檢索,同時執行全文檢索和向量檢索,并附加重排序步驟,從兩類查詢結果中選擇匹配用戶問題的最佳結果。

從實際的代碼來看,還有一個 關鍵詞檢索 的能力,但是沒有特別介紹,不確定是否是效果上還不夠穩定,可以關注下后續的進展。混合檢索的流程如下所示:

請添加圖片描述
實際的實現在 api/core/rag/datasource/retrieval_service.py

# 關鍵詞檢索if retrival_method == 'keyword_search':keyword_thread = threading.Thread(target=RetrievalService.keyword_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'top_k': top_k,'all_documents': all_documents,'exceptions': exceptions,})threads.append(keyword_thread)keyword_thread.start()# 向量檢索(混合檢索中也會調用)if RetrievalMethod.is_support_semantic_search(retrival_method):embedding_thread = threading.Thread(target=RetrievalService.embedding_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'top_k': top_k,'score_threshold': score_threshold,'reranking_model': reranking_model,'all_documents': all_documents,'retrival_method': retrival_method,'exceptions': exceptions,})threads.append(embedding_thread)embedding_thread.start()# 文本檢索(混合檢索中也會調用)if RetrievalMethod.is_support_fulltext_search(retrival_method):full_text_index_thread = threading.Thread(target=RetrievalService.full_text_index_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'retrival_method': retrival_method,'score_threshold': score_threshold,'top_k': top_k,'reranking_model': reranking_model,'all_documents': all_documents,'exceptions': exceptions,})threads.append(full_text_index_thread)full_text_index_thread.start()for thread in threads:thread.join()# 混合檢索之后會執行向量和文本檢索結果合并后的重排序if retrival_method == RetrievalMethod.HYBRID_SEARCH:data_post_processor = DataPostProcessor(str(dataset.tenant_id), reranking_model, False)all_documents = data_post_processor.invoke(query=query,documents=all_documents,score_threshold=score_threshold,top_n=top_k)
檢索結果重排

檢索結果的重排也比較簡單,就是通過外部模型進行打分,之后基于打分的結果進行排序,實際的實現在 api/core/model_manager.py 中:

def invoke_rerank(self, query: str, docs: list[str], score_threshold: Optional[float] = None,top_n: Optional[int] = None,user: Optional[str] = None) \-> RerankResult:self.model_type_instance = cast(RerankModel, self.model_type_instance)# 輪詢調用重排序模型,獲得重排序得分,并基于得分進行排序return self._round_robin_invoke(function=self.model_type_instance.invoke,model=self.model,credentials=self.credentials,query=query,docs=docs,score_threshold=score_threshold,top_n=top_n,user=user)

總結

本文主要介紹了 Dify 的知識庫 RAG 服務,作為完整 Agent 中一個基礎模塊,Dify 沒有特別強調 RAG 獨特之處,但是依舊存在一些獨特的亮點:

  1. 多種召回模式,支持根據用戶意圖自動選擇合適的知識庫,也可以跨知識庫進行檢索,彌補了常規的 RAG 服務需要用戶手工選擇知識庫的不便之處;
  2. 獨特的 Q&A 模式,可以直接根據文本生成問答對,可以解決常規情況下用戶問題與文本匹配度不夠的問題,但是應該只適用于特定類型的場景,否則可能會因為轉換導致的信息損耗導致效果更差;

總體而言,Dify 中的 RAG 服務是一個設計完備的服務,模塊化的設計方便組合與拓展,一些獨特的設計也可以提升易用性,代碼質量也很高,感興趣的可以深入研究下。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37553.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37553.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37553.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ss命令詳細使用講解文章

ss 命令作為 iproute2 軟件包的一部分&#xff0c;是Socket Statistics的縮寫&#xff0c;也稱為IPC&#xff08;Inter-process Communication&#xff09;套接字統計 ss命令用于顯示sockets&#xff08;套接字&#xff09;的狀態。與netstat類似&#xff0c;但它通常提供更詳…

WebKit 簡介及工作流程探秘

在探索現代互聯網世界的奧秘時&#xff0c;瀏覽器引擎是不可或缺的一環&#xff0c;而 WebKit 正是其中的佼佼者。WebKit&#xff0c;這個開源的瀏覽器渲染引擎&#xff0c;以其卓越的性能和廣泛的支持度&#xff0c;成為了 Safari、早期的 Chrome 以及其他眾多瀏覽器的核心。本…

【筆試記錄】華為 | 20230823 | cpp

獲取連通的相鄰節點列表 題目描述 在網元內&#xff0c;存在了 N 個轉發節點&#xff0c;每個轉發節點有自己唯一的標識 TB 且每個節點有 M 個端口&#xff0c;節點間通過端口進行報文通訊。出于業務隔離的需求&#xff0c;服務器內的端口被劃分為多個通訊平面(用 VLAN 隔離&…

取消lfs, 使用原始文件上傳的辦法

查詢當前倉庫使用lfs的文件&#xff0c;然后刪除 git lfs ls-files 刪除lfs文件后&#xff0c;提交commit git add . git commit -m"remove lfs file" 查詢本地lfs配置 git config --local --list 重置本地lfs配置 git config --unset filter.lfs.smudgegit co…

從0到1搭建微服務框架

目錄 1.技術棧&#xff1a; 2.模塊介紹: 3.關鍵代碼講解 3.1基礎公共模塊(common)依賴&#xff1a; 3.3授權模塊(auth)依賴: 3.4授權模塊核心配置類(AuthrizatonConfig): 3.4 SecurityConfig.java 3.5 bootstrap的核心配置文件(其他服務配置類似這個)&#xff1a; 3.6n…

防爆巡檢終端在石化工廠安全保障中的應用

防爆巡檢終端在石化工廠安全保障中的應用是廣泛而關鍵的&#xff0c;其設計旨在確保在易燃易爆環境中進行安全、有效的巡檢工作。以下是防爆巡檢終端在石化工廠安全保障中的詳細應用描述&#xff1a; 1. 環境監測與預警 防爆巡檢終端配備了各種傳感器&#xff0c;能夠實時監測…

網銀U盾多又亂?后悔沒早點用USB Server遠程連接管理!

一、引言 網銀服務已成為企業日常運營中不可或缺的一部分。但隨著企業規模的擴大和業務的增多&#xff0c;網銀U盾的數量也隨之激增&#xff0c;又多又亂&#xff0c;只能頻繁插拔、分散管理&#xff0c;不僅效率低下&#xff0c;而且存在嚴重的安全隱患。 事實上&#xff0…

ADS131A04硬件設計與軟件調試

一、IC基本信息 ADS131A0x 雙通道或四通道 24 位 128kSPS 同步采樣 Δ-Σ ADC ?雙通道或四通道同步采樣差分輸入 ? 數據速率&#xff1a;高達 128kSPS ? 高性能&#xff1a; – 單通道精度&#xff1a;在 10,000:1 動態范圍內優于 0.1% – 有效分辨率&#xff1a;20.6位…

SpringCloud-服務網關-Gateway

1.服務網關在微服務中的應用 (1)對外提供服務的難題分析&#xff1a; 微服務架構下的應用系統體系很龐大&#xff0c;光是需要獨立部署的基礎組件就有注冊中心、配置中心和服務總線、Turbine異常聚合和監控大盤、調用鏈追蹤器和鏈路聚合&#xff0c;還有Kaka和MQ之類的中間件&…

海思NNIE部署yolov5-shufflenet

1.簡要說明 由于NNIE上transpose支持的順序是固定的,shufflenet那種x=torch.transpose(x,1,2).contiguous() 的操作一般是不支持的。需要進行調整。 2.使用工程以及修改 使用的是開源工程:GitHub - Lufei-github/shufflev2-yolov5: shufflev2-yolov5:lighter, faster and ea…

c++應用網絡編程之一基本介紹

一、網絡編程介紹 c編程的應用場景在前面分析過&#xff0c;一個重要的方向就是網絡編程。一般來說&#xff0c;開發者說的服務端編程在c方向上簡單的可以認為是網絡編程。首先需要說明的&#xff0c;本系列不對網絡編程的相關基礎知識展開詳細的說明&#xff0c;因為這種知識…

瑪格家居從深交所轉板北交所:營收凈利潤連年下滑,銷售費用大增

《港灣商業觀察》施子夫 近日&#xff0c;瑪格家居股份有限公司&#xff08;以下簡稱&#xff0c;瑪格家居&#xff09;發布公告&#xff0c;重慶證監局已經受理其北交所上市的備案申請&#xff0c;輔導機構為國泰君安證券。 公開信息顯示&#xff0c;2022年1月&#xff0c;瑪…

【轉】Android靜態集成X5內核

項目中的老機器使用webview 無法加載vue3打包的網頁&#xff0c;只能用獨立的webview內核&#xff0c;采用靜態加載x5內核的方式&#xff0c; 以下內容轉自簡書作者漆先生的博客&#xff0c;僅用作備份記錄 之前在項目中在線集成的X5內核&#xff0c;但是效果不好&#xff0c;只…

基于STM32的智能電池管理系統

目錄 引言環境準備智能電池管理系統基礎代碼實現&#xff1a;實現智能電池管理系統 4.1 數據采集模塊4.2 數據處理與分析4.3 控制系統實現4.4 用戶界面與數據可視化應用場景&#xff1a;電池管理與優化問題解決方案與優化收尾與總結 1. 引言 智能電池管理系統&#xff08;Ba…

【昇思25天學習打卡營打卡指南-第十三天】ShuffleNet圖像分類

ShuffleNet圖像分類 ShuffleNet網絡介紹 ShuffleNetV1是曠視科技提出的一種計算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一樣主要應用在移動端&#xff0c;所以模型的設計目標就是利用有限的計算資源來達到最好的模型精度。ShuffleNetV1的設計核心是引入了兩種操…

GPT-5 一年半后發布,打開人工智能新世紀

關于GPT-5一年半后發布的消息&#xff0c;這一預測主要基于OpenAI首席技術官Mira Murati的采訪和聲明。然而&#xff0c;需要明確的是&#xff0c;這個時間點&#xff08;即2025年底或2026年初&#xff09;已經與早期傳聞有所不同&#xff0c;顯示了OpenAI對產品質量的重視&…

react18.x+播放文本內容

需要調接口將文字傳遞給后端將文字轉換成音頻文件&#xff0c;然后播放&#xff0c;同時每次播放不同文本時&#xff0c;當前播放的文本需要暫停&#xff0c;切換到播放新點擊的文本 可以設置緩存播放過的音頻&#xff0c;也可以不設置緩存&#xff1a; 設置緩存的代碼如下&am…

驍龍相機拍照流程分析

和你一起終身學習&#xff0c;這里是程序員Android 經典好文推薦&#xff0c;通過閱讀本文&#xff0c;您將收獲以下知識點: 1.deliverInputEvent 拍照點擊事件處理 2.submitRequestList Camera 提交拍照請求 3.createCaptureRequest 拍照請求幀數 驍龍相機通過binder 數據傳輸…

idea 內存參數修改不生效問題解決 VM參數設置不生效解決

很多人配置idea 內存參數&#xff0c;怎么配置都不生效&#xff0c;主要原因是配置文件用的不是你修改的那個。 系統環境變量中的這個才是你真正要修改的配置文件。 找到并修改后保存&#xff0c;重啟idea就可生效

C++ | Leetcode C++題解之第208題實現Trie(前綴樹)

題目&#xff1a; 題解&#xff1a; class Trie { private:vector<Trie*> children;bool isEnd;Trie* searchPrefix(string prefix) {Trie* node this;for (char ch : prefix) {ch - a;if (node->children[ch] nullptr) {return nullptr;}node node->children[…