LLM之RAG实战(十九)| 利用LangChain、OpenAI、ChromaDB和Streamlit构建RAG

生成式人工智能凭借其在处理与上下文相关的信息时的能力,彻底革新了技术领域,并开启了人工智能发展的新纪元。该技术的核心在于检索增强生成(RAG)模型,在整合信息检索技术和大型语言模型(LLM)的基础上,在外部文档中实现智能化且具有深刻理解能力的回应机制。
本文旨在全面探讨基于ChromaDB构建RAG驱动的LLM应用程序,并对该数据库在其处理大型数据集方面的卓越性能进行详细研究。
一、环境准备
要构建基于RAG的LLM应用程序,需要准备如下环境配置:
- Python安装地址如下:
https://www.python.org/downloads/ - OpenAI平台API密钥获取链接如下:
https://platform.openai.com/signup
以及对Python和web API的基本理解。
二、代码实现
2.1 创建并导航到项目目录
在终端中,创建一个新目录并导航到该目录:
mkdir rag_lmm_applicationcd rag_lmm_application
2.2 创建虚拟环境
虚拟环境可以隔离不同的python环境,创建命令如下所示:
python -m venv venv
激活虚拟环境。对于Mac/Linux用户,请使用:
source venv/bin/activate
对于Windows用户:
venv\Scripts\activate
2.3 安装所需的包
安装基本库:
pip install -r requirements.txt
PS:确保requirements.txt文件中包含所有必要的依赖项。
按照前面所述的方法,在前述方法的基础上
2.4 加载和处理文档
使用LangChain导入不同文档格式(如PDF、DOCX和TXT),这旨在保证外部数据的可访问性并确保高效的数据处理流程;同时为后续阶段提供统一的数据准备环境具有不可或缺的作用
# loading PDF, DOCX and TXT files as LangChain Documentsdef load_document(file): import os name, extension = os.path.splitext(file) if extension == '.pdf': from langchain.document_loaders import PyPDFLoader print(f'Loading {file}') loader = PyPDFLoader(file) elif extension == '.docx': from langchain.document_loaders import Docx2txtLoader print(f'Loading {file}') loader = Docx2txtLoader(file) elif extension == '.txt': from langchain.document_loaders import TextLoader loader = TextLoader(file) else: print('Document format is not supported!') return None data = loader.load() return data
在数据处理过程中进行合理的分块对于提升RAG系统的性能至关重要。将数据按照特定规则进行划分和整理后能够便于后续的向量化处理。通过这样的处理方式能够有效提升模型在复杂文档环境下的检索效率。代码如下:
# splitting data in chunksdef chunk_data(data, chunk_size=256, chunk_overlap=20): from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap) chunks = text_splitter.split_documents(data) return chunks
2.5 使用OpenAI和ChromaDB创建嵌入
基于OpenAI的大模型生成嵌入数据,则这些数据被有效地存储于ChromaDB中。从而实现信息的快速检索。
# create embeddings using OpenAIEmbeddings() and save them in a Chroma vector storedef create_embeddings(chunks): embeddings = OpenAIEmbeddings() vector_store = Chroma.from_documents(chunks, embeddings) # if you want to use a specific directory for chromadb # vector_store = Chroma.from_documents(chunks, embeddings, persist_directory='./mychroma_db') return vector_store
2.6 使用Streamlight构建聊天界面
我们的RAG LLM应用程序充分展现了Streamlit技术的独特魅力,在提升用户体验方面发挥了显著作用。借助Streamlit的初始化配置和整体架构设计, 我们能够方便地接收文件并有效地管理数据来源。系统接收并处理这些文件内容, 然后实时生成相应的结果展示, 从而实现了前端操作与后台处理之间的高效协同工作。以下是一个具体的设置示例:
def ask_and_get_answer(vector_store, q, k=3): from langchain.chains import RetrievalQA from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model='gpt-3.5-turbo', temperature=1) retriever = vector_store.as_retriever(search_type='similarity', search_kwargs={'k': k}) chain = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=retriever) answer = chain.run(q) return answer# calculate embedding cost using tiktokendef calculate_embedding_cost(texts): import tiktoken enc = tiktoken.encoding_for_model('text-embedding-ada-002') total_tokens = sum([len(enc.encode(page.page_content)) for page in texts]) # print(f'Total Tokens: {total_tokens}') # print(f'Embedding Cost in USD: {total_tokens / 1000 * 0.0004:.6f}') return total_tokens, total_tokens / 1000 * 0.0004# clear the chat history from streamlit session statedef clear_history(): if 'history' in st.session_state: del st.session_state['history']if __name__ == "__main__": import os # loading the OpenAI api key from .env from dotenv import load_dotenv, find_dotenv load_dotenv(find_dotenv(), override=True) st.image('img.png') st.subheader('LLM Question-Answering Application 🤖') with st.sidebar: # text_input for the OpenAI API key (alternative to python-dotenv and .env) api_key = st.text_input('OpenAI API Key:', type='password') if api_key: os.environ['OPENAI_API_KEY'] = api_key # file uploader widget uploaded_file = st.file_uploader('Upload a file:', type=['pdf', 'docx', 'txt']) # chunk size number widget chunk_size = st.number_input('Chunk size:', min_value=100, max_value=2048, value=512, on_change=clear_history) # k number input widget k = st.number_input('k', min_value=1, max_value=20, value=3, on_change=clear_history) # add data button widget add_data = st.button('Add Data', on_click=clear_history) if uploaded_file and add_data: # if the user browsed a file with st.spinner('Reading, chunking and embedding file ...'): # writing the file from RAM to the current directory on disk bytes_data = uploaded_file.read() file_name = os.path.join('./', uploaded_file.name) with open(file_name, 'wb') as f: f.write(bytes_data) data = load_document(file_name) chunks = chunk_data(data, chunk_size=chunk_size) st.write(f'Chunk size: {chunk_size}, Chunks: {len(chunks)}') tokens, embedding_cost = calculate_embedding_cost(chunks) st.write(f'Embedding cost: ${embedding_cost:.4f}') # creating the embeddings and returning the Chroma vector store vector_store = create_embeddings(chunks) # saving the vector store in the streamlit session state (to be persistent between reruns) st.session_state.vs = vector_store st.success('File uploaded, chunked and embedded successfully.')
上面的代码展示了如何在Streamlit平台中生成文本输入字段,并实现数据接收和处理。采用这种方式后,用户能够更加直接且方便地与人工智能应用程序进行连接或交流。
2.7 检索答案和增强用户交互
我们的RAG聊天系统主要依赖于LangChain的RetrievalQA组件以及ChromaDB数据库,在ChromaDB存储的嵌入式数据中获取高质量的相关信息,并能够高效地处理用户的查询请求。该系统展现了强大的生成式人工智能技术能力
下面的代码片段展示了Streamlit应用程序的实现:
# user's question text input widget q = st.text_input('Ask a question about the content of your file:') if q: # if the user entered a question and hit enter if 'vs' in st.session_state: # if there's the vector store (user uploaded, split and embedded a file) vector_store = st.session_state.vs st.write(f'k: {k}') answer = ask_and_get_answer(vector_store, q, k) # text area widget for the LLM answer st.text_area('LLM Answer: ', value=answer) st.divider() # if there's no chat history in the session state, create it if 'history' not in st.session_state: st.session_state.history = '' # the current question and answer value = f'Q: {q} \nA: {answer}' st.session_state.history = f'{value} \n {"-" * 100} \n {st.session_state.history}' h = st.session_state.history # text area widget for the chat history st.text_area(label='Chat History', value=h, key='history', height=400)
该代码集成了与Streamlit集成的用户输入和响应生成功能。通过ChromaDB提供的矢量数据搜索技术可以实现精准查询结果,并且能够有效提升检索效率与准确性。从而提升了聊天应用程序的互动体验,并实现了信息丰富且具有智能化深度的人工智能对话。
三、结论
本文深入分析了利用OpenAI、ChromaDB和Streamlit构建大型语言模型(LLM)系统的复杂性问题。具体介绍了系统环境配置、文档处理流程以及内容向量化模型的构建过程,并实现了数据存储机制。重点展示了易于使用的对话界面模块的开发情况,并探讨了RAG技术与ChromaDB的强大结合。
要运行应用程序,请在终端中执行以下命令:
streamlit run ./chat_with_documents.py
现在,可以通过导航到http://localhost:8501来测试该应用程序。
