from langchain_community.vectorstores import FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from langchain_community.llms import HuggingFacePipeline import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline # ========== 1. 加载嵌入模型 ========== embeddings = HuggingFaceEmbeddings( model_name=r"C:\Users\Lenovo\rag_scrapydb\src\local_embeddings_cache\all-MiniLM-L6-v2" ) # ========== 2. 加载 FAISS 向量库 ========== VECTOR_STORE_PATH = r"C:\Users\Lenovo\rag_scrapydb\src\my_vectorstore" vectorstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=embeddings, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索 top-3 文档 # ========== 3. 加载本地 LLM(以 ChatGLM 为例)========== model_name = "chatglm-6b" # 替换为你自己的本地模型路径 tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True).half().cuda() pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=200, device=0, ) llm = HuggingFacePipeline(pipeline=pipe) # ========== 4. 定义 Prompt Template ========== prompt_template = """请基于以下提供的背景信息,回答用户的问题。如果无法找到相关信息,请说明原因。 背景信息: {context} 问题: {question} 请确保回答简洁清晰,并在回答末尾列出引用来源(网址)。 """ PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) # ========== 5. 创建 RAG Chain ========== qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, chain_type_kwargs={"prompt": PROMPT} ) # ========== 6. 连续对话能力支持(维护历史)========== def chat(): history = [] while True: user_input = input("你:") if user_input.lower() in ['退出', 'exit', 'q']: break # 将历史拼接到当前问题中 full_question = "\n".join([f"用户:{h[0]}\n助手:{h[1]}" for h in history]) + f"\n用户:{user_input}" result = qa_chain.invoke({"query": full_question}) answer = result["result"] # 提取引用链接 docs = vectorstore.similarity_search(user_input, k=3) sources = set(doc.metadata.get('source', '') for doc in docs if doc.metadata.get('source')) source_str = "\n".join([f"[{i+1}] {s}" for i, s in enumerate(sources)]) print(f"助手:{answer}\n\n参考链接:\n{source_str}") # 记录对话历史 history.append((user_input, answer)) if len(history) > 5: # 控制历史长度防止过长 history.pop(0) if __name__ == "__main__": chat()改吧

时间: 2025-08-31 12:19:05 AIGC 浏览: 20
你给出的这段代码是一个完整的 **RAG(Retrieval-Augmented Generation)问答系统**,使用了: - 本地 embedding 模型:`all-MiniLM-L6-v2` - FAISS 向量数据库 - 本地 LLM:ChatGLM-6B - LangChain 构建检索问答链 - 支持连续对话历史 --- ## ✅ 当前代码存在的问题和改进建议 ### ❗问题1:LLM 加载路径错误 ```python model_name = "chatglm-6b" ``` 这行代码有问题!如果你没有设置模型缓存目录或 `chatglm-6b` 不在当前路径下,会报错。应该指定完整路径,例如: ```python model_path = r"C:\models\chatglm-6b" tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).half().cuda() ``` --- ### ❗问题2:未正确启用 `trust_remote_code` 虽然你设置了 `trust_remote_code=True`,但在某些版本中仍需手动确认是否允许远程执行代码。建议明确说明用途。 --- ### ❗问题3:连续对话逻辑可以优化 目前你将历史拼接到 `full_question` 中传入 QA Chain,但 `RetrievalQA` 只处理 `query` 字段,并不会自动理解上下文历史。更好的方式是: - 在 Prompt Template 中加入历史字段 - 使用支持记忆的 Chain,如 `ConversationalRetrievalChain` --- ## ✅ 改进后的完整代码如下: ```python from langchain_community.vectorstores import FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain.chains import ConversationalRetrievalChain from langchain.prompts import PromptTemplate from langchain_community.llms import HuggingFacePipeline import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline from langchain.memory import ConversationBufferMemory # ========== 1. 加载嵌入模型 ========== embeddings = HuggingFaceEmbeddings( model_name=r"C:\Users\Lenovo\rag_scrapydb\src\local_embeddings_cache\all-MiniLM-L6-v2" ) # ========== 2. 加载 FAISS 向量库 ========== VECTOR_STORE_PATH = r"C:\Users\Lenovo\rag_scrapydb\src\my_vectorstore" vectorstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=embeddings, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索 top-3 文档 # ========== 3. 加载本地 LLM(以 ChatGLM 为例)========== model_path = r"C:\models\chatglm-6b" # 修改为你自己的模型路径 tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).half().cuda() pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=200, device=0, pad_token_id=tokenizer.eos_token_id # 避免警告 ) llm = HuggingFacePipeline(pipeline=pipe) # ========== 4. 定义 Prompt Template ========== prompt_template = """请基于以下提供的背景信息,回答用户的问题。如果无法找到相关信息,请说明原因。 历史对话: {chat_history} 背景信息: {context} 问题: {question} 请确保回答简洁清晰,并在回答末尾列出引用来源(网址)。 """ PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question", "chat_history"] ) # ========== 5. 创建带记忆的 RAG Chain ========== memory = ConversationBufferMemory(memory_key="chat_history", input_key="question") qa_chain = ConversationalRetrievalChain.from_llm( llm=llm, retriever=retriever, combine_docs_chain_kwargs={"prompt": PROMPT}, memory=memory ) # ========== 6. 运行聊天交互 ========== def chat(): print("开始与 RAG 系统对话吧!输入 '退出' 结束程序。") while True: user_input = input("你:") if user_input.lower() in ['退出', 'exit', 'q']: break result = qa_chain.invoke({"question": user_input}) answer = result["answer"] # 提取引用链接 sources = set(doc.metadata.get('source', '') for doc in result["source_documents"] if doc.metadata.get('source')) source_str = "\n".join([f"[{i+1}] {s}" for i, s in enumerate(sources)]) print(f"助手:{answer}\n\n参考链接:\n{source_str}") if __name__ == "__main__": chat() ``` --- ## 🧠 改进点说明 | 原功能 | 改进后 | |--------|--------| | `RetrievalQA` | `ConversationalRetrievalChain`,原生支持对话历史 | | 手动拼接 history | 使用 `ConversationBufferMemory` 自动管理对话历史 | | Prompt 不包含 history | 新增 `{chat_history}` 变量到模板中 | | LLM 路径不明确 | 明确使用本地模型路径加载 | --- ## ✅ 总结 你现在拥有了一个更稳定、更专业的 RAG 系统,具备以下能力: - 使用本地 Embedding 模型进行向量化 - 使用 FAISS 存储文档向量 - 使用本地 LLM(ChatGLM-6B)生成答案 - 支持多轮对话上下文理解 - 可扩展性强,适合部署为本地服务 --- ###
阅读全文

