很少有一種技術(shù)既能充當(dāng)幕后扛旗的無(wú)名英雄,又能兼具網(wǎng)紅明星的氣質(zhì)。
而DeepSeek做到了這一點(diǎn)。
作為提升生產(chǎn)力的利器,DeepSeek正吸引著眾多個(gè)人開發(fā)者與企業(yè)用戶的興趣,他們紛紛尋求在本地環(huán)境中部署DeepSeek-R1模型,以充分利用其強(qiáng)大的AI能力。
隨著大語(yǔ)言模型和RAG技術(shù)的快速發(fā)展,AI知識(shí)庫(kù)系統(tǒng)正在全面滲透各行各業(yè)。
目前,我們已經(jīng)在多個(gè)領(lǐng)域見證了其成功應(yīng)用,包括跨境電商平臺(tái)的智能客服、教育機(jī)構(gòu)的個(gè)性化學(xué)習(xí)助手、醫(yī)療機(jī)構(gòu)的診斷支持系統(tǒng),以及餐飲行業(yè)的智能點(diǎn)餐服務(wù)等實(shí)際落地案例。
下面博主將詳細(xì)介紹如何利用 一張RTX 4090顯卡 在本地部署基于DeepSeek-R1(深度思考模型)和RAG技術(shù)的知識(shí)庫(kù)系統(tǒng)(Knowledge Base System)。
該系統(tǒng)可廣泛應(yīng)用于智能客服、企業(yè)內(nèi)部知識(shí)管理、學(xué)術(shù)研究及教育等多個(gè)領(lǐng)域,為企業(yè)智能化轉(zhuǎn)型提供新動(dòng)能,助力企業(yè)實(shí)現(xiàn)提質(zhì)增效。
首先體驗(yàn)一下部署效果(圖片來(lái)自MaxKB),一睹為快。
若有系統(tǒng)搭建或咨詢需求,請(qǐng)留言或關(guān)注本公眾號(hào)私信博主。
汽車跨境電商智能AI客服 生物醫(yī)藥AI客服 微信客服 釘釘機(jī)器人 配置飛書機(jī)器人 飛書機(jī)器人 深圳信用中心 AI 助手 華萊士智能AI客服助手 高校教學(xué)管理AI小助手 高校教學(xué)管理AI小助手-微信公眾號(hào) 低代碼可視化業(yè)務(wù)流程編排 創(chuàng)建函數(shù)腳本 后端應(yīng)用監(jiān)控 在數(shù)字化轉(zhuǎn)型的浪潮下,個(gè)人和企業(yè)內(nèi)部的信息管理面臨著很大的挑戰(zhàn)。傳統(tǒng)的信息管理系統(tǒng)往往存在數(shù)據(jù)分散、檢索效率低下、缺乏智-能化支持等問題。尤其是在面對(duì)海量非結(jié)構(gòu)化數(shù)據(jù)時(shí),企業(yè)難以快速提取有價(jià)值的信息,導(dǎo)致決策效率低下。
在專有領(lǐng)域,AI大模型LLM無(wú)法學(xué)習(xí)到所有的專業(yè)知識(shí)細(xì)節(jié),因此在面向?qū)I(yè)領(lǐng)域知識(shí)的提問時(shí),無(wú)法給出可靠準(zhǔn)確的回答,甚至?xí)昂詠y語(yǔ)”,這種現(xiàn)象稱之為L(zhǎng)LM的“幻覺”。
為此,實(shí)現(xiàn)AI大模型商用級(jí)知識(shí)庫(kù)主要有兩種方法:
第一種:通過專業(yè)知識(shí)的再訓(xùn)練或模型微調(diào)來(lái)增強(qiáng)模型能力,但這種方法需要大量標(biāo)注數(shù)據(jù)和計(jì)算資源,成本高昂,對(duì)個(gè)人用戶來(lái)說不太可行;
第二種:在向大模型提問時(shí)提供相關(guān)背景知識(shí),使模型能夠基于這些上下文信息生成更準(zhǔn)確的回答。這種知識(shí)庫(kù)構(gòu)建方法的核心就是RAG(Retrieval-Augmented Generation,檢索增強(qiáng)生成)技術(shù)。
RAG將信息檢索與生成模型相結(jié)合,其核心流程是:
在生成回答前,先從外部知識(shí)庫(kù)中檢索相關(guān)信息,讓模型能夠引用訓(xùn)練數(shù)據(jù)之外的專業(yè)知識(shí),使其在生成響應(yīng)之前能夠引用訓(xùn)練數(shù)據(jù)來(lái)源之外的權(quán)威知識(shí)庫(kù),再將檢索結(jié)果與用戶輸入結(jié)合,指導(dǎo)生成模型輸出更可靠的回答。
這種方法允許大型語(yǔ)言模型在不重新訓(xùn)練的情況下訪問特定領(lǐng)域或組織的內(nèi)部知識(shí)庫(kù),從而保持其輸出的相關(guān)性、準(zhǔn)確性和實(shí)用性。
檢索增強(qiáng)生成(RAG)把信息檢索技術(shù)和大模型結(jié)合起來(lái),將檢索出來(lái)的文檔和提示詞一起提供給大模型服務(wù),從而生成更可靠的答案,有效地緩解大模型推理的“幻覺”問題。
作為商用級(jí)的知識(shí)庫(kù),不僅僅需要通過RAG和其它基礎(chǔ)組件滿足用戶問題分類、敏感詞檢索等各類復(fù)雜場(chǎng)景需求,還能夠內(nèi)置強(qiáng)大的工作流引擎和函數(shù)庫(kù),支持業(yè)務(wù)流程編排,甚至是通過低代碼實(shí)現(xiàn)可視化自定義工作流,從而指導(dǎo)大模型的工作過程,滿足復(fù)雜業(yè)務(wù)場(chǎng)景下的需求,而這些則交由Agent智能體解決。
如果把AI大模型LLM比作學(xué)生的大腦,把RAG比作教材教輔,那么,就可以把Agent比作眼、耳、鼻、舌、身,協(xié)助LLM完成“應(yīng)試教育”之外的“素質(zhì)教育”。為了過五關(guān)斬六將,應(yīng)對(duì)各種考試,學(xué)霸則需要LangChain這樣的工程化框架,統(tǒng)籌以上各項(xiàng)能力的發(fā)揮。
實(shí)際上,LangChain提供了Models、Prompts、Indexes、Memory、Chains、Agents六大核心抽象,在降低系統(tǒng)實(shí)現(xiàn)復(fù)雜度的同時(shí),提升系統(tǒng)整體的擴(kuò)展性。它的能力邊界只取決于LLM的智力水平和LangChain能提供的工具集的豐富程度。
一、整體框架 1、技術(shù)架構(gòu) · 硬件:一張RTX 4090顯卡(24GB顯存) · 大語(yǔ)言模型:DeepSeek-R1-Distill-Qwen-32B(Qwen 320億參數(shù)Q4量化版DeepSeek-R1蒸餾模型) · 向量模型:text2vec-base-chinese · 向量數(shù)據(jù)庫(kù):PostgreSQL / PG Vector 2、RAG 原理 二、本地部署DeepSeek 1、GPU顯卡內(nèi)存估算 如何準(zhǔn)確計(jì)算大模型所需的顯存大小,是許多開發(fā)者經(jīng)常遇到的問題。掌握GPU內(nèi)存的估算方法,并據(jù)此合理配置硬件資源以支持模型運(yùn)行,是確保大模型成功部署和擴(kuò)展的關(guān)鍵。這一能力也是衡量開發(fā)者對(duì)大模型生產(chǎn)環(huán)境部署和可擴(kuò)展性理解程度的重要指標(biāo)。
要估算服務(wù)大型語(yǔ)言模型所需的 GPU 內(nèi)存,可以使用以下公式:
· M是所需的 GPU 顯卡內(nèi)存(單位:GB千兆字節(jié))。 · P是模型中的參數(shù)數(shù)量,表示模型的大小。例如,這里使用的 Llama 90B模型有 900 億個(gè)參數(shù),則該值將為 90。 · 4B表示每個(gè)參數(shù)使用 4 個(gè)字節(jié)。每個(gè)參數(shù)通常需要 4 個(gè)字節(jié)的內(nèi)存。這是因?yàn)楦↑c(diǎn)精度通常占用 4 個(gè)字節(jié)(32 位)。但是,如果使用半精度(16 位),則計(jì)算將相應(yīng)調(diào)整。 · Q是加載模型的位數(shù)(例如,16 位或 32 位)。根據(jù)以 16 位還是 32 位精度加載模型,此值將會(huì)發(fā)生變化。16 位精度在許多大模型部署中很常見,因?yàn)樗梢詼p少內(nèi)存使用量,同時(shí)保持足夠的準(zhǔn)確性。 · 1.2 乘數(shù)增加了 20% 的開銷,以解決推理期間使用的額外內(nèi)存問題。這不僅僅是一個(gè)安全緩沖區(qū);它對(duì)于覆蓋模型執(zhí)行期間激活和其他中間結(jié)果所需的內(nèi)存至關(guān)重要。 估算GPU顯存大小 舉例:以滿血版DeepSeek-R1(671B參數(shù)、加載 16 位精度)為例,計(jì)算其推理所需的顯存:
這個(gè)計(jì)算告訴我們,需要大約1610.4 GB 的 GPU 顯存來(lái)為 16 位模式下具有 6710 億個(gè)參數(shù)的滿血版 DeepSeek-R1 大模型提供推理服務(wù)。
因此,單個(gè)具有 80 GB 顯存的 NVIDIA A100 GPU 或者 H00 GPU 不足以滿足此模型的需求,需要至少20張具有 80 GB 內(nèi)存的 A100 GPU 才能有效處理內(nèi)存負(fù)載。
此外,僅加載 CUDA 內(nèi)核就會(huì)消耗 1-2GB 的內(nèi)存。實(shí)際上,無(wú)法僅使用參數(shù)填滿整個(gè) GPU 顯存作為估算依據(jù)。
如果是訓(xùn)練大模型,則需要更多的 GPU 顯存,因?yàn)閮?yōu)化器狀態(tài)、梯度和前向激活每個(gè)參數(shù)都需要額外的內(nèi)存。
2、選擇模型 目前DeepSeek-R1系列模型在 Huggingface [1] 上共計(jì)開源了8種。
DeepSeek-R1系列模型 完整系列一覽(按參數(shù)規(guī)模排序):
· DeepSeek-R1-Zero (671B) · DeepSeek-R1-Distill-Llama-70B · DeepSeek-R1-Distill-Qwen-32B · DeepSeek-R1-Distill-Qwen-14B · DeepSeek-R1-Distill-Llama-8B · DeepSeek-R1-Distill-Qwen-7B · DeepSeek-R1-Distill-Qwen-1.5B DeepSeek-R1系列的兩大明星產(chǎn)品:
DeepSeek-R1-Zero:AI界的'極限探索者'
· 超強(qiáng)算力:6710億參數(shù)(采用MoE架構(gòu),每個(gè)token可調(diào)動(dòng)370億參數(shù)) · 創(chuàng)新訓(xùn)練:采用純強(qiáng)化學(xué)習(xí)的端到端訓(xùn)練方式 · 突破性能:實(shí)現(xiàn)自我驗(yàn)證、長(zhǎng)鏈推理等前沿能力 · 實(shí)戰(zhàn)表現(xiàn):在AIME 2024基準(zhǔn)測(cè)試中取得71%的亮眼成績(jī) DeepSeek-R1:AI界的'全能冠軍'
· 強(qiáng)大算力:同樣擁有6710億參數(shù)的超強(qiáng)實(shí)力 · 獨(dú)特訓(xùn)練:創(chuàng)新性采用多階段混合訓(xùn)練方法 · 雙重加持:結(jié)合監(jiān)督微調(diào)冷啟動(dòng)與強(qiáng)化學(xué)習(xí)優(yōu)化 · 卓越成就:在AIME 2024測(cè)試中達(dá)到79.8%的驚人準(zhǔn)確率 值得一提的是,DeepSeek團(tuán)隊(duì)通過知識(shí)蒸餾技術(shù),成功將這些頂級(jí)模型的能力傳承給更輕量級(jí)的版本。
這種創(chuàng)新方式不僅大幅降低了模型應(yīng)用門檻,還提升了小型模型的推理能力,這正是DeepSeek在AI領(lǐng)域備受矚目的重要原因之一。
DeepSeek-R1 蒸餾模型的幾款小尺寸模型,是使用 DeepSeek-R1 生成的包含 <think>...</think>
標(biāo)記的思考鏈數(shù)據(jù)進(jìn)行微調(diào)后的蒸餾版本,繼承了 R1的推理能力。
畢竟博主囊中羞澀,為了完成這篇文章,選擇 bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF [2] 的DeepSeek-R1-Distill-Qwen-32B大模型的4bit量化模型,根據(jù)上面的估算公式,僅使用1張具有 24 GB 內(nèi)存的 4090 GPU 就可以運(yùn)行完成本文所需的推理任務(wù)。
Qwen2.5-32B是一個(gè)通用的預(yù)訓(xùn)練語(yǔ)言模型,而DeepSeek-R1-Distill-Qwen-32B是基于Qwen2.5-32B使用DeepSeek-R1生成的包含 <think>...</think>
標(biāo)記的思考鏈數(shù)據(jù)進(jìn)行微調(diào)后的蒸餾版本,因此繼承了R1的推理能力。
這些微調(diào)數(shù)據(jù)包含問題拆解、中間推導(dǎo)等推理過程,通過強(qiáng)化學(xué)習(xí)讓DeepSeek-R1-Distill-Qwen-32B對(duì)齊了R1生成推理步驟的行為模式。通過這種蒸餾機(jī)制,小型模型既能保持計(jì)算效率,又獲得了接近大模型的復(fù)雜推理能力,這在資源受限場(chǎng)景下具有重要應(yīng)用價(jià)值。
3、選擇模型推理服務(wù)器和推理框架 在選擇模型后,本地部署面臨的第二個(gè)問題便是如何選擇推理服務(wù)器和推理框架 ??
對(duì)于LLM推理服務(wù)器的選擇,目前主要有三種方法。
提供LLM推理服務(wù)的三種方法 第一種方法是將個(gè)人電腦或租用的服務(wù)器配置成一臺(tái)LLM推理服務(wù)器,本文采取的便是這種搭建方式。
第二種方法是利用OpenAI、Anthropic等大型公司的LLM服務(wù),只需通過API密鑰直接調(diào)用,而無(wú)需訪問其官網(wǎng)。
第三種方法是在云平臺(tái)上構(gòu)建LLM服務(wù)器,并調(diào)用該服務(wù)器的API,常見的選擇包括阿里云、騰訊云、百度云、AWS、Azure、谷歌云,甚至Modal和SkyPilot等服務(wù)。
在具體選擇時(shí),一定要綜合考慮成本,謹(jǐn)慎挑選最適合的模型。
為編寫本文,博主租了一臺(tái)帶有一張RTX 4090 GPU 顯卡的服務(wù)器(花費(fèi)大概10元左右就能完成本文案例的部署,當(dāng)然還需要一些降低費(fèi)用的小技巧,比如提前租用配置的服務(wù)器把模型文件下載到服務(wù)器,這樣就可以節(jié)省很多費(fèi)用??,具體情況可以關(guān)注本公眾號(hào)咨詢博主)。
模型推理服務(wù)器的配置如下:
· CPU:16 核,Xeon(R) Platinum 8352V · 數(shù)據(jù)盤:50 GB(用于存放模型文件、分詞器文件) 在選擇模型推理服務(wù)器后,本地部署面臨的第二個(gè)問題便是如何選擇推理框架,今天我們就來(lái)盤一盤四大主流推理框架的優(yōu)缺點(diǎn):
?? 四大天王對(duì)決: 1?? SGLang - 大規(guī)模集群部署專家 2?? Ollama - 輕量級(jí)玩家最愛 3?? vLLM - GPU推理性能王者 4?? LLaMA.cpp - CPU部署救星
?? 選擇秘籍: ? 要極致性能 → 選vLLM ? 要簡(jiǎn)單易用 → 選Ollama ? 要集群部署 → 選SGLang ? 要CPU運(yùn)行 → 選LLaMA.cpp
?? 性能對(duì)比:
· 推理速度:vLLM > SGLang > Ollama > LLaMA.cpp · 易用程度:Ollama > LLaMA.cpp > vLLM > SGLang · 硬件要求:vLLM(需GPU) > SGLang > Ollama > LLaMA.cpp ?? 實(shí)戰(zhàn)建議:
· 個(gè)人開發(fā)者 → Ollama快速上手 · 企業(yè)級(jí)部署 → SGLang更專業(yè) 目前市面上關(guān)于如何用Ollama拉取Q4或Q8量化模型進(jìn)行本地推理的教程已經(jīng)層出不窮,Ollama 確實(shí)以簡(jiǎn)單易用俘獲了一大批開發(fā)者,但如果你和我一樣,追求的是 生產(chǎn)環(huán)境的穩(wěn)定高效 ,那么Ollama可能就不是你的菜了!
為什么我最終選擇了 vLLM?
· ?? 性能才是硬道理 :Ollama 在高并發(fā)和推理速度上,相比 vLLM 真的弱了不少,尤其是在吃 GPU 算力的場(chǎng)景下。 · ?? 生產(chǎn)環(huán)境 Real Talk :如果你是認(rèn)認(rèn)真真要搞生產(chǎn)部署 DeepSeek-R1,vLLM 這種專為生產(chǎn)設(shè)計(jì)的框架才是更穩(wěn)的選擇。 · ?? RTX 4090 最佳拍檔 :?jiǎn)慰?4090 想發(fā)揮最大威力?vLLM 的優(yōu)化更到位!SGLang 那種大規(guī)模集群方案,對(duì)我們來(lái)說就太重了。 4、搭建環(huán)境 如果模型推理服務(wù)器沒有安裝CUDA和cuDNN的話,需要自行安裝CUDA和cuDNN,并配置環(huán)境變量,具體方法可以參考英偉達(dá)官網(wǎng):
CUDA cuDNN 本文所需的的CUDA、cuDNN、Python和PyTorch版本如下:
· Linux版本:Ubuntu 22.04.3 LTS 讀者可以使用VSCode、Cursor或者其它SSH客戶端連接到云服務(wù)器,然后使用以下命令安裝CUDA和cuDNN。
安裝前需要確保服務(wù)器上已經(jīng)安裝了NVIDIA驅(qū)動(dòng),可以使用以下命令查看是否安裝了NVIDIA驅(qū)動(dòng):
$ nvidia-smi
安裝前,需要確保 PyTorch [5] 與CUDA的版本對(duì)應(yīng),否則會(huì)報(bào)錯(cuò)。
PyTorch與CUDA的對(duì)應(yīng)版本 # 添加 CUDA 存儲(chǔ)庫(kù) $ sudo apt update $ sudo apt install -y software-properties-common $ sudo add-apt-repository ppa:graphics-drivers/ppa # 下載并安裝 CUDA 12.1 $ wget https://developer.download./compute/cuda/12.1/12.1.0/local_installers/cuda_12.1.0_520.61.05_linux.run $ sudo sh cuda_12.1.0_520.61.05_linux.run
在安裝過程中,選擇是否安裝 NVIDIA 驅(qū)動(dòng)(如果你已經(jīng)有安裝過,可以跳過)。
設(shè)置環(huán)境變量:
# 在 .bashrc 中添加 CUDA 路徑 $ echo 'export PATH=/usr/local/cuda-12.1/bin: $PATH ' >> ~/.bashrc $ echo 'export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64: $LD_LIBRARY_PATH ' >> ~/.bashrc $ source ~/.bashrc
要安裝 cuDNN,首先需要從 NVIDIA 官方下載 cuDNN 8.9.0。
下載后,解壓并安裝 cuDNN。
# 假設(shè) cuDNN 安裝包下載到當(dāng)前目錄 $ tar -xzvf cudnn-12.1-linux-x64-v8.9.0.131.tgz # 將 cuDNN 文件復(fù)制到 CUDA 路徑 $ sudo cp cuda/include/cudnn*.h /usr/local/cuda-12.1/include $ sudo cp cuda/lib64/libcudnn* /usr/local/cuda-12.1/lib64 $ sudo chmod a+r /usr/local/cuda-12.1/include/cudnn*.h /usr/local/cuda-12.1/lib64/libcudnn* # 更新庫(kù)路徑 $ echo 'export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64: $LD_LIBRARY_PATH ' >> ~/.bashrc $ source ~/.bashrc
# 安裝 Python 3.10 $ sudo apt update $ sudo apt install -y python3.10 python3.10-dev python3.10-distutils # 設(shè)置 Python 3.10 為默認(rèn)版本 $ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1 # 檢查 Python 版本 $ python3 --version
# 安裝 pip $ sudo apt install -y python3-pip # 安裝 PyTorch 2.5.1+cu124 $ pip install torch==2.5.1+cu124 torchvision torchaudio # 驗(yàn)證安裝 $ python -c 'import torch; print(torch.__version__)'
驗(yàn)證 CUDA 和 cuDNN 是否正確安裝:
# 檢查 CUDA 版本 $ nvcc --version # 檢查 cuDNN 版本 $ cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
驗(yàn)證 PyTorch 是否可以使用 GPU:
$ python -c 'import torch; print(torch.cuda.is_available())'
現(xiàn)在已經(jīng)成功地安裝了 CUDA 12.1、cuDNN 8.9.0、Python 3.10.8 和 PyTorch 2.5.1+cu124 環(huán)境。
可以使用以下命令查看GPU內(nèi)存信息
$ nvidia-smi
如果安裝正確,則可以看到類似如下的GPU內(nèi)存信息
nvidia-smi 執(zhí)行結(jié)果 5、下載DeepSeek模型權(quán)重文件 為了在本地部署模型,事先需要從Huggingface上手動(dòng)下載量化過的DeepSeek-R1的4 bit量化模型 bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF [6] 。
bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF 在這個(gè)頁(yè)面中存在26種尺寸的量化模型。
為了能夠在單卡4090(24GB顯存)進(jìn)行推理,我們選擇其中的DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf。
根據(jù)上文中的GPU顯存估算公式,4bit量化模型理論上會(huì)占用19.2GB左右的顯存,實(shí)際該文件大小為19.9GB。
由于模型權(quán)重文件較大,不建議直連下載,根據(jù)博主的經(jīng)驗(yàn),按照下面的方式下載速度較快。
$ source /etc/network_turbo
$ pip install -U huggingface_hub
· 設(shè)置Huggingface鏡像源(必須設(shè)置,否則下載模型會(huì)報(bào)錯(cuò)??) $ export HF_ENDPOINT=https://
$ huggingface-cli login
$ huggingface-cli download bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF --include 'DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf' --local-dir ./ # 【這里的./可替換為模型在本地的其它存放路徑】
下載成功后的DeepSeek-R1大模型的文件列表如下:
total 19386083 drwxr-xr-x 3 root root 4096 Feb 14 12:34 ./ drwxr-xr-x 4 root root 4096 Feb 14 21:00 ../ drwxr-xr-x 3 root root 4096 Feb 14 10:29 .cache/ -rw-r--r-- 1 root root 19851335840 Feb 14 12:34 DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf
6、下載DeepSeek分詞器tokenizer文件 正常情況下,使用vLLM加載上面DeepSeek模型GGUF權(quán)重文件后,不需要單獨(dú)加載分詞器文件,即可實(shí)現(xiàn)推理。
然而,博主在本地部署DeepSeek后,發(fā)現(xiàn)DeepSeek的官方模型庫(kù)的一個(gè)bug,需要通過修改DeepSeek的分詞器配置文件予以解決。
由于這個(gè)月DeepSeek的官方模型庫(kù)更新了分詞器配置文件tokenizer_config.json里的chat-template,導(dǎo)致本地部署DeepSeek-R1-Distill-Qwen-32B后, 向模型提問時(shí),模型只輸出 </think>
,沒有開頭的 <think>
,從而導(dǎo)致前端應(yīng)用無(wú)法正確識(shí)別DeepSeek的思考過程(Reasoning)。
還有一種解決辦法是:
通過源碼編譯安裝vLLM ,修改deepseek_r1_reasoning_parser.py文件中的相關(guān)代碼,把解析think標(biāo)簽的部分更新一下;說不定還能順便給 vLLM 提個(gè) PR 呢
此外,網(wǎng)上有開發(fā)者建議建議使用DeepSeek基礎(chǔ)模型的 tokenizer 而不是 GGUF 模型的 tokenizer。因?yàn)閺?GGUF 轉(zhuǎn)換 tokenizer 既耗時(shí)又不穩(wěn)定, 尤其是對(duì)于一些詞匯量較大的模型。
基于以上兩點(diǎn)原因,博主單獨(dú)下載DeepSeek分詞器文件,并使用vLLM進(jìn)行加載。
在瀏覽器進(jìn)入 DeepSeek的Hugging Face官方模型庫(kù) [7] 頁(yè)面, 打開 Files and versions 標(biāo)簽,找下面2個(gè)文件。
將圖中2個(gè)文件下載到本地。
通過文本編輯器打開tokenizer_config.json文件,找到字段'chat_template',將其字段值末尾的 <think>\\n
刪除掉即可。
注意:這種解決bug的workaround方式,需要在提示詞中顯式增加 <think></think>
標(biāo)簽,才能啟動(dòng)DeepSeek模型的推理Reasoning能力。后文的提示詞中有所體現(xiàn),請(qǐng)讀者留意。
{ 'add_bos_token' : true , 'add_eos_token' : false , 'bos_token' : { '__type' : 'AddedToken' , 'content' : '<|begin▁of▁sentence|>' , 'lstrip' : false , 'normalized' : true , 'rstrip' : false , 'single_word' : false } , 'clean_up_tokenization_spaces' : false , 'eos_token' : { '__type' : 'AddedToken' , 'content' : '<|end▁of▁sentence|>' , 'lstrip' : false , 'normalized' : true , 'rstrip' : false , 'single_word' : false } , 'legacy' : true , 'model_max_length' : 16384 , 'pad_token' : { '__type' : 'AddedToken' , 'content' : '<|end▁of▁sentence|>' , 'lstrip' : false , 'normalized' : true , 'rstrip' : false , 'single_word' : false } , 'sp_model_kwargs' : { } , 'unk_token' : null , 'tokenizer_class' : 'LlamaTokenizerFast' , 'chat_template' : '#此處內(nèi)容省略' }
然后通過scp等方式分別上傳到模型推理服務(wù)器。
$ scp -rP [端口號(hào)] [本地文路徑] root@[遠(yuǎn)程服務(wù)器地址]:[遠(yuǎn)程服務(wù)器目錄]
或者,通過以下命令將上述2個(gè)文件下載到模型推理服務(wù)器,直接在服務(wù)器上修改。
$ huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-32B --include 'tokenizer.json' 'tokenizer_config.json' --local-dir ./tokenizer
7、搭建推理框架vLLM 高效運(yùn)行DeepSeek R1需要一個(gè)高性能的推理引擎,上文博主已分析過了 vLLM 是最佳選擇之一,因?yàn)樗哂袃?yōu)化的內(nèi)存管理、快速的執(zhí)行速度以及與 Hugging Face 模型的無(wú)縫集成。
本文使用 vLLM v1 在本地安裝和運(yùn)行 DeepSeek R1,以實(shí)現(xiàn)消費(fèi)級(jí) GPU 上的高速推理。
$ pip install vllm --upgrade
無(wú)縫啟用 vLLM v1,只需將 VLLM_USE_V1=1 環(huán)境變量設(shè)置為 1,而無(wú)需對(duì)現(xiàn)有 API 進(jìn)行任何更改。
$ export VLLM_USE_V1=1
8、啟動(dòng)DeepSeek推理服務(wù) 一切準(zhǔn)備就緒后,執(zhí)行以下命令使用vLLM加載DeepSeek模型,提供與OpenAI API兼容的DeepSeek推理服務(wù)接口。
部署大模型具挑戰(zhàn)性的部分是需要根據(jù)你自己的具體情況配置每個(gè)組件,有可能會(huì)頻繁發(fā)生內(nèi)存不足 (OOM) 錯(cuò)誤,因此選擇正確的模型并調(diào)整運(yùn)行參數(shù)至關(guān)重要。
$ python -m vllm.entrypoints.openai.api_server \ --served-model-name bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF \ --model [DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf文件的存儲(chǔ)路徑] \ --trust-remote-code \ --host 0.0.0.0 \ --port 6006 \ --max-model-len 2048 \ --dtype float16 \ --enable-prefix-caching \ --enforce-eager \ --max_num_seqs 1 \ --api-key [API訪問密鑰] \ --tokenizer [分詞器tokenizer的存儲(chǔ)路徑]
根據(jù)博主的經(jīng)驗(yàn),以上便是最佳設(shè)置,針對(duì)每個(gè)參數(shù),說明如下:
· served-model-name,指定模型的名稱。 · model,DeepSeek模型權(quán)重文件的路徑。 · max-model-len,模型上下文長(zhǎng)度。如果未指定,將繼承模型自身配置。將max_model_len設(shè)置為2048、4096或8196,以找到在沒有錯(cuò)誤的情況下工作的最大值。如果取值過大,你可能會(huì)遇到OOM錯(cuò)誤。 · max_num_seqs,用于配置同時(shí)處理多少個(gè)請(qǐng)求;由于這將使內(nèi)存使用量增加一倍,因此最好將其設(shè)置為1。 · trust-remote-code,加載HuggingFace自定義代碼時(shí)必須啟用。 · host和port,可以根據(jù)你的服務(wù)器機(jī)器的具體情況進(jìn)行配置。 · dtype,權(quán)重和激活參數(shù)的數(shù)據(jù)類型,用于控制計(jì)算精度,常用float16/bfloat16。 · enforce-eager,用于啟用 eager 模式,加快推理速度。 · enable-prefix-caching,重復(fù)調(diào)用接口時(shí)緩存提示詞內(nèi)容,以加快推理速度。例如,如果你輸入一個(gè)長(zhǎng)文檔并詢問有關(guān)它的各種問題,啟用該參數(shù)將提高性能。 · api-key,用于設(shè)置API訪問秘鑰,保證自己的DeepSeek不會(huì)被隨便訪問,自行設(shè)置一個(gè)字符串即可;當(dāng)后文部署的知識(shí)庫(kù)應(yīng)用訪問DeepSeek推理服務(wù)器時(shí),會(huì)檢查其請(qǐng)求頭中的 API 密鑰。 · tokenizer,如前文所述,單獨(dú)下載的DeepSeek分詞器存儲(chǔ)目錄。 · tensor-parallel-size,指定GPU數(shù)量,本文只用單卡,因此不用設(shè)置此參數(shù)。 另一種方法是運(yùn)行 vllm serve
命令,加載DeepSeek-R1-Distill-Qwen-32B-GGUF模型。
$ vllm serve [DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf文件的存儲(chǔ)路徑] \ --served-model-name bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF \ --trust-remote-code \ --host 0.0.0.0 \ --port 6006 \ --max-model-len 2048 \ --dtype float16 \ --enable-prefix-caching \ --enforce-eager \ --max_num_seqs 1 \ --api-key [API訪問密鑰] \ --tokenizer [分詞器tokenizer的存儲(chǔ)路徑]
在執(zhí)行如上所述的命令后,希望沒有錯(cuò)誤發(fā)生。
加載完畢后出現(xiàn)如下信息說明服務(wù)成功啟動(dòng)。
INFO 02-19 19:49:36 gpu_model_runner.py:872] Loading model weights took 18.5326 GB INFO 02-19 19:49:45 kv_cache_utils.py:407] # GPU blocks: 376 INFO 02-19 19:49:45 kv_cache_utils.py:410] Maximum concurrency for 2048 tokens per request: 2.94x INFO 02-19 19:49:45 core.py:91] init engine (profile, create kv cache, warmup model) took 8.87 seconds INFO 02-19 19:49:45 api_server.py:756] Using supplied chat template: INFO 02-19 19:49:45 api_server.py:756] None INFO 02-19 19:49:45 launcher.py:21] Available routes are: INFO 02-19 19:49:45 launcher.py:29] Route: /openapi.json, Methods: GET, HEAD INFO 02-19 19:49:45 launcher.py:29] Route: /docs, Methods: GET, HEAD INFO 02-19 19:49:45 launcher.py:29] Route: /docs/oauth2-redirect, Methods: GET, HEAD INFO 02-19 19:49:45 launcher.py:29] Route: /redoc, Methods: GET, HEAD INFO 02-19 19:49:45 launcher.py:29] Route: /health, Methods: GET INFO 02-19 19:49:45 launcher.py:29] Route: /ping, Methods: POST, GET INFO 02-19 19:49:45 launcher.py:29] Route: /tokenize, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /detokenize, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v1/models, Methods: GET INFO 02-19 19:49:45 launcher.py:29] Route: /version, Methods: GET INFO 02-19 19:49:45 launcher.py:29] Route: /v1/chat/completions, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v1/completions, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v1/embeddings, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /pooling, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /score, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v1/score, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /rerank, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v1/rerank, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /v2/rerank, Methods: POST INFO 02-19 19:49:45 launcher.py:29] Route: /invocations, Methods: POST INFO: Started server process [3433] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:6006 (Press CTRL+C to quit)
此時(shí),使用 nvidia-smi
查看顯存占用情況。
加載DeepSeek后顯存占用情況 可以看到,加載DeepSeek后,24GB的顯存已被占用21GB。
顯存實(shí)際占用 = 模型權(quán)重占用 + KV cache占用 + 其他內(nèi)存開銷
根據(jù)日志信息,這里對(duì)顯存占用進(jìn)行分析:
1. 模型權(quán)重內(nèi)存 (主要占用) · 模型權(quán)重文件加載后占用 18.5326 GB · 這是量化后的 Q4_K_M 格式模型,原始 32B 模型如果是 FP16 格式約需 64GB,量化后顯存占用大幅降低 · 包含 embedding 層、transformer 層參數(shù)等 · 分配了 376 個(gè) GPU blocks 用于存儲(chǔ) KV cache · 每個(gè) block 存儲(chǔ)的 token 數(shù)由 block_size
參數(shù)決定(默認(rèn) 16) · 計(jì)算公式: KV Cache 內(nèi)存 = 2 * num_layers * num_heads * head_dim * seq_length * batch_size * dtype_size
· 支持 2048 token 請(qǐng)求時(shí)的最大并發(fā)達(dá)到 2.94 倍;這部分內(nèi)存在生成過程中按需分配,可大幅提高推理效率,但也會(huì)增加總體顯存占用。 · 系統(tǒng)保留內(nèi)存:約 0.5-1 GB 因此,整個(gè) GPU 內(nèi)存消耗可以看作是靜態(tài)的模型參數(shù)和動(dòng)態(tài)計(jì)算緩存(KV cache)兩大塊的合并。
確保 GPU 顯存充足不僅要滿足模型權(quán)重加載的 18.5GB,還需要預(yù)留足夠空間應(yīng)付 KV cache 及其他運(yùn)行時(shí)需求。
使用vLLM成功加載模型后,現(xiàn)在就可以使用DeepSeek R1模型了。
· 通過瀏覽器查看當(dāng)前服務(wù)接口文檔 通過瀏覽器訪問 http://localhost:6006/docs 查看 vLLM 支持的 DeepSeek API 接口
DeepSeek API · 通過 curl 命令查看當(dāng)前的模型列表 $ curl http://localhost:6006/v1/models -H 'Authorization: Bearer ds-key-001'
輸出結(jié)果:
{ 'object' : 'list' , 'data' : [ { 'id' : '/root/autodl-fs/model/deepseek/bartowski/DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf' , 'object' : 'model' , 'created' : 1739969336 , 'owned_by' : 'vllm' , 'root' : '/root/autodl-fs/model/deepseek/bartowski/DeepSeek-R1-Distill-Qwen-32B-Q4_K_M.gguf' , 'parent' : null , 'max_model_len' : 2048 , 'permission' : [ { 'id' : 'modelperm-f96541eb4c5849baa7d25b138009a094' , 'object' : 'model_permission' , 'created' : 1739969336 , 'allow_create_engine' : false , 'allow_sampling' : true , 'allow_logprobs' : true , 'allow_search_indices' : false , 'allow_view' : true , 'allow_fine_tuning' : false , 'organization' : '*' , 'group' : null , 'is_blocking' : false } ] } ] }
· 使用 curl 命令測(cè)試 DeepSeek API $ curl http://localhost:6006/v1/chat/completions \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ds-key-001' \ -d '{ 'model': 'bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF', 'messages': [ {'role': 'user', 'content': '問題:玄武門之變結(jié)束的當(dāng)天,李世民在深夜寫下一段獨(dú)白,他會(huì)寫什么?要求:先思考,然后按照以下格式回答用戶的問題:<think>推理內(nèi)容</think>內(nèi)容'} ], 'temperature': 0.6 }'
注:如前文所述,為了啟用DeepSeek的推理能力,需要在提示詞中的問題后面增加以下內(nèi)容:
先思考,然后按照以下格式回答用戶的問題:
<think>推理內(nèi)容</think>
內(nèi)容
使用建議:
為了獲得預(yù)期的性能,建議在使用 DeepSeek-R1 系列模型(包括基準(zhǔn)測(cè)試)時(shí),遵循以下配置:
· 將溫度設(shè)置在 0.5-0.7 范圍內(nèi)(推薦 0.6),以防止無(wú)休止的重復(fù)或語(yǔ)無(wú)倫次的輸出。 · 避免添加系統(tǒng)提示;所有指令都應(yīng)包含在用戶提示中。 · 對(duì)于數(shù)學(xué)問題,建議在提示中包含如下指令:“請(qǐng)逐步推理,并將最終答案放在 \boxed{} 中。” · 在評(píng)估模型性能時(shí),建議進(jìn)行多次測(cè)試并對(duì)結(jié)果取平均值。 執(zhí)行以上命令后,在啟動(dòng)vLLM服務(wù)的終端窗口,可以看到以下日志:
INFO 02-19 20:55:19 loggers.py:72] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs GPU KV cache usage: 0.0%. INFO 02-19 20:55:24 loggers.py:72] Avg prompt throughput: 9.2 tokens/s, Avg generation throughput: 36.8 tokens/s, Running: 1 reqs, Waiting: 0 reqs GPU KV cache usage: 4.5%. INFO 02-19 20:55:29 loggers.py:72] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 38.7 tokens/s, Running: 1 reqs, Waiting: 0 reqs GPU KV cache usage: 7.2%. INFO: 127.0.0.1:54702 - 'POST /v1/chat/completions HTTP/1.1' 200 OK
下面對(duì)日志中提到的幾個(gè)指標(biāo)進(jìn)行說明:
· Avg prompt throughput 反映了 prompt 處理的速度,數(shù)值可能因 prompt 大小及初始處理開銷而波動(dòng); · Avg generation throughput 則表示生成輸出過程中的 token 速率,數(shù)值較高表明生成效率較好; · Running reqs 和 Waiting reqs 分別展示了當(dāng)前正在處理與等待處理的請(qǐng)求數(shù)量,當(dāng)前系統(tǒng)負(fù)載較低(運(yùn)行1個(gè)請(qǐng)求、無(wú)等待請(qǐng)求); · GPU KV cache usage 表示生成過程中用于緩存的 GPU 內(nèi)存占用率,隨生成 token 數(shù)的累計(jì)逐步增加,反映模型在動(dòng)態(tài)生成時(shí)對(duì)內(nèi)存的使用情況。 這些指標(biāo)綜合起來(lái)有助于監(jiān)控系統(tǒng)的實(shí)時(shí)性能和資源使用,能夠?yàn)檎{(diào)優(yōu)和擴(kuò)容提供依據(jù)。
· Avg prompt throughput(平均提示吞吐率) · 含義 :該指標(biāo)表示系統(tǒng)處理輸入 prompt 時(shí),單位時(shí)間內(nèi)處理的 token 數(shù)量,通常以 tokens/s 為單位。 · 日志中顯示有一次為 0.0 tokens/s
,另一處為 9.2 tokens/s
。 · 這說明在某個(gè)時(shí)刻(例如剛接收到請(qǐng)求時(shí))prompt 的 token 數(shù)處理速度可能較低,而在實(shí)際載入或處理 prompt 數(shù)據(jù)后,平均每秒可以處理大約 9.2 個(gè) token。 · Avg generation throughput(平均生成吞吐率) · 含義 :該指標(biāo)描述模型在生成響應(yīng)(即生成 tokens 時(shí))的 token 生成速度,同樣以 tokens/s 為單位。 · 日志中分別顯示 36.8 tokens/s
和 38.7 tokens/s
。 · 這表示模型在生成階段的算力較強(qiáng),平均每秒能產(chǎn)生大約 37 個(gè) token,反映了模型生成階段的高效性。 · Running reqs(正在運(yùn)行的請(qǐng)求數(shù)量) · 含義 :這是當(dāng)前系統(tǒng)中正處于活躍狀態(tài)、正在被處理(例如生成響應(yīng))的請(qǐng)求數(shù)。 · 日志中狀態(tài)顯示為 Running: 1 reqs
,這表明當(dāng)前有一個(gè)請(qǐng)求在被系統(tǒng)積極處理。 · Waiting reqs(等待中的請(qǐng)求數(shù)量) · 含義 :表示目前在隊(duì)列中等待處理、尚未啟動(dòng)生成的請(qǐng)求數(shù)量。 · 日志中顯示為 Waiting: 0 reqs
,說明沒有請(qǐng)求處于排隊(duì)等待狀態(tài),系統(tǒng)的調(diào)度和資源分配都能及時(shí)處理進(jìn)入的請(qǐng)求。 · GPU KV cache usage(GPU KV緩存使用率) · 含義 :KV cache(Key-Value Cache)用于 Transformer 模型中保存此前計(jì)算得到的 key 和 value,以便在生成過程中復(fù)用這些信息,從而避免重復(fù)計(jì)算。該指標(biāo)顯示當(dāng)前這部分緩存占用了 GPU 顯存的百分比。 · 日志中先后顯示 4.5%
和 7.2%
的使用率。 · 這說明隨著生成 token 數(shù)量的增加,KV cache 會(huì)逐漸占用更多的 GPU 顯存,反映了生成過程動(dòng)態(tài)累積緩存的結(jié)果。 · KV cache 的設(shè)計(jì)目的是為避免重復(fù)計(jì)算,同時(shí)支持更高的并發(fā)和長(zhǎng)序列生成,因此其內(nèi)存占用會(huì)隨著生成任務(wù)的 token 數(shù)增加而逐步上升。 · 用 Python 腳本測(cè)試 DeepSeek API from openai import OpenAI openai_api_key = 'ds-key-001' #填寫前文啟動(dòng)DeepSeek推理服務(wù)時(shí)設(shè)置的API秘鑰 openai_api_base = 'http://localhost:6006/v1' model_name= 'bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF' client = OpenAI( api_key=openai_api_key, base_url=openai_api_base, ) prompt= ''' 問題: 玄武門之變結(jié)束的當(dāng)天,李世民在深夜寫下一段獨(dú)白,你覺得他會(huì)寫什么? 要求: 先思考,然后按照以下格式回答用戶的問題: <think>推理內(nèi)容</think> 內(nèi)容 ''' chat_response = client.chat.completions.create( model=model_name, messages=[ { 'role' : 'user' , 'content' : prompt}, ], temperature= 0.6 ) print ( 'Chat response:' , chat_response)
Python腳本測(cè)試DeepSeek API的輸出結(jié)果如下:
<think> 好,我需要幫用戶想一下李世民在玄武門之變結(jié)束當(dāng)天深夜寫下的獨(dú)白。首先,我要了解玄武門之變的背景。這場(chǎng)變故發(fā)生在626年,李世民為了爭(zhēng)奪皇位,發(fā)動(dòng)了政變,殺死了自己的兄弟李建成和李元吉。 李世民當(dāng)時(shí)的心理應(yīng)該是復(fù)雜的。一方面,他成功地鞏固了自己的地位,成為太子,為后來(lái)的皇帝鋪平了道路。另一方面,他也背負(fù)了兄弟相殘的罪名,內(nèi)心一定有很多掙扎和反思。 所以,他的獨(dú)白可能會(huì)反映出他的復(fù)雜情緒。他可能會(huì)表達(dá)對(duì)權(quán)力的渴望,同時(shí)也感到內(nèi)心的壓力和不安。他可能會(huì)提到自己曾經(jīng)的猶豫,以及最終做出決定的艱難。 另外,李世民后來(lái)成為了唐太宗,開創(chuàng)了“貞觀之治”,這說明他有治國(guó)理政的雄心。因此,他的獨(dú)白中也可能流露出對(duì)未來(lái)的期望和責(zé)任感。 我還需要考慮獨(dú)白的語(yǔ)氣。他可能會(huì)用一種反思和嚴(yán)肅的口吻,既不掩飾自己的野心,也不回避內(nèi)心的矛盾。 綜合這些因素,我可以構(gòu)思一段獨(dú)白,既展現(xiàn)他的決心,也反映他的內(nèi)心掙扎,同時(shí)為未來(lái)的統(tǒng)治埋下伏筆。 最后,我需要確保這段獨(dú)白符合歷史背景和人物性格,讓讀者能夠感受到李世民當(dāng)時(shí)的復(fù)雜心境。 </think> ## 《權(quán)力的代價(jià)》 寒風(fēng)刺骨,我獨(dú)自站在玄武門城樓上,看著地上斑駁的血跡。遠(yuǎn)處的宮燈明明滅滅,像是無(wú)數(shù)雙眼睛在注視著這個(gè)改變命運(yùn)的夜晚。 長(zhǎng)嘆息一聲,我點(diǎn)燃了桌上的蠟燭。火苗在黑暗中搖曳,將我的影子投射在墻上,那影子比往日還要高大幾分。 '權(quán)力...終究是要用鮮血來(lái)澆灌的。'我喃喃自語(yǔ),指尖無(wú)意識(shí)地摩挲著腰間的佩劍。劍鞘上還殘留著清晨的血跡,那是我親手抹去的。 腦海中又浮現(xiàn)出那個(gè)場(chǎng)景:大哥李建成端著酒杯,臉上帶著一貫的溫和笑容;四弟李元吉在一旁促狹地笑著,攛掇大哥多喝幾杯。我看著他們,突然覺得這兄弟情義太過虛偽可笑。 '你們以為我愿意這樣嗎?'我握緊了拳頭,指甲深深陷入掌心。記得當(dāng)年在東宮,我夜以繼日地讀書,謀劃著如何治理國(guó)家,如何讓百姓安居樂業(yè)??伤麄?,卻只顧著爭(zhēng)權(quán)奪利,甚至想要取我性命。 燭光下,我的影子忽明忽暗。我閉上眼睛,仿佛又回到了那個(gè)雨夜。雨聲中,我聽到大哥在后院與人密謀,要如何除掉我這個(gè)眼中釘。那一刻,我握緊了刀柄,渾身的血液仿佛都凝固了。 '對(duì)不起,大哥。'我低聲說著,淚水在眼眶中打轉(zhuǎn)??赊D(zhuǎn)念一想,若我不先動(dòng)手,今日的我早已是刀下之鬼。這天下,終究是要由有能力的人來(lái)治理。 桌上的茶已經(jīng)涼了,我端起來(lái)一飲而盡??酀奈兜涝诳谥新?,像是這權(quán)力帶來(lái)的所有辛酸。遠(yuǎn)處傳來(lái)更夫的梆聲,新的一天即將開始。 我站起身,拍了拍衣襟上的塵土。既然已經(jīng)踏上了這條路,就再無(wú)回頭的余地。我李世民,定不會(huì)辜負(fù)這大好河山,也定會(huì)讓大唐盛世重現(xiàn)人間。
三、部署知識(shí)庫(kù)應(yīng)用 1、開放DeepSeek推理服務(wù)接口 一般情況下,LLM大模型推理服務(wù)與應(yīng)用服務(wù)不會(huì)部署在同一臺(tái)服務(wù)器上。
由于知識(shí)庫(kù)應(yīng)用服務(wù)器會(huì)調(diào)用DeepSeek推理服務(wù),因此需要將DeepSeek推理服務(wù)接口開放出來(lái)。
通過終端登錄知識(shí)庫(kù)應(yīng)用服務(wù)器,執(zhí)行以下命令后回車(注意:執(zhí)行后不要關(guān)閉該終端窗口):
$ ssh -CNg -L 6006:127.0.0.1:6006 root@[DeepSeek服務(wù)器地址] -p [DeepSeek服務(wù)器端口號(hào)]
如詢問yes/no請(qǐng)回答yes,并輸入ssh服務(wù)的密碼。
輸入密碼回車后無(wú)任何其他輸出則為正常,如顯示Permission denied則可能密碼粘貼失敗,請(qǐng)手動(dòng)輸入密碼 (Win10終端易出現(xiàn)無(wú)法粘貼密碼問題)
該命令用于建立SSH 隧道實(shí)現(xiàn)帶端口轉(zhuǎn)發(fā)的 SSH 連接,這樣可以通過知識(shí)庫(kù)應(yīng)用服務(wù)器上的本地端口( localhost:6006 )訪問DeepSeek推理服務(wù)器上的API接口。
這通常用于保護(hù)對(duì)DeepSeek服務(wù)器上運(yùn)行的推理服務(wù)的訪問,或訪問那些無(wú)法直接從互聯(lián)網(wǎng)訪問的DeepSeek服務(wù)器。
為了測(cè)試DeepSeek推理服務(wù)接口是否成功開放,請(qǐng)?jiān)谥R(shí)庫(kù)應(yīng)用服務(wù)器上打開瀏覽器,訪問 http://localhost:6006/docs ,查看是否成功顯示如前文所述的DeepSeek接口頁(yè)面。
如在本地電腦上遠(yuǎn)程訪問知識(shí)庫(kù)應(yīng)用服務(wù)器驗(yàn)證DeepSeek推理服務(wù)的的話,需要通過以下命令打開知識(shí)庫(kù)應(yīng)用服務(wù)器的防火墻端口。
$ sudo ufw allow 6006/tcp
2、部署知識(shí)庫(kù)應(yīng)用 前文完成DeepSeek推理服務(wù)的部署后,下一步就是部署和運(yùn)行LLM應(yīng)用——知識(shí)庫(kù)。
知識(shí)庫(kù)應(yīng)用服務(wù)器配置要求:
· 操作系統(tǒng):Ubuntu 22.04 / CentOS 7.6 64 位系統(tǒng) 執(zhí)行以下命令通過Docker方式在線安裝 MaxKB [8] 知識(shí)庫(kù)應(yīng)用。
$ docker run -d --name=maxkb --restart=always -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data -v ~/.python-packages:/opt/maxkb/app/sandbox/python-packages registry.fit2cloud.com/maxkb/maxkb
待所有容器狀態(tài)顯示為healthy后,可通過瀏覽器訪問知識(shí)庫(kù)。
打開瀏覽器,輸入以下地址:
http://[知識(shí)庫(kù)應(yīng)用服務(wù)器地址]:8080
默認(rèn)登錄信息
如在本地電腦上遠(yuǎn)程訪問知識(shí)庫(kù)應(yīng)用服務(wù)器的話,需要通過以下命令打開知識(shí)庫(kù)應(yīng)用服務(wù)器的防火墻端口。
$ sudo ufw allow 8080/tcp
知識(shí)庫(kù)成功部署后,能夠打開以下登錄頁(yè)面。
知識(shí)庫(kù)登錄頁(yè)面 3、知識(shí)庫(kù)應(yīng)用對(duì)接DeepSeek模型 知識(shí)庫(kù)應(yīng)用的使用操作流程一般可分為四步:添加模型、創(chuàng)建知識(shí)庫(kù)、創(chuàng)建應(yīng)用、發(fā)布應(yīng)用。
在高級(jí)編排應(yīng)用中還可以通過函數(shù)庫(kù)的功能,實(shí)現(xiàn)數(shù)據(jù)處理、邏輯判斷、信息提取等功能,提供更加強(qiáng)大、靈活的能力。
知識(shí)庫(kù)操作流程 模型管理用于對(duì)接供應(yīng)商的大語(yǔ)言模型,支持對(duì)接主流的大模型,包括本地私有大模型(DeepSeek / Llama 等)。
除了DeepSeek等文本生成模型外,還支持向量模型、重排、語(yǔ)音識(shí)別、語(yǔ)音合成、視覺模型、圖片生成等模型。
登錄 MaxKB 系統(tǒng)后,在供應(yīng)商列表中選擇vLLM,然后點(diǎn)擊【添加模型】,進(jìn)入模型配置表單配置參數(shù)如下:
· 權(quán)限:分為私有和公用兩種權(quán)限,私有模型僅當(dāng)前用戶可用,公用模型即系統(tǒng)內(nèi)所有用戶均可使用,但其它用戶不能編輯。 · 基礎(chǔ)模型:輸入前文中部署的DeepSeek地址。 · API Key:輸入前文啟動(dòng)DeepSeek推理服務(wù)時(shí)所設(shè)置的API Key。 如下圖所示,將前述DeepSeek大語(yǔ)言模型配置到知識(shí)庫(kù)應(yīng)用中。
接入DeepSeek模型 如前文所述,由于DeepSeek的官方模型庫(kù)的一個(gè)bug,需要通過修改DeepSeek的分詞器配置文件予以解決。
這種解決bug的workaround方式,需要在提示詞中顯式增加 <think></think>
標(biāo)簽,才能啟動(dòng)DeepSeek模型的推理Reasoning能力。
提示詞增加think標(biāo)簽 4、低代碼可視化流程編排 點(diǎn)擊【創(chuàng)建應(yīng)用】,輸入應(yīng)用名稱,選擇【高級(jí)編排】,點(diǎn)擊【創(chuàng)建】,進(jìn)入工作流編排頁(yè)面。
工作流默認(rèn)樣例 每個(gè)工作流都有基本信息與開始兩個(gè)基礎(chǔ)節(jié)點(diǎn):
· 基本信息:應(yīng)用的基本信息設(shè)置節(jié)點(diǎn),如應(yīng)用名稱、描述、開場(chǎng)白等設(shè)置,每個(gè)應(yīng)用只有一個(gè)基本信息節(jié)點(diǎn),不能刪除和復(fù)制。 · 開始節(jié)點(diǎn):工作流程的開始,每個(gè)應(yīng)用只能有一個(gè)開始節(jié)點(diǎn),不能刪除和復(fù)制。 編排工作流 點(diǎn)擊右上角的【添加組件】,可以點(diǎn)擊或拖拽到畫布進(jìn)行工作流編排。以下是每個(gè)組件的用途說明:
· AI對(duì)話:與AI大模型進(jìn)行對(duì)話節(jié)點(diǎn)。 · 圖片理解:識(shí)別并理解圖片所包含的信息。 · 圖片生成:根據(jù)提供的文本內(nèi)容生成圖片。 · 知識(shí)庫(kù)檢索:關(guān)聯(lián)知識(shí)庫(kù),檢索與問題相關(guān)分段的節(jié)點(diǎn)。 · 多路召回:使用重排模型隊(duì)多個(gè)知識(shí)庫(kù)的檢索結(jié)果進(jìn)行二次召回。 · 判斷器:根據(jù)不同條件執(zhí)行不同的節(jié)點(diǎn)。 · 指定回復(fù):直接指定回復(fù)內(nèi)容。 · 表單收集:通過表單的方式收集問答所需要的必要信息。 · 問題優(yōu)化:AI對(duì)話的一種,設(shè)定了默認(rèn)的角色和提示詞,根據(jù)上下文優(yōu)化問題。 · 文檔內(nèi)容提?。禾崛∥臋n中的內(nèi)容。 · 語(yǔ)音轉(zhuǎn)文本:將音頻轉(zhuǎn)換為文本。 · 文本轉(zhuǎn)語(yǔ)音:將文本轉(zhuǎn)換為語(yǔ)音。 文檔上傳 :支持在對(duì)話時(shí)上傳文檔、圖片以及音頻文件,并在后續(xù)節(jié)點(diǎn)中可以對(duì)上傳后的文件進(jìn)行解析。
文檔上傳節(jié)點(diǎn) 圖片理解 :對(duì)用戶上傳的圖片文件進(jìn)行分析和理解。
圖片理解節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 角色設(shè)定:回答的角色或身份設(shè)定。 · 提示詞:引導(dǎo)模型生成特定輸出的詳細(xì)描述。 · 選擇圖片:待理解和分析的圖片,默認(rèn)為當(dāng)前用戶上傳的圖片文件。 · 返回內(nèi)容:是否在對(duì)話中顯示該節(jié)點(diǎn)返回的內(nèi)容。 參數(shù)輸出:
· AI回答內(nèi)容{answer}:根據(jù)上傳的圖片以及角色、提示詞等信息圖片理解模型返回的內(nèi)容。 圖片生成 :根據(jù)文本描述生成對(duì)應(yīng)的圖片。
圖片生成節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 提示詞(正向):引導(dǎo)模型生成積極、建設(shè)性輸出的文字輸入。 · 提示詞(負(fù)向):不應(yīng)該包含在生成輸出中的元素、主題或特征的描述。 · 返回內(nèi)容:是否在對(duì)話中顯示該節(jié)點(diǎn)返回的內(nèi)容。 參數(shù)輸出:
· AI回答內(nèi)容 {answer}:即圖片生成模型根據(jù)文本輸入生成的圖片。 · 圖片 {image}: 生成圖片的詳細(xì)信息。 知識(shí)庫(kù)檢索 :如果應(yīng)用需要關(guān)聯(lián)知識(shí)庫(kù),則需要在編排中添加知識(shí)庫(kù)檢索節(jié)點(diǎn),選擇知識(shí)庫(kù)、設(shè)置檢索參數(shù)、選擇檢索的問題。
知識(shí)庫(kù)檢索節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 知識(shí)庫(kù):待檢索的知識(shí)庫(kù)。 · 檢索參數(shù):包括檢索模式、相似度閾值、引用分段數(shù)量以及最大引用字符數(shù)。 · 檢索問題:一般是開始節(jié)點(diǎn)的用戶問題。 參數(shù)輸出:
· 檢索結(jié)果的分段列表 {paragraph_list}:數(shù)組類型,指根據(jù)檢索問題、檢索參數(shù)進(jìn)行檢索后命中的分段列表,包含了分段的所有屬性; · 滿足直接回答的分段列表 {is_hit_handling_method_list}:數(shù)組類型,指根據(jù)檢索問題、檢索參數(shù)進(jìn)行檢索后命中的分段中滿足直接回答的所有分段列表,包含了分段的所有屬性; · 檢索結(jié)果 {data}:字符串類型,指根據(jù)檢索問題、檢索參數(shù)進(jìn)行檢索后命中的分段內(nèi)容; · 滿足直接回答的分段內(nèi)容 {directly_return}:字符串類型,指根據(jù)檢索問題、檢索參數(shù)進(jìn)行檢索后命中的分段中滿足直接回答的所有分段內(nèi)容。 多路召回 :根據(jù)需要重排的內(nèi)容、檢索問題以及檢索參數(shù)進(jìn)行多路召回。
多路召回節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 重排內(nèi)容:待重排的多個(gè)內(nèi)容,一般是多個(gè)不同知識(shí)庫(kù)的檢索結(jié)果。 · 檢索參數(shù):包括 score 閾值、引用分段數(shù)以及最大引用字符數(shù)。 · 檢索問題:根據(jù)檢索問題進(jìn)行重排,一般為用戶問題或問題優(yōu)化后的結(jié)果。 參數(shù)輸出:
· 重排結(jié)果列表 {result_list}:數(shù)組類型,指根據(jù)重排后的結(jié)果列表。 · 重排結(jié)果 {result}:字符串類型,指根據(jù)檢索參數(shù)后的重排結(jié)果。 判斷器 :根據(jù)不同的條件進(jìn)行邏輯判斷,每個(gè)判斷分支后面必須有后置執(zhí)行節(jié)點(diǎn)。
判斷器 輸出參數(shù)說明:
· 分支名稱{branch_name}:每個(gè)判斷分支的名稱。 指定回復(fù) :指定輸出文本內(nèi)容,在知識(shí)庫(kù)查詢到的相關(guān)內(nèi)容滿足直接回答的要求,可以輸出檢索內(nèi)容,也可以在知識(shí)庫(kù)沒有查詢到關(guān)聯(lián)內(nèi)容時(shí),指定回復(fù)內(nèi)容。
指定回復(fù) 輸出參數(shù)說明:
· 內(nèi)容{answer}: 指定回復(fù)輸出的內(nèi)容。 表單收集 :通過表單的設(shè)計(jì),以引導(dǎo)的方式主動(dòng)獲取必要的信息,一般應(yīng)用于需要多次詢問的應(yīng)答場(chǎng)景。
表單收集節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 表單輸出內(nèi)容:表單提示說明以及表單內(nèi)容,可以單項(xiàng)輸入,也可以輸入多項(xiàng)信息。 · 表單配置:通過添加不同的組件進(jìn)行表單的設(shè)計(jì)。 參數(shù)輸出:
· 表單全部?jī)?nèi)容{form_data}:表單的全部?jī)?nèi)容。 · 表單全部?jī)?nèi)容將作為固定的輸出,對(duì)于各個(gè)表單項(xiàng)也都進(jìn)行參數(shù)化輸出。 問題優(yōu)化 :根據(jù)當(dāng)前會(huì)話的歷史聊天記錄,以及在節(jié)點(diǎn)設(shè)置的大預(yù)言模型和提示詞,對(duì)當(dāng)前問題進(jìn)行智能優(yōu)化。
問題優(yōu)化節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· AI 模型:大語(yǔ)言模型的名稱以及參數(shù)控制。 · 角色設(shè)定:大語(yǔ)言模型回答的角色或身份設(shè)定。 · 提示詞:引導(dǎo)模型生成特定輸出的詳細(xì)描述。 · 歷史聊天記錄:在當(dāng)前對(duì)話中有關(guān)聯(lián)的歷史會(huì)話內(nèi)容。例如,歷史聊天記錄為1,表示當(dāng)前問題以及上一次的對(duì)話內(nèi)容一起輸送給大模型。 · 返回內(nèi)容:是否在對(duì)話中顯示該節(jié)點(diǎn)返回的內(nèi)容。。 參數(shù)輸出:
· 問題優(yōu)化結(jié)果 {answer}:通過大模型優(yōu)化后的問題。 文檔內(nèi)容提取 :對(duì)用戶上傳的文檔進(jìn)行內(nèi)容總結(jié)。
文檔內(nèi)容提取節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 選擇文檔:即用戶上傳的文檔,需要在基本信息節(jié)點(diǎn)開啟對(duì)文件上傳的支持。 參數(shù)輸出:
· 文檔輸出 {content}:對(duì)用戶上傳文件進(jìn)行的總結(jié)輸出。 語(yǔ)音轉(zhuǎn)文本 :將音頻文件轉(zhuǎn)換為文本。
語(yǔ)音轉(zhuǎn)文本節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 語(yǔ)音識(shí)別模型:選擇語(yǔ)音識(shí)別模型的名稱。 · 語(yǔ)音文件:即上傳的音頻文件,支持的格式包括:mp3、wav、ogg、acc。 · 返回內(nèi)容:是否在對(duì)話中顯示該節(jié)點(diǎn)返回的內(nèi)容。 參數(shù)輸出:
· 結(jié)果 {result}:語(yǔ)音轉(zhuǎn)換后的文本內(nèi)容。 文本轉(zhuǎn)語(yǔ)音 :將文本轉(zhuǎn)換為音頻。
文本轉(zhuǎn)語(yǔ)音節(jié)點(diǎn) 節(jié)點(diǎn)設(shè)置:
· 語(yǔ)音合成模型:選擇可用語(yǔ)音合成模型的名稱。 · 文本內(nèi)容:選擇待合成的文本內(nèi)容。 · 返回內(nèi)容:是否在對(duì)話中顯示該節(jié)點(diǎn)返回的內(nèi)容。 參數(shù)輸出:
· 結(jié)果 {result}:將文本轉(zhuǎn)成的音頻內(nèi)容。 添加函數(shù) :在高級(jí)編排流程中,可以添加函數(shù)庫(kù)函數(shù)作為流程中的一個(gè)處理節(jié)點(diǎn),以靈活處理復(fù)雜需求。
添加函數(shù) · 節(jié)點(diǎn)設(shè)置:即函數(shù)的輸入?yún)?shù)。 · 參數(shù)輸出:即函數(shù)的返回結(jié)果。 添加應(yīng)用 :在高級(jí)編排流程中,可以添加其它應(yīng)用(簡(jiǎn)單配置應(yīng)用和流程編排應(yīng)用)作為流程中的一個(gè)處理節(jié)點(diǎn),直接快速利用子應(yīng)用的問答結(jié)果。
添加應(yīng)用 節(jié)點(diǎn)設(shè)置:
· 用戶問題:對(duì)子應(yīng)用的提問信息。 · 返回內(nèi)容:開啟后在對(duì)話過程中將子應(yīng)用的返回結(jié)果。 參數(shù)輸出:
· 結(jié)果:即子應(yīng)用的返回結(jié)果。 執(zhí)行條件 :工作流中支持多出多進(jìn),在這個(gè)情況下,匯集節(jié)點(diǎn)可以根據(jù)與前置節(jié)點(diǎn)的邏輯關(guān)系,選擇執(zhí)行條件。
執(zhí)行條件 · ALL:需要等所有前置連線節(jié)點(diǎn)全部執(zhí)行完成后,才可執(zhí)行當(dāng)前節(jié)點(diǎn)。 · ANY:任一前置連線節(jié)點(diǎn)執(zhí)行完成后,即可執(zhí)行當(dāng)前節(jié)點(diǎn)。 調(diào)試預(yù)覽 :完成所有的編排設(shè)計(jì)后,可點(diǎn)擊【調(diào)試】后,先校驗(yàn)流程是否合規(guī),校驗(yàn)通過后可在當(dāng)前頁(yè)面進(jìn)行對(duì)話測(cè)試。在調(diào)試對(duì)話框中進(jìn)行提問,AI回答完成后,會(huì)顯示【執(zhí)行詳情】,點(diǎn)擊【執(zhí)行詳情】后,在彈出執(zhí)行詳情對(duì)話框中可以查看每個(gè)流程節(jié)點(diǎn)的執(zhí)行狀態(tài)、耗時(shí)以及其它執(zhí)行信息。
調(diào)試預(yù)覽 應(yīng)用接入 :知識(shí)庫(kù)支持創(chuàng)建的應(yīng)用的與企業(yè)微信應(yīng)用、企業(yè)微信客服、公眾號(hào)(服務(wù)號(hào)和訂閱號(hào))、釘釘應(yīng)用、飛書應(yīng)用接入,實(shí)現(xiàn)企業(yè)內(nèi)部員工、外部公眾進(jìn)行對(duì)話。
配置企業(yè)微信應(yīng)用 企業(yè)微信機(jī)器人 接入微信客服 釘釘機(jī)器人 配置飛書機(jī)器人 飛書機(jī)器人 四、知識(shí)庫(kù)核心業(yè)務(wù)邏輯 知識(shí)庫(kù)通過模塊化的設(shè)計(jì),將知識(shí)召回、對(duì)話交互、圖像處理等多個(gè)核心功能拆分為獨(dú)立的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都有清晰的業(yè)務(wù)邏輯與上下文管理。前端則通過 LogicFlow 實(shí)現(xiàn)圖形化配置與實(shí)時(shí)交互,而后端則依賴 Django、LangChain 與 PG Vector 等組件保證高效的數(shù)據(jù)檢索與 LLM 推理服務(wù)接口。整個(gè)系統(tǒng)為用戶提供了一個(gè)靈活、可擴(kuò)展的知識(shí)問答平臺(tái),能夠快速整合多種數(shù)據(jù)與模型服務(wù),響應(yīng)用戶提出的各類查詢問題。
下面給出一個(gè)對(duì)該知識(shí)庫(kù)的核心業(yè)務(wù)邏輯的概述,以便快速理解整體架構(gòu)和主要功能模塊:
1、整體架構(gòu) 知識(shí)庫(kù)整合了以下核心技術(shù)和模塊:
· 前端 :基于 Vue.js 和 LogicFlow 的工作流編輯器。用戶可以在圖形化界面中通過拖拽方式配置工作流程,比如設(shè)置“開始節(jié)點(diǎn)”、“問答節(jié)點(diǎn)”、“搜索節(jié)點(diǎn)”等,從而構(gòu)建不同的使用場(chǎng)景。 · 后端 :使用 Django 作為 Web 框架,通過 Python 實(shí)現(xiàn)后端服務(wù)。利用 LangChain 框架對(duì)接大語(yǔ)言模型(LLM)的推理服務(wù),支持流式和非流式輸出。 · 數(shù)據(jù)處理 :使用 PostgreSQL 作為數(shù)據(jù)庫(kù),并借助 PG Vector 插件實(shí)現(xiàn)文檔向量化存儲(chǔ)與相似度搜索,為知識(shí)召回、語(yǔ)義匹配等提供支持。 · 模型服務(wù) :構(gòu)建了對(duì)接 LLM 推理服務(wù)的各個(gè)模塊,包括直接調(diào)用 LLM 模型生成回答、對(duì)搜索結(jié)果進(jìn)行重新排序(reranker)、圖像生成與理解等業(yè)務(wù)邏輯。各個(gè)節(jié)點(diǎn)模塊之間通過共享上下文數(shù)據(jù),實(shí)現(xiàn)了整個(gè)工作流的銜接。 知識(shí)庫(kù)應(yīng)用代碼庫(kù)地址:https://github.com/1Panel-dev/MaxKB
以下是知識(shí)庫(kù)應(yīng)用Django后端代碼結(jié)構(gòu)。
root ├── apps # Django后端代碼根目錄 │ ├── application # 主要應(yīng)用模塊 │ │ ├── flow # 工作流引擎相關(guān)模塊 │ │ │ ├── step_node # 工作流節(jié)點(diǎn)定義目錄 │ │ │ │ ├── ai_chat_step_node # AI 對(duì)話節(jié)點(diǎn)相關(guān)代碼 (例如: base_chat_node.py) │ │ │ │ │ └── impl # AI 對(duì)話節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_chat_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── application_node # 應(yīng)用節(jié)點(diǎn)相關(guān)代碼 (例如: base_application_node.py) │ │ │ │ │ └── impl # 應(yīng)用節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_application_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── image_generate_step_node # 圖像生成節(jié)點(diǎn)相關(guān)代碼 (例如: base_image_generate_node.py) │ │ │ │ │ └── impl # 圖像生成節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_image_generate_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── image_understand_step_node # 圖像理解節(jié)點(diǎn)相關(guān)代碼 (例如: base_image_understand_node.py) │ │ │ │ │ └── impl # 圖像理解節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_image_understand_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── question_node # 問題節(jié)點(diǎn)/通用對(duì)話節(jié)點(diǎn)相關(guān)代碼 (例如: base_question_node.py) │ │ │ │ │ └── impl # 問題節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_question_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── reranker_node # 重排序節(jié)點(diǎn)相關(guān)代碼 (例如: base_reranker_node.py) │ │ │ │ │ └── impl # 重排序節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_reranker_node.py 的具體實(shí)現(xiàn)) │ │ │ │ ├── search_dataset_node # 知識(shí)庫(kù)搜索節(jié)點(diǎn)相關(guān)代碼 (例如: base_search_dataset_node.py) │ │ │ │ │ └── impl # 知識(shí)庫(kù)搜索節(jié)點(diǎn)實(shí)現(xiàn) (例如: base_search_dataset_node.py 的具體實(shí)現(xiàn)) │ │ │ │ └── i_step_node.py # 工作流節(jié)點(diǎn)接口定義 (例如: INode 接口) │ │ │ ├── impl # 工作流引擎核心實(shí)現(xiàn) │ │ │ │ └── workflow_manage.py # 工作流管理類 (WorkflowManage) │ │ │ ├── tools.py # 工作流工具類 (例如: Reasoning, 流式響應(yīng)工具) │ │ │ └── default_workflow.json # 默認(rèn)工作流配置示例 │ │ ├── tools.py # 應(yīng)用級(jí)別的工具模塊 │ │ └── flow.py # 工作流定義或相關(guān)類 │ ├── common # 通用模塊 │ │ ├── config # 通用配置 (例如: embedding_config.py 向量配置) │ │ ├── db # 數(shù)據(jù)庫(kù)相關(guān)模塊 │ │ │ └── search.py # 數(shù)據(jù)庫(kù)搜索相關(guān)功能 (例如: native_search) │ │ ├── response # 通用響應(yīng)處理 (例如: result 函數(shù)) │ │ │ └── base_response.py # 基礎(chǔ)響應(yīng)類定義 │ │ ├── util # 通用工具函數(shù) │ │ │ ├── common.py # 常用工具函數(shù) (例如: bytes_to_uploaded_file) │ │ │ └── file_util.py # 文件操作工具 (例如: get_file_content) │ │ └── response.py # 響應(yīng)處理相關(guān) │ ├── dataset # 數(shù)據(jù)集/知識(shí)庫(kù)相關(guān)模塊 │ │ ├── models.py # 數(shù)據(jù)集模型定義 (例如: Document, Paragraph, DataSet, File) │ │ └── serializers # 數(shù)據(jù)集序列化器 (例如: file_serializers.py FileSerializer) │ │ └── file_serializers.py │ ├── embedding # 向量嵌入相關(guān)模塊 │ │ └── models.py # 嵌入模型相關(guān)定義 (例如: SearchMode) │ ├── setting # 系統(tǒng)設(shè)置/模型設(shè)置模塊 │ │ ├── models.py # 設(shè)置相關(guān)模型 (例如: Model, ModelCredential) │ │ └── models_provider # 模型提供者相關(guān) │ │ └── tools.py # 模型提供工具函數(shù) (例如: get_model_instance_by_model_user_id, get_model_credential) │ └── smartdoc # 項(xiàng)目根目錄或智能文檔相關(guān)模塊 │ └── conf # 項(xiàng)目配置 │ └── __init__.py └── manage.py # Django 項(xiàng)目管理腳本
以下是知識(shí)庫(kù)應(yīng)用Vue前端代碼結(jié)構(gòu)。
ui/src # Vue前端代碼根目錄 ├── assets # 靜態(tài)資源目錄 │ ├── images # 圖片資源 │ └── styles # 全局樣式文件 (如 CSS, SCSS) ├── components # 通用組件目錄 │ ├── Common # 通用UI組件 (例如按鈕,對(duì)話框,表格等) │ ├── Specific # 特定業(yè)務(wù)場(chǎng)景組件 (例如工作流節(jié)點(diǎn)組件,圖表組件) ├── layouts # 布局組件目錄 (例如頭部,側(cè)邊欄,頁(yè)腳等) ├── views # 視圖頁(yè)面目錄 (每個(gè)頁(yè)面通常對(duì)應(yīng)一個(gè)路由) │ ├── Home.vue # 首頁(yè)視圖 │ ├── Workflow.vue # 工作流管理視圖 │ ├── Dataset.vue # 數(shù)據(jù)集管理視圖 │ └── ... # 其他業(yè)務(wù)視圖頁(yè)面 ├── router # 路由配置目錄 │ └── index.js # 路由配置文件 ├── store # Vuex 狀態(tài)管理目錄 (如果項(xiàng)目使用了 Vuex) │ ├── modules # 模塊化的狀態(tài)管理 │ │ ├── user.js # 用戶狀態(tài)管理模塊 │ │ └── app.js # 應(yīng)用全局狀態(tài)管理模塊 │ └── index.js # Vuex store 入口文件 ├── utils # 工具函數(shù)庫(kù)目錄 │ ├── request.js # HTTP 請(qǐng)求封裝 │ ├── helpers.js # 通用輔助函數(shù) │ └── ... # 其他工具函數(shù) ├── App.vue # 根組件 ├── main.js # 入口文件,Vue 應(yīng)用初始化 └── index.html # HTML 模板文件
2、前端工作流編輯與展示 · LogicFlow 與 Vue.js 前端基于 Vue 組件構(gòu)建,利用 LogicFlow 實(shí)現(xiàn)工作流圖形展示與操作。開發(fā)者可以在頁(yè)面上構(gòu)建一個(gè)包含多個(gè)節(jié)點(diǎn)的流程圖,每個(gè)節(jié)點(diǎn)對(duì)應(yīng)后端中不同的業(yè)務(wù)處理邏輯。例如: · “開始節(jié)點(diǎn)”:收集用戶輸入(提問、時(shí)間、全局信息等)。 · “AI Chat 節(jié)點(diǎn)”:調(diào)用 LLM 模型進(jìn)行回答生成。 · “搜索數(shù)據(jù)集節(jié)點(diǎn)”:根據(jù)用戶問題,利用向量匹配技術(shù)檢索相關(guān)文檔。 · 實(shí)時(shí)反饋與交互 前端利用 LogicFlow 提供的拖拽、縮放等功能,讓用戶可以直觀地配置工作流,同時(shí)也支持響應(yīng)式展示大模型返回的流式回答內(nèi)容。 3、后端工作流節(jié)點(diǎn)與業(yè)務(wù)邏輯 后端主要采用“節(jié)點(diǎn)化”的工作流架構(gòu),每個(gè)節(jié)點(diǎn)對(duì)應(yīng)一段業(yè)務(wù)邏輯,常見的節(jié)點(diǎn)類型包括:
· 搜索數(shù)據(jù)集節(jié)點(diǎn) 在 BaseSearchDatasetNode
中,邏輯主要包括: · 根據(jù)用戶問題,獲取相應(yīng)知識(shí)庫(kù)的嵌入模型 ID。 · 調(diào)用嵌入模型將問題轉(zhuǎn)為向量,并用 PG Vector 實(shí)現(xiàn)向量查詢,檢索與問題語(yǔ)義最相近的文檔段落。 · 對(duì)檢索結(jié)果進(jìn)行過濾與排序,然后返回給下游節(jié)點(diǎn)使用。 · 問答節(jié)點(diǎn) / AI Chat 節(jié)點(diǎn) 在 BaseChatNode
和 BaseQuestionNode
中: · 先從節(jié)點(diǎn)上下文中獲取歷史對(duì)話記錄,以及當(dāng)前問題。 · 調(diào)用 LangChain 封裝的 LLM 模型,通過 invoke
或 stream
方法得到模型回答。 · 回答過程中支持流式輸出,通過分塊拼接內(nèi)容,并對(duì)答案進(jìn)行 token 計(jì)數(shù)、上下文保存等操作。 · 每個(gè)節(jié)點(diǎn)還實(shí)現(xiàn)了 save_context
方法,將節(jié)點(diǎn)執(zhí)行信息(如回答、耗時(shí)、 token 數(shù)量)保存到上下文中,方便后續(xù)結(jié)果組裝與調(diào)試。 · 重新排序節(jié)點(diǎn) (Reranker) 在 BaseRerankerNode
中: · 將檢索出的候選文檔利用一個(gè)重排模型(如 SiliconCloud 或本地重排模型)進(jìn)行壓縮與重新排序,提高最終答案的相關(guān)性。 · 返回的結(jié)果通常經(jīng)過進(jìn)一步聚合,形成最終的答案或文檔摘要。 · 圖像生成與理解節(jié)點(diǎn) 例如在 BaseImageGenerateNode
與 BaseImageUnderstandNode
中: · 根據(jù)用戶描述調(diào)用相應(yīng)模型生成圖像,或?qū)ι蟼鞯膱D像進(jìn)行理解處理。 · 生成的圖像會(huì)經(jīng)過文件處理,上傳后返回 URL,供前端展示。 · 應(yīng)用節(jié)點(diǎn) 應(yīng)用節(jié)點(diǎn)(Application Node)將前面各個(gè)節(jié)點(diǎn)的處理結(jié)果進(jìn)行整合,最終生成整體回答。它不僅保存了回答文本,還匯總了各個(gè)節(jié)點(diǎn)的詳細(xì)信息、token 使用情況、上下文數(shù)據(jù)等。 · 工作流整體管理 工作流各節(jié)點(diǎn)之間通過上下文數(shù)據(jù)(例如 node_chunk
、 workflow_manage
等)共享信息。整體流程從用戶輸入開始,依次經(jīng)過各個(gè)節(jié)點(diǎn)處理,最終在返回答案同時(shí)也保存一個(gè)詳細(xì)的執(zhí)行日志,便于追蹤整個(gè)會(huì)話流程。 4、數(shù)據(jù)向量與知識(shí)庫(kù)召回 · 向量存儲(chǔ)與檢索 利用 PostgreSQL 與 PG Vector 插件,對(duì)知識(shí)庫(kù)中的文檔進(jìn)行向量化存儲(chǔ)。用戶輸入的問題首先會(huì)通過嵌入模型轉(zhuǎn)換成一個(gè)向量,再在向量庫(kù)中搜索語(yǔ)義相似的文檔。 · 嵌入模型與向量庫(kù)邏輯 在相關(guān)模塊如 pg_vector.py
、 search_dataset_node
中,可以看到: · 對(duì)文檔的嵌入進(jìn)行更新、刪除操作。 · 構(gòu)建查詢語(yǔ)句,使用向量距離作為排序依據(jù),返回最匹配的結(jié)果。 5、模型服務(wù)及對(duì)接 后端通過多種模型提供者(比如 SiliconCloud 重排模型、本地重排模型等)對(duì)接外部 LLM 推理服務(wù)。調(diào)用流程通常如下:
1. 獲取模型實(shí)例 利用 get_model_instance_by_model_user_id
根據(jù)模型 ID 和用戶信息獲取具體的模型包裝類實(shí)例。 2. 調(diào)用推理或流式 API 根據(jù)業(yè)務(wù)場(chǎng)景,調(diào)用模型實(shí)例的 invoke
(同步)或 stream
(流式)方法進(jìn)行推理,返回回答文本或分塊回答。 3. 上下文組裝與輸出 推理結(jié)果通過 _write_context
或類似方法保存,并經(jīng)過 Reasoning 類處理附加 “思考” 邏輯,最后組裝成完整回答返回給前端。 五、核心代碼解析 下面介紹該知識(shí)庫(kù)系統(tǒng)中如何利用 LangChain 框架來(lái)連接大語(yǔ)言模型(LLM)、調(diào)用輔助函數(shù)、以及基于向量數(shù)據(jù)庫(kù)的知識(shí)檢索等核心組件。
整個(gè)系統(tǒng)采用模塊化設(shè)計(jì),每個(gè)“節(jié)點(diǎn)”負(fù)責(zé)完成特定的任務(wù),節(jié)點(diǎn)內(nèi)部通過調(diào)用 get_model_instance_by_model_user_id 等工廠方法,獲取由 LangChain 封裝的模型實(shí)例,然后調(diào)用相應(yīng)的方法(如 invoke、stream、embed_query 等)實(shí)現(xiàn)推理、流式響應(yīng)以及向量搜索等操作。
下面給出幾個(gè)關(guān)鍵模塊的示例代碼及詳細(xì)說明。
1、LLM 推理模塊(基于 LangChain) 在問答和對(duì)話節(jié)點(diǎn)中,系統(tǒng)通過調(diào)用 LangChain 封裝的 LLM 模型來(lái)生成回答。核心邏輯包括:
· 利用工廠函數(shù) get_model_instance_by_model_user_id 根據(jù)模型 ID 和用戶信息獲取具體的模型實(shí)例; · 構(gòu)造系統(tǒng)提示、歷史對(duì)話消息、用戶提問等,拼裝成消息列表(消息類型使用 HumanMessage、SystemMessage 等); · 根據(jù)是否需要流式響應(yīng),調(diào)用模型的 invoke(同步)或 stream(流式)方法; · 在返回結(jié)果前調(diào)用 _write_context 將節(jié)點(diǎn)執(zhí)行過程和 token 統(tǒng)計(jì)信息寫入上下文。 下面是一個(gè)類似 BaseChatNode 節(jié)點(diǎn)中 LLM 調(diào)用的示例代碼:
def execute ( self, model_id, system, prompt, dialogue_number, history_chat_record, stream, chat_id, chat_record_id, model_params_setting= None , dialogue_type= None , model_setting= None , **kwargs ) -> NodeResult: if dialogue_type is None : dialogue_type = 'WORKFLOW' if model_params_setting is None : model_params_setting = get_default_model_params_setting(model_id) if model_setting is None : model_setting = { 'reasoning_content_enable' : False , 'reasoning_content_end' : '</think>' , 'reasoning_content_start' : '<think>' } self .context[ 'model_setting' ] = model_setting # 獲取 LLM 模型實(shí)例,底層借助 LangChain 封裝 chat_model = get_model_instance_by_model_user_id( model_id, self .flow_params_serializer.data.get( 'user_id' ), **model_params_setting) # 構(gòu)建歷史消息 history_message = self .get_history_message(history_chat_record, dialogue_number, dialogue_type, self .runtime_node_id) self .context[ 'history_message' ] = history_message # 生成當(dāng)前問題的提示信息 question = self .generate_prompt_question(prompt) self .context[ 'question' ] = question.content system = self .workflow_manage.generate_prompt(system) self .context[ 'system' ] = system # 構(gòu)造最終交互的消息列表,利用 LangChain 中的消息類型進(jìn)行封裝 message_list = self .generate_message_list(system, prompt, history_message) self .context[ 'message_list' ] = message_list if stream: response = chat_model.stream(message_list) return NodeResult({ 'result' : response, 'chat_model' : chat_model, 'message_list' : message_list, 'history_message' : history_message, 'question' : question.content }, {}, _write_context=write_context_stream) else : response = chat_model.invoke(message_list) return NodeResult({ 'result' : response, 'chat_model' : chat_model, 'message_list' : message_list, 'history_message' : history_message, 'question' : question.content }, {}, _write_context=write_context)
說明:
· get_model_instance_by_model_user_id 用于獲取具體的 LLM 模型實(shí)例,內(nèi)部可能針對(duì)不同的模型調(diào)用不同的 API; · generate_message_list 將系統(tǒng)提示、歷史信息和用戶提問結(jié)合,生成符合 LangChain 格式的消息列表; · 根據(jù) stream 參數(shù)選擇同步或流式調(diào)用,返回的 NodeResult 對(duì)象中包含后續(xù)處理需要的上下文信息。 2、向量數(shù)據(jù)庫(kù)(PG Vector)與語(yǔ)義檢索 在搜索數(shù)據(jù)集節(jié)點(diǎn)中,系統(tǒng)利用向量數(shù)據(jù)庫(kù)做知識(shí)召回。流程如下:
· 通過 get_embedding_id 確定使用哪個(gè)嵌入模型; · 通過 get_model_instance_by_model_user_id 獲取嵌入模型實(shí)例,并調(diào)用 embed_query 將自然語(yǔ)言問題轉(zhuǎn)換成向量表示; · 調(diào)用 VectorStore 中封裝好的向量檢索方法(例如 vector.query)進(jìn)行向量相似度搜索,檢索與問題語(yǔ)義相近的文檔段落。 下面是一個(gè)基于 BaseSearchDatasetNode 的示例:
def execute ( self, dataset_id_list, dataset_setting, question, exclude_paragraph_id_list= None , **kwargs ) -> NodeResult: self .context[ 'question' ] = question if len (dataset_id_list) == 0 : return get_none_result(question) # 根據(jù)知識(shí)庫(kù)列表,獲取統(tǒng)一的嵌入模型ID model_id = get_embedding_id(dataset_id_list) # 獲取嵌入模型實(shí)例,基于 LangChain 調(diào)用嵌入接口 embedding_model = get_model_instance_by_model_user_id( model_id, self .flow_params_serializer.data.get( 'user_id' )) # 將問題轉(zhuǎn)換為向量 embedding_value = embedding_model.embed_query(question) # 獲取向量數(shù)據(jù)庫(kù)實(shí)例,此處基于 PG Vector 封裝 vector = VectorStore.get_embedding_vector() exclude_document_id_list = [ str (document. id ) for document in QuerySet(Document). filter ( dataset_id__in=dataset_id_list, is_active= False )] # 調(diào)用向量檢索接口,根據(jù)向量距離返回相似候選文檔 embedding_list = vector.query( question, embedding_value, dataset_id_list, exclude_document_id_list, exclude_paragraph_id_list, True , dataset_setting.get( 'top_n' ), dataset_setting.get( 'similarity' ), SearchMode(dataset_setting.get( 'search_mode' )) ) # 手動(dòng)關(guān)閉數(shù)據(jù)庫(kù)連接 connection.close() if embedding_list is None : return get_none_result(question) paragraph_list = self .list_paragraph(embedding_list, vector) result = [ self .reset_paragraph(paragraph, embedding_list) for paragraph in paragraph_list] result = sorted (result, key= lambda p: p.get( 'similarity' ), reverse= True ) return NodeResult({ 'result' : result, 'question' : question}, {})
說明:
· 首先通過嵌入模型將問題編碼成向量,再調(diào)用 PG Vector 提供的查詢接口; · 向量檢索返回的是一系列候選段落,之后經(jīng)過過濾和排序得到最匹配的結(jié)果; · 這些匹配結(jié)果可以后續(xù)傳遞給重排節(jié)點(diǎn)或直接用于回答生成。 3、函數(shù)調(diào)用與工具集成 除了對(duì)話和知識(shí)檢索外,系統(tǒng)還支持調(diào)用其他輔助函數(shù)來(lái)實(shí)現(xiàn)例如文檔重排、圖像生成/理解等功能。以重排節(jié)點(diǎn)(reranker)為例,其主要邏輯如下:
· 整合多個(gè)節(jié)點(diǎn)輸入的內(nèi)容,通過 merge_reranker_list 合并; · 通過 get_model_instance_by_model_user_id 獲取重排模型實(shí)例; · 調(diào)用模型的 compress_documents 方法,對(duì)候選文檔進(jìn)行內(nèi)容壓縮和重新排序。 示例代碼如下:
def execute ( self, question, reranker_setting, reranker_list, reranker_model_id, **kwargs ) -> NodeResult: # 將不同來(lái)源的候選文本合并 documents = merge_reranker_list(reranker_list) top_n = reranker_setting.get( 'top_n' , 3 ) self .context[ 'document_list' ] = [ { 'page_content' : document.page_content, 'metadata' : document.metadata} for document in documents ] self .context[ 'question' ] = question # 獲取重排模型,并調(diào)用相關(guān)函數(shù)實(shí)現(xiàn)文檔壓縮 reranker_model = get_model_instance_by_model_user_id( reranker_model_id, self .flow_params_serializer.data.get( 'user_id' ), top_n=top_n) result = reranker_model.compress_documents(documents, question) similarity = reranker_setting.get( 'similarity' , 0.6 ) max_paragraph_char_number = reranker_setting.get( 'max_paragraph_char_number' , 5000 ) result = reset_result_list(result, documents) filtered_result = filter_result(result, max_paragraph_char_number, top_n, similarity) return NodeResult({ 'result_list' : filtered_result, 'result' : '' .join([item.get( 'page_content' ) for item in filtered_result]) }, {})
說明:
· merge_reranker_list 會(huì)把不同節(jié)點(diǎn)返回的候選文檔整合成統(tǒng)一的 Document 對(duì)象列表; · 重排操作通過調(diào)用模型實(shí)例中的 compress_documents 實(shí)現(xiàn),從而得到更加準(zhǔn)確和簡(jiǎn)潔的回答內(nèi)容。 總結(jié) 知識(shí)庫(kù)整個(gè)系統(tǒng)的核心邏輯在于:
1. 使用 LangChain 封裝的模型實(shí)例 通過 get_model_instance_by_model_user_id、embed_query、invoke 以及 stream 等方法,實(shí)現(xiàn) LLM 整體調(diào)用,無(wú)縫對(duì)接大語(yǔ)言模型推理服務(wù)。 2. 構(gòu)造上下文和消息列表 利用 HumanMessage、SystemMessage 等消息類型將系統(tǒng)提示、歷史對(duì)話、用戶輸入等進(jìn)行整合,作為調(diào)用 LLM 的輸入。 3. 調(diào)用向量庫(kù)進(jìn)行語(yǔ)義檢索 使用 PG Vector 對(duì)知識(shí)庫(kù)中的文檔進(jìn)行嵌入存儲(chǔ),并通過向量檢索找到與用戶問題語(yǔ)義最相關(guān)的內(nèi)容。 4. 集成其他輔助功能 例如文檔重排、圖像生成/理解等均通過各自節(jié)點(diǎn)調(diào)用相應(yīng)模型接口、工具函數(shù)完成。 這種基于節(jié)點(diǎn)化工作流的設(shè)計(jì),使得系統(tǒng)能夠靈活地將大語(yǔ)言模型、向量數(shù)據(jù)庫(kù)以及其他工具組合起來(lái),實(shí)現(xiàn)一個(gè)功能豐富、響應(yīng)迅速的知識(shí)問答平臺(tái)。
引用鏈接 [1]
Huggingface: https:///collections/deepseek-ai/deepseek-r1-678e1e131c0169c0bc89728d [2]
bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF: https:///bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF [3]
CUDA安裝教程: https://developer./cuda-downloads [4]
cuDNN安裝教程: https://developer./cudnn [5]
PyTorch: https://pytorch.org/ [6]
bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF: https:///bartowski/DeepSeek-R1-Distill-Qwen-32B-GGUF [7]
DeepSeek的Hugging Face官方模型庫(kù): https:///deepseek-ai/DeepSeek-R1-Distill-Qwen-32B [8]
MaxKB: https://github.com/1Panel-dev/MaxKB