準備設備: 手機+aidlux2.0個人版
一、下載依賴
pip install langchain langchain-community faiss-cpu pypdf
二、安裝ollama并下載模型
curl -fsSL https://ollama.com/install.sh | sh #需要科學上網
ollama serve & #讓ollama服務在后臺運行
安裝完畢可以查看ollama版本進行驗證,出現版本號之后就可以使用ollama
ollama -v
考慮性能因素,選擇下載較小的模型
ollama pull phi3:mini
ollama pull all-minilm
三、構建rag知識庫
- 打開手機上的aidlux應用,打開Cloud_ip查看網絡ip,輸入ip到瀏覽器+端口號
:8000
訪問
輸入以下命令:
cd ~
touch build_knowledge_base.py
- 在文件瀏覽器中/home/aidlux 下找到對應py文件并打開
- 自行準備一個知識庫文本(txt或pdf),將文本的路徑填入腳本中
- 寫入以下腳本內容
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()
- 運行腳本
python3 build_knowledge_base.py
四、創建 RAG 問答系統
- 創建一個腳本
touch rag_query.py
- 用文件瀏覽器的方式寫入以下內容
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輸入超時,請重新輸入...")continueif query.lower() == "exit":breakstart_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退出系統...")breakexcept Exception as e:print(f"處理問題時出錯: {str(e)}")print("請嘗試簡化問題或稍后重試")# 清除可能的輸入緩沖區殘留sys.stdin.readline()
五、測試驗證
python3 rag_query.py
根據提示詞輸入