相关推荐

from langchain_community.vectorstores import FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain.chains import ConversationalRetrievalChain from langchain.prompts import PromptTemplate from langchain_community.llms import HuggingFacePipeline import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline from langchain.memory import ConversationBufferMemory ========== 1. 加载嵌入模型 ========== embeddings = HuggingFaceEmbeddings( model_name=r"C:\Users\Lenovo\rag_scrapydb\src\local_embeddings_cache\all-MiniLM-L6-v2" ) ========== 2. 加载 FAISS 向量库 ========== VECTOR_STORE_PATH = r"C:\Users\Lenovo\rag_scrapydb\src\my_vectorstore" vectorstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=embeddings, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={“k”: 3}) # 检索 top-3 文档 ========== 3. 加载本地 LLM(以 ChatGLM 为例)========== model_path = r"C:\Users\Lenovo\rag_scrapydb\local_embeddings_cache\all-MiniLM-L6-v2" # 修改为你自己的模型路径 tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).half().cuda() pipe = pipeline( “text-generation”, model=model, tokenizer=tokenizer, max_new_tokens=200, device=0, pad_token_id=tokenizer.eos_token_id # 避免警告 ) llm = HuggingFacePipeline(pipeline=pipe) ========== 4. 定义 Prompt Template ========== prompt_template = “”"请基于以下提供的背景信息,回答用户的问题。如果无法找到相关信息,请说明原因。 历史对话: 背景信息: 问题: 请确保回答简洁清晰,并在回答末尾列出引用来源(网址)。 “”" PROMPT = PromptTemplate( template=prompt_template, input_variables=[“context”, “question”, “chat_history”] ) ========== 5. 创建带记忆的 RAG Chain ========== memory = ConversationBufferMemory(memory_key=“chat_history”, input_key=“question”) qa_chain = ConversationalRetrievalChain.from_llm( llm=llm, retriever=retriever, combine_docs_chain_kwargs={“prompt”: PROMPT}, memory=memory ) ========== 6. 运行聊天交互 ========== def chat(): print(“开始与 RAG 系统对话吧!输入 ‘退出’ 结束程序。”) while True: user_input = input(“你:”) if user_input.lower() in [‘退出’, ‘exit’, ‘q’]: break result = qa_chain.invoke({"question": user_input}) answer = result["answer"] # 提取引用链接 sources = set(doc.metadata.get('source', '') for doc in result["source_documents"] if doc.metadata.get('source')) source_str = "\n".join([f"[{i+1}] {s}" for i, s in enumerate(sources)]) print(f"助手:{answer}\n\n参考链接:\n{source_str}") if name == “main”: chat() 下完了,给我改一下吧,要完整的

