借助LangChain(Python)创建AI RAG聊天机器人:提升智能交互体验
谁不想从文档中立即获得答案?这正是 RAG 聊天机器人所做的 – 将检索与 AI 生成相结合,以获得快速、准确的响应!
在本指南中,我将向您展示如何使用LangChain和Streamlit中的检索增强生成 (RAG)创建聊天机器人。该聊天机器人将从知识库中提取相关信息并使用语言模型生成响应。
我将引导您完成每个步骤,提供多种响应生成选项,无论您使用OpenAI、Gemini还是Fireworks——确保灵活且经济高效的解决方案。
什么是检索增强生成 (RAG)?
RAG是一种结合检索和生成的方法,旨在提供更准确、更能感知上下文的聊天机器人响应。检索过程从知识库中提取相关文档,而生成过程则使用语言模型根据检索到的内容创建连贯的响应。这可确保您的聊天机器人能够使用最新数据回答问题,即使语言模型本身尚未针对该信息进行专门训练。
想象一下,您有一个私人助理,但他并不总是知道您问题的答案。因此,当您提出问题时,他们会查阅书籍并找到相关信息(检索),然后总结这些信息并用自己的话告诉您(生成)。这基本上就是 RAG 的工作方式,结合了两全其美的优势。
在流程图中,RAG 流程看起来有点像这样:
设置项目环境
1.创建项目文件夹和虚拟环境
mkdir rag-chatbot
cd rag-chatbot
python -m venv venv
source venv/bin/activate
2.安装依赖项
接下来,创建一个requirements.txt文件来列出所有必要的依赖项:
langchain==0.0.329
streamlit==1.27.2
faiss-cpu==1.7.4
python-dotenv==1.0.0
tiktoken==0.5.1
openai==0.27.10
gemini==0.3.1
fireworks==0.4.0
sentence_transformers==2.2.2
现在,安装以下依赖项:
pip install -r requirements.txt
3.设置 API 密钥
我们将使用OpenAI、Gemini或Fireworks来生成聊天机器人的响应。您可以根据自己的喜好选择其中任何一种。
如果您正在实验,请不要担心,Fireworks 免费提供价值 1 美元的 API 密钥,并且gemini-1.5-flash模型在一定程度上也是免费的!
设置一个.env文件来存储您首选模型的 API 密钥:
# Uncomment your API key
# OPENAI_API_KEY=your_openai_api_key_here
# GEMINI_API_KEY=your_gemini_api_key_here
# FIREWORKS_API_KEY=your_fireworks_api_key_here
请务必注册这些服务并获取您的 API 密钥。Gemini和Fireworks均提供免费套餐,而OpenAI则根据使用量收费。
文档处理和分块
为了给聊天机器人提供上下文,我们需要处理文档并将其拆分成可管理的块。这很重要,因为需要分解大型文本才能嵌入和索引。
1. 创建document_processor.py
创建一个名为的新 Python 脚本document_processor.py来处理文档:
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
class DocumentProcessor:
def __init__(self, file_path):
self.file_path = file_path
def load_and_split(self):
loader = TextLoader(self.file_path)
documents = loader.load()
splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
texts = splitter.split_documents(documents)
return texts
if __name__ == "__main__":
processor = DocumentProcessor("data/sample_text.txt")
texts = processor.load_and_split()
print(f"Processed {len(texts)} text chunks")
此脚本加载文本文件并将其拆分为约 1000 个字符的小块,并留有少量重叠,以确保块之间不会丢失任何上下文。处理完成后,文档即可嵌入和索引。
创建嵌入和索引
现在我们已经将文档分块,下一步是将它们转换为嵌入(文本的数字表示)并对其进行索引以便快速检索。(因为机器理解数字比理解单词更容易)
1. 创建embedding_indexer.py
创建另一个脚本embedding_indexer.py:
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
class EmbeddingIndexer:
def __init__(self):
self.embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
def create_vectorstore(self, texts):
vectorstore = FAISS.from_documents(texts, self.embeddings)
return vectorstore
if __name__ == "__main__":
from document_processor import DocumentProcessor
processor = DocumentProcessor("data/sample_text.txt")
texts = processor.load_and_split()
indexer = EmbeddingIndexer()
vectorstore = indexer.create_vectorstore(texts)
print("Vector store created successfully")
在此脚本中,使用Hugging Face模型创建嵌入all-MiniLM-L6-v2。然后,我们将这些嵌入存储在FAISS向量存储中,这使我们能够根据查询快速检索类似的文本块。
实现检索和响应生成
接下来是令人兴奋的部分:将检索与语言生成结合起来!现在,您将创建一个RAG 链,从 vectorstore 获取相关块并使用语言模型生成响应。(vectorstore 是一个数据库,我们将转换为数字的数据作为向量存储在其中)
1. 创建rag_chain.py
让我们创建文件rag_chain.py:
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI, Gemini, Fireworks
from dotenv import load_dotenv
import os
load_dotenv()
class RAGChain:
def __init__(self, vectorstore):
self.vectorstore = vectorstore
self.llm = self.get_llm()
def get_llm(self):
if os.getenv("OPENAI_API_KEY"):
return OpenAI(api_key=os.getenv("OPENAI_API_KEY"), temperature=0)
elif os.getenv("GEMINI_API_KEY"):
return Gemini(api_key=os.getenv("GEMINI_API_KEY"), temperature=0)
elif os.getenv("FIREWORKS_API_KEY"):
return Fireworks(api_key=os.getenv("FIREWORKS_API_KEY"), temperature=0)
else:
raise ValueError("No valid API key found! Please set one in .env file.")
def create_chain(self):
retriever = self.vectorstore.as_retriever(search_kwargs={"k": 3})
qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
return qa_chain
if __name__ == "__main__":
from document_processor import DocumentProcessor
from embedding_indexer import EmbeddingIndexer
processor = DocumentProcessor("data/sample_text.txt")
texts = processor.load_and_split()
indexer = EmbeddingIndexer()
vectorstore = indexer.create_vectorstore(texts)
rag_chain = RAGChain(vectorstore)
qa_chain = rag_chain.create_chain()
query = "What is the capital of France?"
result = qa_chain({"query": query})
print(f"Answer: {result['result']}")
在这里,我们根据您提供的 API 密钥为您提供OpenAI、Gemini或Fireworks之间的选择。RAG 链将检索前 3 个最相关的文档并使用语言模型生成响应。
您可以根据预算或使用偏好在模型之间切换 – Gemini和Fireworks是免费的,而OpenAI则根据使用情况收费。
构建聊天机器人界面
现在,我们将构建一个简单的聊天机器人界面,以接受用户输入并使用我们的 RAG 链生成响应。
1. 创建chatbot.py
class Chatbot:
def __init__(self, qa_chain):
self.qa_chain = qa_chain
def get_response(self, user_input):
try:
response = self.qa_chain({"query": user_input})
return response['result']
except Exception as e:
return f"An error occurred: {str(e)}"
if __name__ == "__main__":
from rag_chain import RAGChain
from document_processor import DocumentProcessor
from embedding_indexer import EmbeddingIndexer
processor = DocumentProcessor("data/sample_text.txt")
texts = processor.load_and_split()
indexer = EmbeddingIndexer()
vectorstore = indexer.create_vectorstore(texts)
rag_chain = RAGChain(vectorstore)
qa_chain = rag_chain.create_chain()
chatbot = Chatbot(qa_chain)
while True:
user_input = input("You: ")
if user_input.lower() in ['exit', 'quit', 'bye']:
print("Chatbot: Goodbye!")
break
response = chatbot.get_response(user_input)
print(f"Chatbot: {response}")
该脚本创建一个命令行聊天机器人界面,持续监听用户输入,通过 RAG 链处理,并返回生成的响应。
创建Streamlit UI
1. 创建app.py
import streamlit as st
from document_processor import DocumentProcessor
from embedding_indexer import EmbeddingIndexer
from rag_chain import RAGChain
from chatbot import Chatbot
@st.cache_resource
def initialize_chatbot(file_path):
processor = DocumentProcessor(file_path)
texts = processor.load_and_split()
indexer = EmbeddingIndexer()
vectorstore = indexer.create_vectorstore(texts)
rag_chain = RAGChain(vectorstore)
return Chatbot(rag_chain.create_chain())
st.title("RAG Chatbot")
uploaded_file = st.file_uploader("Upload a text file for the knowledge base", type="txt")
if uploaded_file:
with open("temp_knowledge_base.txt", "wb") as f:
f.write(uploaded_file.getbuffer())
chatbot = initialize_chatbot("temp_knowledge_base.txt")
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
st.chat_message(message["role"]).markdown(message["content"])
if prompt := st.chat_input("Ask a question"):
st.chat_message("user").markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
response = chatbot.get_response(prompt)
st.chat_message("assistant").markdown(response)
st.session_state.messages.append({"role": "assistant", "content": response})
else:
st.write("Please upload a text file to start chatting!")
2.运行Streamlit应用程序
streamlit run app.py
这将启动一个网络界面,您可以在其中上传文本文件、提出问题并从聊天机器人那里获得答案。
优化性能
为了获得更好的性能,您可以在拆分文本时尝试不同的块大小和重叠。较大的块可提供更多上下文,但较小的块可能会加快检索速度。您还可以使用Streamlit 缓存来避免重复生成嵌入等昂贵的操作。
如果您想优化成本,您可以根据查询复杂度在OpenAI、Gemini或Fireworks之间切换 -对于复杂问题使用OpenAI ,对于简单问题使用Gemini或Fireworks以降低成本。
恭喜!您已成功创建自己的基于 RAG 的聊天机器人。
作者:小袁在上班