使用Langchain生成本地rag知识库并搭载大模型

准备设备: 手机+aidlux2.0个人版

一、下载依赖

pip install langchain langchain-community faiss-cpu pypdf

二、安装ollama并下载模型

bash 复制代码
 curl -fsSL https://ollama.com/install.sh | sh #需要科学上网
 ollama serve & #让ollama服务在后台运行

安装完毕可以查看ollama版本进行验证,出现版本号之后就可以使用ollama

ollama -v

考虑性能因素,选择下载较小的模型

bash 复制代码
 ollama pull phi3:mini 
 ollama pull all-minilm

三、构建rag知识库

  1. 打开手机上的aidlux应用,打开Cloud_ip查看网络ip,输入ip到浏览器+端口号:8000访问 输入以下命令:
bash 复制代码
 cd ~
 touch build_knowledge_base.py
  1. 在文件浏览器中/home/aidlux 下找到对应py文件并打开
  2. 自行准备一个知识库文本(txt或pdf),将文本的路径填入脚本中
  3. 写入以下脚本内容
python 复制代码
 from langchain_community.document_loaders import PyPDFLoader, TextLoader
 from langchain_text_splitters import RecursiveCharacterTextSplitter
 from langchain_community.embeddings import OllamaEmbeddings
 from langchain_community.vectorstores import FAISS
 import os
 
 # 1. 设置环境变量优化 Ollama 性能
 os.environ["OLLAMA_NUM_THREADS"] = "8"  # 设置线程数
 os.environ["OLLAMA_NUM_CTX"] = "2048"   # 设置上下文长度
 
 # 2. 配置嵌入模型 - 移除无效参数
 embeddings = OllamaEmbeddings(
     model="all-minilm"  # 仅保留必要参数
 )
 
 # 3. 加载文档
 def load_documents(file_path):
     if file_path.endswith(".pdf"):
         loader = PyPDFLoader(file_path)
         print(f"加载 PDF 文档: {file_path}")
     elif file_path.endswith(".txt"):
         loader = TextLoader(file_path)
         print(f"加载文本文档: {file_path}")
     else:
         raise ValueError(f"不支持的文档格式: {file_path}")
     return loader.load()
 
 # 4. 文本分割
 def split_documents(docs):
     text_splitter = RecursiveCharacterTextSplitter(
         chunk_size=500,
         chunk_overlap=80,
         separators=["\n\n", "\n", "。", "!", "?", ";"]
     )
     return text_splitter.split_documents(docs)
 
 # 5. 主函数
 def main():
     # 示例文档 - 修改为您的文件路径
     document_path = "knowledge.txt"
     
     # 加载和分割文档
     print("开始处理文档...")
     documents = load_documents(document_path)
     chunks = split_documents(documents)
     print(f"文档分割完成: 共 {len(chunks)} 个文本块")
     
     # 创建向量存储
     print("开始生成嵌入向量...")
     vector_store = FAISS.from_documents(
         documents=chunks,
         embedding=embeddings
     )
     
     # 保存知识库索引
     save_path = "my_knowledge_base"
     vector_store.save_local(save_path)
     print(f"知识库构建完成! 保存到: {save_path}")
     print(f"向量库大小: {len(vector_store.index_to_docstore_id)} 个向量")
 
 if __name__ == "__main__":
     main()
 
  1. 运行脚本

python3 build_knowledge_base.py

四、创建 RAG 问答系统

  1. 创建一个脚本

touch rag_query.py

  1. 写入以下内容
