Python使用Ollama實(shí)現(xiàn)私有大模型知識庫
在不依賴 LangChain、LlamaIndex 等框架,以及各種知識問答軟件的情況下,盡量減少第三方庫的使用,僅通過 Ollama 和 NumPy 兩個(gè)外部庫來實(shí)現(xiàn) RAG(Retrieval-Augmented Generation)應(yīng)用。
一、安裝python
下載:https://python.org/downloads/
安裝:一路下一步即可,安裝完成后運(yùn)行以下代碼,即可查看對應(yīng)版本號
python --version

二、安裝PyCharm
(推薦,也可以用vscode或windows記事本等編輯軟件)
PyCharm的優(yōu)點(diǎn):
- 自動(dòng)提示
- 創(chuàng)建項(xiàng)目時(shí)自動(dòng)創(chuàng)建python虛擬環(huán)境
- 整合本地終端(且基于python對應(yīng)本項(xiàng)目的虛擬環(huán)境)

三、安裝ollama
下載:https://ollama.com/download
安裝:一路下一步。安裝完成后用以下命令檢驗(yàn)
ollama --version

四、在ollama中安裝開源chat大模型
在ollama中安裝開源chat大模型:qwen2.5 或deepseek-r1
ollama官網(wǎng)models(https://ollama.com/search)頁面可以找到很多開源大模型,我們下載用的比較多的千問中文大模型(顯卡差的建議安裝ollama2.5:0.5b)
ollama run qwen2.5

五、在ollama中安裝開源embedding大模型
在ollama中安裝開源embedding大模型:milkey/m3e nomic-embed-text
embedding作用是將問題和知識庫文本轉(zhuǎn)換成向量,便于查詢。
原本打算使用nomic-embed-text模型,但是使用時(shí)效果不好,發(fā)現(xiàn)m3e的效果不錯(cuò),所以改用m3e
ollama run milkey/m3e


六、在項(xiàng)目python虛擬環(huán)境中安裝ollama
pip install ollama

七、安裝numpy
pip install numpy
八、編寫代碼
項(xiàng)目文件目錄結(jié)構(gòu)如下圖

1. kb.py
import numpy as np
from ollama import embeddings
class Kb:
def __init__(self, filepath):
# 讀取文件內(nèi)容
content = self.read_file(filepath)
# print(content)
# 讀取拆分好的數(shù)組
self.chunks = self.split_content(content)
# print(chunks)
# for chunk in chunks:
# print(chunk)
# print('=' * 10)
# 轉(zhuǎn)換成向量
self.embeds = self.get_embeddings(self.chunks)
# 讀取文件
def read_file(self, filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
return content
# 拆分知識庫
@staticmethod
def split_content(content):
chunks = content.split('# ')
# 過濾掉空塊
chunks = [chunk.strip() for chunk in chunks if chunk.strip()]
return chunks
# 字符串轉(zhuǎn)向量(embeddings)
def get_embedding(self, chunk):
# milkey/m3e 0.642084887746903
# bge-m3 0.6073383067378445
# nomic-embed-text 完全找不到
res = embeddings(model='milkey/m3e', prompt=chunk)
# print(chunk)
# print(res)
# print(res['embedding'])
return res['embedding']
def get_embeddings(self, chunks):
embeds = []
for chunk in chunks:
embed = self.get_embedding(chunk)
embeds.append(embed)
return np.array(embeds)
# 查詢相似性向量
def search(self, text):
print(text)
max_similarity = 0
max_similarity_index = 0
ask_embed = self.get_embedding(text)
for kb_embed_index, kb_embed in enumerate(self.embeds):
similarity = self.similarity(kb_embed, ask_embed)
# print(similarity)
# print(self.chunks[kb_embed_index])
if similarity > max_similarity:
max_similarity = similarity
max_similarity_index = kb_embed_index
print(max_similarity)
print(self.chunks[max_similarity_index])
# print(self.embeds[max_similarity_index])
# 返回查到的相關(guān)文本
return self.chunks[max_similarity_index]
# 相似度
@staticmethod
def similarity(A, B):
# 計(jì)算點(diǎn)積
dot_product = np.dot(A, B)
# 計(jì)算范數(shù)
norm_A = np.linalg.norm(A)
norm_B = np.linalg.norm(B)
# 計(jì)算余弦相似度
cosine_sim = dot_product / (norm_A * norm_B)
return cosine_sim2. rag.py
from kb import Kb
from ollama import chat, Message
class Rag:
def __init__(self, model, kb_filepath):
self.kb_filepath = kb_filepath
self.kb = Kb(kb_filepath)
self.model = model
self.prompt_template = """
基于:%s
回答:%s
"""
def chat(self, message):
# 用戶消息檢索相關(guān)上下文
context = self.kb.search(message)
# print(context)
# prompt = self.prompt_template % (context, message)
prompt = '請基于以下內(nèi)容回答問題:\n' + context
response = chat(self.model, [Message(role='system', content=prompt), Message(role='user', content=message)])
return response['message']3. index.py
from rag import Rag
rag = Rag('deepseek-r1:14b', '私人知識庫.txt')
msg = rag.chat('請介紹下劉芳')
print(msg)4. 私人知識庫.txt
MIS部門人員名單
# 1. 張小剛
姓名:張小剛
性別:男
愛好:打籃球、踢足球
電話:132233444
籍貫:山東菏澤# 2. 李光亮
姓名:李光亮
性別:男
愛好:踢足球、打排球
電話:15959595
籍貫:河南平頂山# 3. 王麗麗
姓名:王麗麗
性別:女
愛好:游泳、閱讀
電話:138123456
籍貫:江蘇南京# 4. 陳大明
姓名:陳大明
性別:男
愛好:跑步、爬山
電話:139876543
籍貫:浙江杭州# 5. 劉芳
姓名:劉芳
性別:女
愛好:瑜伽、繪畫
電話:137112233
籍貫:廣東深圳# 6. 趙強(qiáng)
姓名:趙強(qiáng)
性別:男
愛好:打羽毛球、釣魚
電話:135665544
籍貫:四川成都# 7. 孫婷婷
姓名:孫婷婷
性別:女
愛好:跳舞、唱歌
電話:136778899
籍貫:福建廈門# 8. 周偉
姓名:周偉
性別:男
愛好:打乒乓球、下棋
電話:134556677
籍貫:湖南長沙# 9. 吳曉梅
姓名:吳曉梅
性別:女
愛好:攝影、旅行
電話:133445566
籍貫:湖北武漢# 10. 鄭小龍
姓名:鄭小龍
性別:男
愛好:打籃球、游泳
電話:132334455
籍貫:陜西西安# 11. 高靜
姓名:高靜
性別:女
愛好:閱讀、寫作
電話:131223344
籍貫:遼寧沈陽# 12. 林浩
姓名:林浩
性別:男
愛好:踢足球、跑步
電話:130112233
籍貫:廣西南寧# 13. 黃雅婷
姓名:黃雅婷
性別:女
愛好:跳舞、瑜伽
電話:139001122
籍貫:云南昆明# 14. 徐志強(qiáng)
姓名:徐志強(qiáng)
性別:男
愛好:打排球、爬山
電話:138990011
籍貫:貴州貴陽# 15. 何麗
姓名:何麗
性別:女
愛好:繪畫、攝影
電話:137889900
籍貫:江西南昌# 16. 馬超
姓名:馬超
性別:男
愛好:打籃球、釣魚
電話:136778899
籍貫:山西太原# 17. 郭曉燕
姓名:郭曉燕
性別:女
愛好:唱歌、旅行
電話:135667788
籍貫:河北石家莊# 18. 羅志勇
姓名:羅志勇
性別:男
愛好:踢足球、下棋
電話:134556677
籍貫:吉林長春# 19. 鄧麗麗
姓名:鄧麗麗
性別:女
愛好:瑜伽、閱讀
電話:133445566
籍貫:黑龍江哈爾濱# 20. 許文強(qiáng)
姓名:許文強(qiáng)
性別:男
愛好:打羽毛球、跑步
電話:132334455
籍貫:安徽合肥# 21. 韓雪
姓名:韓雪
性別:女
愛好:跳舞、攝影
電話:131223344
籍貫:甘肅蘭州# 22. 曹陽
姓名:曹陽
性別:男
愛好:打籃球、爬山
電話:130112233
籍貫:青海西寧# 23. 謝婷婷
姓名:謝婷婷
性別:女
愛好:唱歌、繪畫
電話:139001122
籍貫:寧夏銀川# 24. 董志剛
姓名:董志剛
性別:男
愛好:踢足球、釣魚
電話:138990011
籍貫:新疆烏魯木齊# 25. 蘇靜
姓名:蘇靜
性別:女
愛好:閱讀、旅行
電話:137889900
籍貫:內(nèi)蒙古呼和浩特# 26. 潘偉
姓名:潘偉
性別:男
愛好:打乒乓球、下棋
電話:136778899
籍貫:海南???/p># 27. 鐘麗
姓名:鐘麗
性別:女
愛好:瑜伽、攝影
電話:135667788
籍貫:重慶# 28. 田小龍
姓名:田小龍
性別:男
愛好:打籃球、游泳
電話:134556677
籍貫:天津# 29. 白曉梅
姓名:白曉梅
性別:女
愛好:跳舞、唱歌
電話:133445566
籍貫:北京# 30. 石浩
姓名:石浩
性別:男
愛好:踢足球、跑步
電話:132334455
籍貫:上海
通過以上代碼,可基本實(shí)現(xiàn)用RAG技術(shù),搭建本地知識庫問答AI助理,非流式回復(fù)(steam=False)。需要等待大模型輸出所有文字之后,才能全部返回,太慢,肯定要實(shí)現(xiàn)一般聊天大模型的流式回復(fù)(steam=True)
首先,在rag.py中增加以下方法
def stream_chat(self, message):
context = self.kb.search(message)
prompt = '請基于以下內(nèi)容回答問題:\n' + context
response = chat(self.model, [Message(role='system', content=prompt), Message(role='user', content=message)], stream=True)
# 遍歷流式響應(yīng)
for chunk in response:
print(chunk['message']['content'], end='', flush=True) # 實(shí)時(shí)打印輸出
print() # 輸出完成后換行然后,調(diào)整index.py代碼為
from rag import Rag
rag = Rag('deepseek-r1:14b', '私人知識庫.txt')
rag.stream_chat('請介紹下劉芳')經(jīng)過以上的修改,就可以看到AI的流式答復(fù)了。

注:以上RAG只是獲取到了本地知識庫中的最為匹配的一條記錄,如果需要實(shí)現(xiàn)一次性獲取多個(gè)關(guān)聯(lián)內(nèi)容,并根據(jù)多個(gè)關(guān)聯(lián)內(nèi)容進(jìn)行答復(fù),需要使用向量數(shù)據(jù)庫。
以上就是Python使用Ollama實(shí)現(xiàn)私有大模型知識庫的詳細(xì)內(nèi)容,更多關(guān)于Python Ollama實(shí)現(xiàn)知識庫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)采集新型冠狀病毒數(shù)據(jù)實(shí)例
在本篇文章里小編給大家整理了關(guān)于Python實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)采集新型冠狀病毒數(shù)據(jù)實(shí)例內(nèi)容,有需要的朋友們可以學(xué)習(xí)參考下。2020-02-02
python pandas合并Sheet,處理列亂序和出現(xiàn)Unnamed列的解決
這篇文章主要介紹了python pandas合并Sheet,處理列亂序和出現(xiàn)Unnamed列的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Pytorch中TensorBoard及torchsummary的使用詳解
這篇文章主要介紹了Pytorch中TensorBoard及torchsummary的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05
Python 調(diào)用有道翻譯接口實(shí)現(xiàn)翻譯
這篇文章主要介紹了Python 調(diào)用有道翻譯接口實(shí)現(xiàn)翻譯,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Python中標(biāo)準(zhǔn)模塊importlib詳解
這篇文章主要給大家詳細(xì)介紹了Python中標(biāo)準(zhǔn)模塊importlib的使用方法和示例,非常簡單,有需要的小伙伴可以參考下2017-04-04