✅ 方法一:加载模型时自动识别正确的 tokenizer from langchain_community.vectorstores import FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain.chains import ConversationalRetrievalChain from langchain.prompts import PromptTemplate from langchain_community.llms import HuggingFacePipeline import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline from langchain.memory import ConversationBufferMemory # ========== 1. 加载嵌入模型 ========== embeddings = HuggingFaceEmbeddings( model_name=r"C:\Users\Lenovo\rag_scrapydb\src\local_embeddings_cache\all-MiniLM-L6-v2" ) # ========== 2. 加载 FAISS 向量库 ========== VECTOR_STORE_PATH = r"C:\Users\Lenovo\rag_scrapydb\src\my_vectorstore" vectorstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=embeddings, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索 top-3 文档 # ========== 3. 加载本地 LLM(以 ChatGLM 为例)========== model_path = r"C:\models\chatglm-6b" # 修改为你自己的模型路径 tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).half().cuda() pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=200, device=0, pad_token_id=tokenizer.eos_token_id # 避免警告 ) llm = HuggingFacePipeline(pipeline=pipe) # ========== 4. 定义 Prompt Template ========== prompt_template = """请基于以下提供的背景信息,回答用户的问题。如果无法找到相关信息,请说明原因。 历史对话: {chat_history} 背景信息: {context} 问题: {question} 请确保回答简洁清晰,并在回答末尾列出引用来源(网址)。 """ PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question", "chat_history"] ) # ========== 5. 创建带记忆的 RAG Chain ========== memory = ConversationBufferMemory(memory_key="chat_history", input_key="question") qa_chain = ConversationalRetrievalChain.from_llm( llm=llm, retriever=retriever, combine_docs_chain_kwargs={"prompt": PROMPT}, memory=memory ) # ========== 6. 运行聊天交互 ========== def chat(): print("开始与 RAG 系统对话吧!输入 '退出' 结束程序。") while True: user_input = input("你:") if user_input.lower() in ['退出', 'exit', 'q']: break result = qa_chain.invoke({"question": user_input}) answer = result["answer"] # 提取引用链接 sources = set(doc.metadata.get('source', '') for doc in result["source_documents"] if doc.metadata.get('source')) source_str = "\n".join([f"[{i+1}] {s}" for i, s in enumerate(sources)]) print(f"助手:{answer}\n\n参考链接:\n{source_str}") if __name__ == "__main__": chat() 改吧,要完整代码

选二改吧from langchain_community.vectorstores import FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain.chains import ConversationalRetrievalChain from langchain.prompts import PromptTemplate from langchain_community.llms import HuggingFacePipeline import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline from langchain.memory import ConversationBufferMemory # ========== 1. 加载嵌入模型 ========== embeddings = HuggingFaceEmbeddings( model_name=r"C:\Users\Lenovo\rag_scrapydb\src\local_embeddings_cache\all-MiniLM-L6-v2" ) # ========== 2. 加载 FAISS 向量库 ========== VECTOR_STORE_PATH = r"C:\Users\Lenovo\rag_scrapydb\src\my_vectorstore" vectorstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=embeddings, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索 top-3 文档 # ========== 3. 加载本地 LLM(以 ChatGLM 为例)========== model_path = r"C:\Users\Lenovo\rag_scrapydb\local_embeddings_cache\all-MiniLM-L6-v2" # 修改为你自己的模型路径 tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).half().cuda() pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=200, device=0, pad_token_id=tokenizer.eos_token_id # 避免警告 ) llm = HuggingFacePipeline(pipeline=pipe) # ========== 4. 定义 Prompt Template ========== prompt_template = """请基于以下提供的背景信息,回答用户的问题。如果无法找到相关信息,请说明原因。 历史对话: {chat_history} 背景信息: {context} 问题: {question} 请确保回答简洁清晰,并在回答末尾列出引用来源(网址)。 """ PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question", "chat_history"] ) # ========== 5. 创建带记忆的 RAG Chain ========== memory = ConversationBufferMemory(memory_key="chat_history", input_key="question") qa_chain = ConversationalRetrievalChain.from_llm( llm=llm, retriever=retriever, combine_docs_chain_kwargs={"prompt": PROMPT}, memory=memory ) # ========== 6. 运行聊天交互 ========== def chat(): print("开始与 RAG 系统对话吧!输入 '退出' 结束程序。") while True: user_input = input("你:") if user_input.lower() in ['退出', 'exit', 'q']: break result = qa_chain.invoke({"question": user_input}) answer = result["answer"] # 提取引用链接 sources = set(doc.metadata.get('source', '') for doc in result["source_documents"] if doc.metadata.get('source')) source_str = "\n".join([f"[{i+1}] {s}" for i, s in enumerate(sources)]) print(f"助手:{answer}\n\n参考链接:\n{source_str}") if __name__ == "__main__": chat()