python 复制代码
 from langchain_community.llms import Ollama
 from langchain_community.embeddings import OllamaEmbeddings
 from langchain_community.vectorstores import FAISS
 from langchain_core.prompts import ChatPromptTemplate
 from langchain_core.runnables import RunnablePassthrough
 from langchain_core.output_parsers import StrOutputParser
 import os
 import time
 import sys
 import select
 
 # 1. 通过环境变量设置优化参数
 os.environ["OLLAMA_NUM_THREADS"] = "8"  # 设置线程数
 os.environ["OLLAMA_NUM_CTX"] = "2048"   # 设置上下文长度
 
 # 2. 初始化模型
 llm = Ollama(
     model="phi3:mini",        # 轻量级语言模型
     temperature=0.3,           # 平衡创造性和准确性
     timeout=120.0              # 设置超时时间
     )
 
 embeddings = OllamaEmbeddings(model="all-minilm")
 
 # 3. 加载知识库
 try:
     vector_store = FAISS.load_local(
         "my_knowledge_base", 
         embeddings, 
         allow_dangerous_deserialization=True
     )
     retriever = vector_store.as_retriever(search_kwargs={"k": 3})
     print("知识库加载成功")
 except Exception as e:
     print(f"加载知识库失败: {str(e)}")
     print("请确保已运行 build_knowledge_base.py 构建知识库")
     exit(1)
 
 # 4. 定义提示模板
 template = """你是一个专业的知识库助手,请基于以下上下文回答问题。
 如果不知道答案,请说"我不知道",不要编造答案。
 
 上下文:
 {context}
 
 问题:{question}
 
 请用中文给出详细回答:"""
 prompt = ChatPromptTemplate.from_template(template)
 
 # 5. 构建 RAG 链
 rag_chain = (
     {"context": retriever, "question": RunnablePassthrough()}
     | prompt
     | llm
     | StrOutputParser()
 )
 
 # 6. 格式化文档显示
 def format_docs(docs):
     return "\n\n".join(doc.page_content for doc in docs)
 
 # 7. 改进的输入函数(解决输入卡住问题)
 def get_user_input(prompt, timeout=60):
     print(prompt, end='', flush=True)
     
     # 使用 select 检测输入可用性
     if select.select([sys.stdin], [], [], timeout)[0]:
         return sys.stdin.readline().strip()
     return None
 
 # 8. 交互式问答
 print("知识库问答系统已启动(输入 'exit' 退出)")
 while True:
     try:
         # 使用改进的输入函数
         query = get_user_input("\n你的问题:")
         
         if query is None:
             print("\n输入超时,请重新输入...")
             continue
             
         if query.lower() == "exit":
             break
         
         start_time = time.time()
         
         # 显示检索到的参考内容
         relevant_docs = retriever.invoke(query)
         print("\n[检索到的参考内容]")
         for i, doc in enumerate(relevant_docs[:2]):  # 显示前2个相关片段
             print(f"\n片段 {i+1}:\n{doc.page_content[:200]}...")
         
         # 生成答案
         response = rag_chain.invoke(query)
         
         end_time = time.time()
         
         print(f"\n[答案] (耗时:{end_time - start_time:.2f}秒)")
         print(response)
         
         # 确保输出缓冲区刷新
         sys.stdout.flush()
         
     except KeyboardInterrupt:
         print("\n退出系统...")
         break
     except Exception as e:
         print(f"处理问题时出错: {str(e)}")
         print("请尝试简化问题或稍后重试")
         # 清除可能的输入缓冲区残留
         sys.stdin.readline()
 

五、测试验证

python3 rag_query.py

根据提示词输入

相关推荐
楠枬2 小时前
DNS 域名解析
服务器·网络·网络协议
朱自清的诗.2 小时前
使用python脚本储存mosquito服务器数据到sqlite
python·单片机·sqlite·esp32
XMZH030422 小时前
网络编程;TCP多进程并发服务器;TCP多线程并发服务器;TCP网络聊天室和UDP网络聊天室;后面两个还没写出来;0911
服务器·网络·tcp/ip·udp·tcp
xiao-xiang2 小时前
Django的session机制
python·django
SXJR3 小时前
Java mp4parser 实现视频mp4 切割
java·python·音视频
云飞云共享云桌面3 小时前
1台电脑10个画图设计用怎么实现
linux·运维·服务器·网络·数据库·自动化·电脑
EvanSun__3 小时前
Flask 框架引入
后端·python·flask
艾莉丝努力练剑3 小时前
【Linux】初始Linux:从计算机历史发展、操作系统历史脉络的角度详谈Linux相关的话题,附Linux安装和用户创建(环境准备)详解
linux·运维·服务器·经验分享
小王不爱笑1323 小时前
Java基础知识(十四)
java·windows·python