Python使用Ollama实现私有大模型知识库
作者:一笑
在不依赖 LangChain、LlamaIndex 等框架,以及各种知识问答软件的情况下,尽量减少第三方库的使用,仅通过 Ollama 和 NumPy 两个外部库来实现 RAG(Retrieval-Augmented Generation)应用。
一、安装python
下载:https://python.org/downloads/
安装:一路下一步即可,安装完成后运行以下代码,即可查看对应版本号
python --version
二、安装PyCharm
(推荐,也可以用vscode或windows记事本等编辑软件)
PyCharm的优点:
- 自动提示
- 创建项目时自动创建python虚拟环境
- 整合本地终端(且基于python对应本项目的虚拟环境)
三、安装ollama
下载:https://ollama.com/download
安装:一路下一步。安装完成后用以下命令检验
ollama --version
四、在ollama中安装开源chat大模型
在ollama中安装开源chat大模型:qwen2.5 或deepseek-r1
ollama官网models(https://ollama.com/search)页面可以找到很多开源大模型,我们下载用的比较多的千问中文大模型(显卡差的建议安装ollama2.5:0.5b)
ollama run qwen2.5
五、在ollama中安装开源embedding大模型
在ollama中安装开源embedding大模型:milkey/m3e nomic-embed-text
embedding作用是将问题和知识库文本转换成向量,便于查询。
原本打算使用nomic-embed-text模型,但是使用时效果不好,发现m3e的效果不错,所以改用m3e
ollama run milkey/m3e
六、在项目python虚拟环境中安装ollama
pip install ollama
七、安装numpy
pip install numpy
八、编写代码
项目文件目录结构如下图
1. kb.py
import numpy as np from ollama import embeddings class Kb: def __init__(self, filepath): # 读取文件内容 content = self.read_file(filepath) # print(content) # 读取拆分好的数组 self.chunks = self.split_content(content) # print(chunks) # for chunk in chunks: # print(chunk) # print('=' * 10) # 转换成向量 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 # 字符串转向量(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]) # 返回查到的相关文本 return self.chunks[max_similarity_index] # 相似度 @staticmethod def similarity(A, B): # 计算点积 dot_product = np.dot(A, B) # 计算范数 norm_A = np.linalg.norm(A) norm_B = np.linalg.norm(B) # 计算余弦相似度 cosine_sim = dot_product / (norm_A * norm_B) return cosine_sim
2. 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): # 用户消息检索相关上下文 context = self.kb.search(message) # print(context) # prompt = self.prompt_template % (context, message) prompt = '请基于以下内容回答问题:\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. 赵强
姓名:赵强
性别:男
爱好:打羽毛球、钓鱼
电话:135665544
籍贯:四川成都# 7. 孙婷婷
姓名:孙婷婷
性别:女
爱好:跳舞、唱歌
电话:136778899
籍贯:福建厦门# 8. 周伟
姓名:周伟
性别:男
爱好:打乒乓球、下棋
电话:134556677
籍贯:湖南长沙# 9. 吴晓梅
姓名:吴晓梅
性别:女
爱好:摄影、旅行
电话:133445566
籍贯:湖北武汉# 10. 郑小龙
姓名:郑小龙
性别:男
爱好:打篮球、游泳
电话:132334455
籍贯:陕西西安# 11. 高静
姓名:高静
性别:女
爱好:阅读、写作
电话:131223344
籍贯:辽宁沈阳# 12. 林浩
姓名:林浩
性别:男
爱好:踢足球、跑步
电话:130112233
籍贯:广西南宁# 13. 黄雅婷
姓名:黄雅婷
性别:女
爱好:跳舞、瑜伽
电话:139001122
籍贯:云南昆明# 14. 徐志强
姓名:徐志强
性别:男
爱好:打排球、爬山
电话:138990011
籍贯:贵州贵阳# 15. 何丽
姓名:何丽
性别:女
爱好:绘画、摄影
电话:137889900
籍贯:江西南昌# 16. 马超
姓名:马超
性别:男
爱好:打篮球、钓鱼
电话:136778899
籍贯:山西太原# 17. 郭晓燕
姓名:郭晓燕
性别:女
爱好:唱歌、旅行
电话:135667788
籍贯:河北石家庄# 18. 罗志勇
姓名:罗志勇
性别:男
爱好:踢足球、下棋
电话:134556677
籍贯:吉林长春# 19. 邓丽丽
姓名:邓丽丽
性别:女
爱好:瑜伽、阅读
电话:133445566
籍贯:黑龙江哈尔滨# 20. 许文强
姓名:许文强
性别:男
爱好:打羽毛球、跑步
电话:132334455
籍贯:安徽合肥# 21. 韩雪
姓名:韩雪
性别:女
爱好:跳舞、摄影
电话:131223344
籍贯:甘肃兰州# 22. 曹阳
姓名:曹阳
性别:男
爱好:打篮球、爬山
电话:130112233
籍贯:青海西宁# 23. 谢婷婷
姓名:谢婷婷
性别:女
爱好:唱歌、绘画
电话:139001122
籍贯:宁夏银川# 24. 董志刚
姓名:董志刚
性别:男
爱好:踢足球、钓鱼
电话:138990011
籍贯:新疆乌鲁木齐# 25. 苏静
姓名:苏静
性别:女
爱好:阅读、旅行
电话:137889900
籍贯:内蒙古呼和浩特# 26. 潘伟
姓名:潘伟
性别:男
爱好:打乒乓球、下棋
电话:136778899
籍贯:海南海口# 27. 钟丽
姓名:钟丽
性别:女
爱好:瑜伽、摄影
电话:135667788
籍贯:重庆# 28. 田小龙
姓名:田小龙
性别:男
爱好:打篮球、游泳
电话:134556677
籍贯:天津# 29. 白晓梅
姓名:白晓梅
性别:女
爱好:跳舞、唱歌
电话:133445566
籍贯:北京# 30. 石浩
姓名:石浩
性别:男
爱好:踢足球、跑步
电话:132334455
籍贯:上海
通过以上代码,可基本实现用RAG技术,搭建本地知识库问答AI助理,非流式回复(steam=False)。需要等待大模型输出所有文字之后,才能全部返回,太慢,肯定要实现一般聊天大模型的流式回复(steam=True)
首先,在rag.py中增加以下方法
def stream_chat(self, message): context = self.kb.search(message) prompt = '请基于以下内容回答问题:\n' + context response = chat(self.model, [Message(role='system', content=prompt), Message(role='user', content=message)], stream=True) # 遍历流式响应 for chunk in response: print(chunk['message']['content'], end='', flush=True) # 实时打印输出 print() # 输出完成后换行
然后,调整index.py代码为
from rag import Rag rag = Rag('deepseek-r1:14b', '私人知识库.txt') rag.stream_chat('请介绍下刘芳')
经过以上的修改,就可以看到AI的流式答复了。
注:以上RAG只是获取到了本地知识库中的最为匹配的一条记录,如果需要实现一次性获取多个关联内容,并根据多个关联内容进行答复,需要使用向量数据库。
以上就是Python使用Ollama实现私有大模型知识库的详细内容,更多关于Python Ollama实现知识库的资料请关注脚本之家其它相关文章!