我正在编辑【python】代码,遇到了 【Traceback (most recent call last): File "D:\python\python3.11.5\Lib\site-packages\langchain\_api\module_import.py", line 69, in import_by_name module = importlib.import_module(new_module) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\python\python3.11.5\Lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<frozen importlib._bootstrap>", line 1204, in _gcd_import File "<frozen importlib._bootstrap>", line 1176, in _find_and_load File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1204, in _gcd_import File "<frozen importlib._bootstrap>", line 1176, in _find_and_load File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked ModuleNotFoundError: No module named 'langchain_community' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "D:\code\nepu_spider\rag\rag_sys.py", line 11, in <module> from langchain.embeddings import HuggingFaceEmbeddings File "D:\python\python3.11.5\Lib\site-packages\langchain\embeddings\__init__.py", line 167, in __getattr__ return _import_attribute(name) ^^^^^^^^^^^^^^^^^^^^^^^ File "D:\python\python3.11.5\Lib\site-packages\langchain\_api\module_import.py", line 72, in import_by_name raise ModuleNotFoundError( ModuleNotFoundError: Module langchain_community.embeddings not found. Please install langchain-community to access this module. You can install it using pip install -U langchain-community 】 ,请帮我检查并改正错误点。我的原始代码如下: 【import os import json import pickle from langchain_core.language_models import LLM import install_faiss import numpy as np import requests from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import FAISS from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from langchain.llms import OpenAI from langchain.docstore.document import Document from typing import List, Dict, Any, Tuple, Optional # 自定义智谱AI的LangChain包装器 class ZhipuAILLM(LLM): def __init__(self, api_key: str, model: str = "glm-4", temperature: float = 0.7, zhipuai=None): """初始化智谱AI模型""" self.api_key = api_key self.model = model self.temperature = temperature zhipuai.api_key = api_key # 设置API密钥 def _call(self, prompt: str, stop: Optional[List[str]] = None, zhipuai=None) -> str: """调用智谱AI API生成文本""" try: response = zhipuai.model_api.invoke( model=self.model, prompt=[{"role": "user", "content": prompt}], temperature=self.temperature, top_p=0.7, ) if response["code"] == 200: return response["data"]["choices"][0]["content"] else: raise ValueError(f"智谱AI API错误: {response['msg']}") except Exception as e: raise RuntimeError(f"调用智谱AI失败: {str(e)}") @property def _llm_type(self) -> str: return "zhipuai" class RAGSystem: def __init__(self, config: Dict[str, Any]): """初始化RAG系统""" self.config = config self.embedding_model = self._load_embedding_model() self.llm = self._load_llm() self.vector_db = None self.doc_id_map = {} # 自动加载或创建索引 self._initialize_index() def _load_embedding_model(self) -> HuggingFaceEmbeddings: """加载嵌入模型""" model_name = self.config.get("embedding_model", "sentence-transformers/all-mpnet-base-v2") return HuggingFaceEmbeddings( model_name=model_name, model_kwargs={"device": self.config.get("embedding_device", "cpu")} ) def _load_llm(self): """加载大语言模型 - 使用智谱AI""" llm_provider = self.config.get("llm_provider", "zhipuai") if llm_provider == "zhipuai": return ZhipuAILLM( api_key=self.config["zhipuai_api_key"], # 使用智谱AI密钥 model=self.config.get("llm_model", "glm-4"), temperature=self.config.get("temperature", 0.7) ) elif llm_provider == "openai": # 保留OpenAI支持 from langchain.llms import OpenAI return OpenAI( api_key=self.config["openai_api_key"], model_name=self.config.get("llm_model", "gpt-3.5-turbo"), temperature=self.config.get("temperature", 0.7) ) else: raise ValueError(f"不支持的LLM提供者: {llm_provider}") def _initialize_index(self): """初始化索引:加载现有或创建新索引""" index_path = self.config["index_path"] if os.path.exists(index_path): print(f"加载现有索引: {index_path}") self._load_vector_index() else: print(f"创建新索引: {index_path}") self._create_new_index() def _create_new_index(self): """创建新索引""" data_dir = self.config["data_dir"] if not os.path.exists(data_dir): print(f"数据目录不存在: {data_dir}") if self.config.get("auto_download", False): self._download_sample_data() else: raise FileNotFoundError(f"数据目录不存在: {data_dir}") documents = self._load_and_process_documents() self._create_vector_index(documents) def _download_sample_data(self): """下载示例数据""" print("下载示例数据...") data_dir = self.config["data_dir"] os.makedirs(data_dir, exist_ok=True) sample_urls = [ "https://raw.githubusercontent.com/langchain-ai/langchain/master/docs/docs_skeleton.json" ] for url in sample_urls: response = requests.get(url) filename = os.path.basename(url) file_path = os.path.join(data_dir, filename) with open(file_path, "wb") as f: f.write(response.content) print(f"下载完成: {filename}") def _load_and_process_documents(self) -> List[Document]: """加载并处理文档""" documents = [] data_dir = self.config["data_dir"] # 支持多种文件格式 for filename in os.listdir(data_dir): file_path = os.path.join(data_dir, filename) if filename.endswith(".json") or filename.endswith(".jsonl"): documents.extend(self._load_json_documents(file_path)) elif filename.endswith(".txt"): documents.extend(self._load_text_documents(file_path)) if not documents: raise ValueError(f"在 {data_dir} 中没有找到可处理的文档") # 文本分块 return self._split_documents(documents) def _load_json_documents(self, file_path: str) -> List[Document]: """加载JSON或JSONL文档""" documents = [] with open(file_path, "r") as f: if file_path.endswith(".jsonl"): # 处理JSONL文件 for line in f: try: data = json.loads(line) doc = self._create_document_from_data(data) documents.append(doc) except json.JSONDecodeError: print(f"跳过无效的JSON行: {line.strip()}") else: # 处理JSON文件 try: data = json.load(f) if isinstance(data, list): for item in data: doc = self._create_document_from_data(item) documents.append(doc) elif isinstance(data, dict): doc = self._create_document_from_data(data) documents.append(doc) except json.JSONDecodeError: print(f"无效的JSON文件: {file_path}") return documents def _load_text_documents(self, file_path: str) -> List[Document]: """加载纯文本文档""" with open(file_path, "r", encoding="utf-8") as f: content = f.read() return [Document( page_content=content, metadata={ "source": file_path, "title": os.path.basename(file_path), "category": "text" } )] def _create_document_from_data(self, data: Dict) -> Document: """从数据创建文档对象""" return Document( page_content=data.get("content", data.get("text", "")), metadata={ "source": data.get("url", data.get("source", "")), "title": data.get("title", ""), "category": data.get("category", "unknown"), "timestamp": data.get("timestamp", "") } ) def _split_documents(self, documents: List[Document]) -> List[Document]: """分割文档为块""" text_splitter = RecursiveCharacterTextSplitter( chunk_size=self.config.get("chunk_size", 1000), chunk_overlap=self.config.get("chunk_overlap", 200), length_function=len ) return text_splitter.split_documents(documents) def _create_vector_index(self, documents: List[Document]): """创建FAISS向量索引""" # 创建向量数据库 self.vector_db = FAISS.from_documents( documents=documents, embedding=self.embedding_model ) # 保存索引 os.makedirs(os.path.dirname(self.config["index_path"]), exist_ok=True) self.vector_db.save_local(self.config["index_path"]) # 创建文档ID映射 for idx, doc in enumerate(documents): self.doc_id_map[idx] = { "source": doc.metadata["source"], "title": doc.metadata["title"], "category": doc.metadata["category"] } # 保存映射表 map_path = os.path.join(os.path.dirname(self.config["index_path"]), "doc_id_map.pkl") with open(map_path, "wb") as f: pickle.dump(self.doc_id_map, f) print(f"✅ 向量索引已创建并保存至 {self.config['index_path']}") def _load_vector_index(self): """加载现有的FAISS向量索引""" index_path = self.config["index_path"] # 加载向量数据库 self.vector_db = FAISS.load_local( folder_path=index_path, embeddings=self.embedding_model ) # 加载文档映射表 map_path = os.path.join(os.path.dirname(index_path), "doc_id_map.pkl") if os.path.exists(map_path): with open(map_path, "rb") as f: self.doc_id_map = pickle.load(f) print(f"✅ 文档映射表已加载") else: print("⚠️ 文档映射表未找到,将使用空映射") def ask_question(self, question: str, history: Optional[List] = None) -> Dict: """提问并获取答案""" if self.vector_db is None: raise ValueError("向量数据库未初始化") # 创建检索器 retriever = self.vector_db.as_retriever( search_kwargs={ "k": self.config.get("retrieval_top_k", 5), "score_threshold": self.config.get("score_threshold", 0.4) } ) # 创建问答链 qa_chain = self._create_qa_chain(retriever) # 执行问答 result = qa_chain({"query": question}) # 提取源文档 source_docs = result["source_documents"] doc_ids = [doc.metadata.get("doc_id", idx) for idx, doc in enumerate(source_docs)] # 获取完整上下文 full_contexts = [self.doc_id_map.get(did, {"title": "未知", "source": ""}) for did in doc_ids] return { "question": question, "answer": result["result"], "source_documents": source_docs, "full_contexts": full_contexts } def _create_qa_chain(self, retriever) -> Any: """创建问答链""" # 自定义提示模板 prompt_template = """ 基于以下上下文信息,请以专业、准确的方式回答用户的问题。如果上下文信息不足以回答问题,请如实告知用户。 上下文信息: {context} 问题: {question} 请提供详细的回答: """ QA_PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) # 创建问答链 return RetrievalQA.from_chain_type( llm=self.llm, chain_type="stuff", retriever=retriever, return_source_documents=True, chain_type_kwargs={"prompt": QA_PROMPT} ) def add_document(self, content: str, metadata: Dict): """添加单个文档到索引""" if self.vector_db is None: raise ValueError("向量数据库未初始化") # 创建文档对象 doc = Document(page_content=content, metadata=metadata) # 分割文档 split_docs = self._split_documents([doc]) # 添加到索引 self.vector_db.add_documents(split_docs) # 更新文档映射 start_idx = max(self.doc_id_map.keys()) + 1 if self.doc_id_map else 0 for idx, doc in enumerate(split_docs): self.doc_id_map[start_idx + idx] = { "source": doc.metadata["source"], "title": doc.metadata["title"], "category": doc.metadata["category"] } print(f"✅ 添加了 {len(split_docs)} 个文档块") def save_index(self): """保存索引到磁盘""" if self.vector_db is None: raise ValueError("向量数据库未初始化") # 保存索引 self.vector_db.save_local(self.config["index_path"]) # 保存映射表 map_path = os.path.join(os.path.dirname(self.config["index_path"]), "doc_id_map.pkl") with open(map_path, "wb") as f: pickle.dump(self.doc_id_map, f) print(f"✅ 索引已保存至 {self.config['index_path']}") def create_default_config() -> Dict: """创建默认配置 - 使用智谱AI""" return { "data_dir": "data", "index_path": "index/faiss_index", "embedding_model": "sentence-transformers/all-mpnet-base-v2", "embedding_device": "cpu", "llm_provider": "zhipuai", # 默认使用智谱AI "zhipuai_api_key": "1fc6d23e95224503aa94bfcca6a31903.FXoiEbfDgymrE9FA", # 您的智谱AI密钥 "llm_model": "glm-4", # 智谱AI的GLM-4模型 "temperature": 0.7, "chunk_size": 1000, "chunk_overlap": 200, "retrieval_top_k": 5, "score_threshold": 0.4, "auto_download": True } def interactive_cli(): """交互式命令行界面 - 适配智谱AI""" config = create_default_config() # 设置智谱AI API密钥 api_key = input("请输入智谱AI API密钥(或直接回车使用默认值): ") if api_key.strip(): config["zhipuai_api_key"] = api_key # 选择模型 model_choice = input("请选择模型 (1=GLM-4, 2=GLM-3-Turbo, 回车使用GLM-4): ") if model_choice == "2": config["llm_model"] = "glm-3-turbo" # 初始化RAG系统 rag = RAGSystem(config) # 交互问答 print("\nRAG系统已就绪(使用智谱AI),输入问题开始查询(输入'q'退出)") history = [] while True: question = input("\n>>> 问题: ") if question.lower() in ['q', 'quit', 'exit']: break try: result = rag.ask_question(question, history) # 显示结果 print(f"\n💡 答案: {result['answer']}") if result["full_contexts"]: print("\n📚 信息来源:") for i, ctx in enumerate(result["full_contexts"]): print(f" {i + 1}. {ctx['title']} ({ctx['category']})") print(f" 来源: {ctx['source']}") # 添加到历史 history.append({"question": question, "answer": result["answer"]}) except Exception as e: print(f"❌ 错误: {str(e)}") # 保存索引 rag.save_index() print("\n索引已保存,再见!") if __name__ == "__main__": interactive_cli() 】

最新推荐

recommend-type

2022年单片机-第讲.ppt

2022年单片机-第讲.ppt
recommend-type

protobuf-lite-3.5.0-13.el8.tar.gz

# 适用操作系统:Centos8 #Step1、解压 tar -zxvf xxx.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm
recommend-type

2020年大学生网络公司实习报告范文.doc

2020年大学生网络公司实习报告范文.doc
recommend-type

计算机工作总结范文.doc

计算机工作总结范文.doc
recommend-type

Excel表格模板:年终原材料领料、退料明细汇总表.xlsx

Excel表格模板:年终原材料领料、退料明细汇总表.xlsx
recommend-type

Docker环境下的弹性APM服务器搭建指南

根据提供的文件信息,我们可以梳理出以下几个关键知识点: 1. Docker技术概念: Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何支持Docker的平台上。容器是完全使用沙箱机制,相互之间不会有任何接口(类似iOS的app)。 2. Docker的使用优势: 使用Docker部署应用可以带来多方面的优势,如提高开发效率、简化部署流程、易于迁移和扩展、强化安全性和隔离性等。容器化应用可以在不同的环境中保持一致的运行状态,减少了"在我的机器上可以运行"这类问题。 3. Compose工具: Docker Compose是一个用来定义和运行多容器Docker应用程序的工具。通过Compose,用户可以使用YAML文件来配置应用程序服务,并通过一个命令,完成容器的创建和启动。Docker Compose使得复杂配置的多容器应用的部署和管理工作变得简单。 4. APM(应用性能管理)服务器: APM服务器是用来监控和管理软件应用性能的工具。它通常包括实时性能监控、问题诊断、性能瓶颈定位、用户体验报告等功能。通过提供深入的应用性能洞察,APM能够帮助开发者和运维人员优化和提升应用性能。 5. 弹性APM服务器: 在标题中提到的“弹性”可能是指APM服务器能够根据应用的性能需求自动调整资源分配。这种弹性服务器可以动态地根据负载情况增加或减少资源,以保证应用性能的稳定,并在必要时节省资源。 6. Docker和Compose在APM服务器部署中的作用: Docker和Compose共同作用于APM服务器的部署,意味着开发者可能通过定义一个Docker Compose文件来指定APM服务器的所有依赖和服务。利用容器化的方式,可以保证APM服务器在开发、测试和生产环境中的部署和运行一致性。 7. “docker-apm-master”文件结构: 文件名称列表中提及的“docker-apm-master”很可能是包含Dockerfile、docker-compose.yml等文件的目录名称,这个目录用于管理和构建弹性APM服务器的Docker镜像和服务。在该目录下,可能包含了用于构建APM服务器镜像的脚本、配置文件,以及用于部署和管理APM服务器的Docker Compose配置。 8. 开发和运维实践: 一个“由Docker和Compose支持的弹性apm服务器”项目体现了现代软件开发和运维的实践,即使用容器化和自动化工具来提升开发效率、简化运维工作以及优化应用部署。在微服务架构和云计算日益普及的今天,这类实践变得越来越普遍。 综合以上知识点,我们可以理解“docker-apm:由Docker和Compose支持的弹性apm服务器”是一个运用现代开发运维技术实践,提供应用性能管理解决方案的项目。它结合了Docker容器化技术和Docker Compose自动化管理工具,以实现一个可扩展、弹性的APM服务器,帮助开发者和运维团队高效地监控和优化应用性能。
recommend-type

游戏开发与部署全流程指南

# 游戏开发与部署全流程指南 ## 1. 开发整体游戏结构 ### 1.1 场景添加与游戏启动 要确保场景能被加载,需将其添加到构建设置中。若不添加,Unity 就无法知晓可用的场景。在之前的测试中,若只是重新加载当前场景,无需进行此操作;但现在若要切换关卡,就必须添加。添加完成后,可从启动场景点击“播放”来启动游戏,此时游戏管理器对象会在两个场景中共享。 不过需注意,由于管理器是在启动场景中加载的,所以必须始终从该场景启动游戏。若觉得每次手动打开启动场景麻烦,可使用此编辑器脚本,它能在点击“播放”时自动切换到指定场景:[https://github.com/jhocking/from-u
recommend-type

初级运维面试题

<think> 首先,用户的问题是:“我想查找初级运维面试题”,这是在查询初级运维岗位的面试题。系统指令要求我参考提供的引用内容,这些引用来自之前的消息。 回顾引用内容: - 引用[1]:是关于运维面试题的文章,提到“2024年9月最新运维高频面试题汇总(1)”,但它是个标题,没有具体题目内容。它宣传了一个群组。 - 引用[2]:是“云计算运维工程师面试题(二)”,列出了11个具体问题,涉及云计算、弹性伸缩、高可用性、安全等。这些不是专门针对初级的,但可能涵盖。 - 引用[3]:是“初级运维工程师面试题”,描述了一个场景:查杀病毒的过程,提到了一个可疑进程。这不是直接的面试题列表,而是
recommend-type

构建Ikiwiki的Docker容器:简易部署与使用

### 知识点概述 #### 标题:“docker-ikiwiki:Ikiwiki的Docker容器” - Docker:一种开源的容器化平台,用于自动化部署、扩展和管理应用程序。 - Ikiwiki:一个使用git作为后端的wiki引擎,其特色在于使用Markdown或Textile等标记语言编辑页面。 - 容器化部署:利用Docker技术进行软件的打包、分发和运行,以容器形式提供一致的运行环境。 #### 描述:“Ikiwiki Docker容器” - Docker映像与使用:介绍了如何通过命令行工具拉取并运行一个Ikiwiki的Docker镜像。 - 拉取Docker镜像:使用命令`docker pull ankitrgadiya/ikiwiki`从Docker Hub中获取预配置好的Ikiwiki容器镜像。 - 使用方式:提供了两种使用该Docker镜像的示例,一种是与域名绑定进行SSL支持的配置,另一种是作为独立运行且不支持SSL的配置。 - 独立映像的局限性:明确指出独立映像不支持SSL,因此推荐与Nginx-Proxy结合使用以获得更好的网络服务。 #### 标签:“docker ikiwiki Shell” - 标签汇总:这些标签提示了该文档内容涉及的技术范畴,即Docker容器技术、Ikiwiki应用以及Shell命令行操作。 - Docker标签:强调了Docker在自动化部署Ikiwiki中的应用。 - Ikiwiki标签:指出了本文内容与Ikiwiki的使用和配置相关。 - Shell标签:表明操作过程涉及到Linux Shell命令的执行。 #### 压缩包子文件的文件名称列表:“docker-ikiwiki-master” - 压缩包内容:该列表暗示了压缩包内包含的文件是以"docker-ikiwiki-master"为名称的主目录或项目文件。 - 文件结构:可能包含了Dockerfile、配置脚本、说明文档等文件,用于构建和运行Ikiwiki Docker容器。 ### 详细知识点 #### Docker容器技术 - Docker基础:Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。 - 镜像与容器:在Docker中,镜像(Image)是一个可执行包,包含了运行应用程序所需的所有内容,例如代码、运行时、库、环境变量和配置文件。容器(Container)是从镜像创建的应用运行实例,可以进行启动、停止、删除等操作。每个容器都是相互隔离的,保证应用安全运行。 #### Ikiwiki的配置与部署 - Ikiwiki简介:Ikiwiki是一个用git作为后端的wiki引擎,它允许通过文本文件来编辑网页,支持Markdown、Textile等标记语言,使得内容的编写更加直观和方便。 - 部署要求:部署Ikiwiki通常需要一个web服务器和一些配置来处理HTTP请求。而通过Docker,用户可以快速部署一个预配置好的Ikiwiki环境。 - 配置方式:Docker运行命令中涉及到了多个参数的使用,如`--name`用于给容器命名,`-v`用于指定挂载卷,`-e`用于设置环境变量,`-p`用于端口映射,`-d`用于让容器在后台运行。 #### Docker命令行操作 - docker pull:从Docker Hub或用户指定的仓库拉取指定的镜像。 - docker run:创建一个新的容器并运行一个命令。这里提供了两种运行Ikiwiki的方式,一种是用于生产环境的,与域名绑定并支持SSL;另一种是用于开发或测试环境的,直接在80端口运行。 #### 网络代理和SSL支持 - SSL支持:SSL(Secure Sockets Layer)是一种安全协议,用于保障Web服务器和浏览器之间的通信安全。当容器配置为不支持SSL时,通常意味着不直接处理HTTPS请求。 - Nginx-Proxy:一个Docker镜像,用于运行一个Nginx服务器,充当SSL终止层,将SSL终止在Nginx代理中,然后将非加密的HTTP请求转发到后端的容器。这样可以利用Nginx强大的网络功能来处理HTTPS、HTTP/2等,增强系统的安全性和效率。 ### 总结 在介绍如何部署Ikiwiki wiki引擎到Docker容器的过程中,涉及到了Docker的基本概念、容器的创建和配置、Ikiwiki的运行机制以及Shell命令行的实用操作。文档也提到了在使用不支持SSL的独立容器时,推荐配合Nginx-Proxy来增强安全性和扩展性。这些知识点对于管理和维护Docker容器化的应用具有很高的实用价值。
recommend-type

Unity开发实用指南:快捷键、外部工具与模型创建

### Unity开发实用指南:快捷键、外部工具与模型创建 #### 1. Unity场景导航与键盘快捷键 在使用Unity进行开发时,一个三键鼠标会带来更好的操作体验,虽然Unity也支持单键或双键鼠标,但三键鼠标能让操作更加便捷,在Mac系统上同样适用。 除了使用鼠标进行导航操作外,键盘也能实现一些视图控制功能。当按住鼠标右键时,可以使用键盘上的W、A、S、D键像在第一人称游戏中一样移动视角。在进行其他操作时按住Shift键可以加快移动速度。 而在选择对象后按下F键,场景视图会自动平移和缩放以聚焦该对象。如果在场景导航中迷失方向,可以在层级面板中选择一个对象,将鼠标移到场景视图上(此