OpenAI의 ChatGPT와 같은 생성 AI 모델의 급속한 발전으로 자연어 처리에 혁명이 일어나 이러한 시스템이 일관되고 상황에 맞는 응답을 생성할 수 있게 되었습니다. 그러나 최첨단 모델이라 할지라도 도메인별 쿼리를 처리하거나 매우 정확한 정보를 제공하는 데에는 한계가 있습니다. 이는 모델이 부정확하거나 조작된 세부 정보를 생성하는 경우인 환각과 같은 문제로 이어지는 경우가 많습니다.
이러한 격차를 해소하기 위해 설계된 혁신적인 프레임워크인 검색 증강 생성(RAG)입니다. RAG는 외부 데이터 소스를 완벽하게 통합함으로써 생성 모델이 실시간 틈새 정보를 검색할 수 있도록 지원하여 정확성과 신뢰성을 크게 향상시킵니다.
이 기사에서는 RAG의 메커니즘을 자세히 알아보고, 아키텍처를 탐구하며, RAG 제작에 영감을 준 기존 생성 모델의 한계에 대해 논의합니다. 또한 실제 구현, 고급 기술 및 평가 방법을 강조하여 RAG가 AI가 전문 데이터와 상호 작용하는 방식을 어떻게 변화시키고 있는지 보여줄 것입니다.
검색 증강 생성(RAG)은 외부 데이터의 실시간 검색을 통합하여 생성 AI 모델의 기능을 향상시키는 고급 프레임워크입니다. 생성 모델은 일관되고 인간과 유사한 텍스트를 생성하는 데 탁월하지만 정확한 최신 정보 또는 도메인별 정보를 제공하라는 요청을 받으면 실패할 수 있습니다. RAG가 개입하여 응답이 창의적일 뿐만 아니라 신뢰할 수 있고 관련성이 높은 소스에 기반을 두도록 보장합니다.
RAG는 생성 모델을 일반적으로 벡터 데이터베이스 또는 검색 시스템으로 구동되는 검색 메커니즘과 연결하여 작동합니다. 쿼리가 수신되면 검색 구성 요소는 방대한 외부 데이터 세트를 검색하여 관련 정보를 가져옵니다. 그런 다음 생성 모델은 이 데이터를 합성하여 정확하고 상황에 맞는 통찰력을 갖춘 출력을 생성합니다.
환각 및 제한된 도메인 지식과 같은 주요 문제를 해결함으로써 RAG는 전문 분야에서 탁월한 생성 모델의 잠재력을 발휘합니다. 이 애플리케이션은 정확한 답변으로 고객 지원을 자동화하는 것부터 연구자가 필요에 따라 엄선된 지식에 액세스할 수 있도록 하는 등 다양한 산업에 걸쳐 있습니다. RAG는 실제 시나리오에서 AI 시스템을 더욱 지능적이고 신뢰할 수 있으며 유용하게 만드는 데 있어서 중요한 진전을 나타냅니다.
RAG 아키텍처에 대한 명확한 이해는 RAG 아키텍처의 잠재력과 이점을 최대한 활용하는 데 필수적입니다. 기본적으로 프레임워크는 정보 처리의 원활한 흐름에서 함께 작동하는 검색기와 생성기라는 두 가지 주요 구성 요소를 기반으로 구축되었습니다.
전체 프로세스는 다음과 같습니다.
출처: https://weaviate.io/blog/introduction-to-rag
아래 그림에 설명된 RAG 프로세스 흐름의 모든 단계와 필수 구성 요소가 나와 있습니다.
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm
문서를 더 작은 덩어리로 나누는 것은 간단해 보일 수 있지만 문장을 부적절하게 나누는 것을 방지하려면 의미론을 신중하게 고려해야 하며, 이는 질문 답변과 같은 후속 단계에 영향을 미칠 수 있습니다. 순진한 고정 크기 청킹 접근 방식은 각 청크에 불완전한 정보를 초래할 수 있습니다. 대부분의 문서 분할 알고리즘은 청크 크기와 겹침을 사용합니다. 여기서 청크 크기는 문자, 단어 또는 토큰 수에 따라 결정되며 겹침은 인접한 청크 간에 텍스트를 공유하여 연속성을 보장합니다. 이 전략은 청크 전반에 걸쳐 의미적 맥락을 보존합니다.
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm
중요한 벡터 데이터베이스 중 일부는 다음과 같습니다.
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm
RAG(Retrieval-Augmented Generation)와 미세 조정은 LLM 기능을 확장하는 두 가지 주요 방법이며 각각 서로 다른 시나리오에 적합합니다. 미세 조정에는 전문적인 작업을 수행하기 위해 도메인별 데이터에 대한 LLM 재교육이 포함되며, 이는 특정 톤이나 스타일이 필요한 브랜딩 또는 창의적 글쓰기와 같은 정적이고 좁은 사용 사례에 이상적입니다. 그러나 비용이 많이 들고 시간이 많이 걸리며 자주 업데이트되는 동적 데이터에는 적합하지 않습니다.
반면 RAG는 모델 가중치를 수정하지 않고 외부 데이터를 동적으로 검색하여 LLM을 향상시켜 비용 효율적이고 법률, 금융 또는 고객 서비스 애플리케이션과 같은 실시간 데이터 기반 환경에 이상적입니다. RAG를 사용하면 LLM이 구조화되지 않은 대규모 내부 문서 모음을 처리할 수 있어 지저분한 데이터 저장소를 탐색하는 기존 방법에 비해 상당한 이점을 제공합니다.
미세 조정은 미묘하고 일관된 출력을 생성하는 데 탁월한 반면, RAG는 외부 지식 기반을 활용하여 정확한 최신 정보를 제공합니다. 실제로 RAG는 실시간 적응형 응답이 필요한 애플리케이션, 특히 방대한 비정형 데이터를 관리하는 기업에서 선호되는 선택인 경우가 많습니다.
검색 증강 생성(RAG) 접근 방식에는 여러 유형이 있으며 각각 특정 사용 사례와 목표에 맞게 조정됩니다. 기본 유형은 다음과 같습니다.
출처: https://x.com/weaviate_io/status/1866528335884325070
검색 증강 생성(RAG) 프레임워크는 외부 지식을 생성 언어 모델에 동적으로 통합하는 기능으로 인해 다양한 산업 전반에 걸쳐 다양하게 적용됩니다. 다음은 몇 가지 주요 응용 프로그램입니다.
이 섹션에서는 PDF의 내용을 이해하고 RAG(Retrieval-Augmented Generation)를 사용하여 해당 내용을 기반으로 사용자 쿼리에 응답할 수 있는 효율적인 애플리케이션을 개발합니다. 구현에서는 LangChain 플랫폼을 활용하여 LLM 및 벡터 저장소와의 상호 작용을 촉진합니다. 효율적인 정보 검색을 위해 OpenAI의 LLM과 임베딩 모델을 활용하여 FAISS 벡터 저장소를 구축하겠습니다.
python -m venv venv source venv/bin/activate #for ubuntu venv/Scripts/activate #for windows
pip install langchain langchain_community openai faiss-cpu PyPDF2 streamlit python-dotenv tiktoken
OPENAI_API_KEY=sk-proj-xcQxBf5LslO62At... OPENAI_MODEL_NAME=gpt-3.5-turbo OPENAI_EMBEDDING_MODEL_NAME=text-embedding-3-small
from dotenv import load_dotenv import os load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME") OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME")
langchain, streamlit, pyPDF와 같은 PDF 처리 및 앱 구축을 위한 필수 라이브러리를 가져옵니다.
import streamlit as st from PyPDF2 import PdfReader from langchain.text_splitter import CharacterTextSplitter from langchain.prompts import PromptTemplate from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import FAISS from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationalRetrievalChain from langchain_community.chat_models import ChatOpenAI from htmlTemplates import bot_template, user_template, css
def get_pdf_text(pdf_files): text = "" for pdf_file in pdf_files: reader = PdfReader(pdf_file) for page in reader.pages: text += page.extract_text() return text
LangChain의 CharacterTextSplitter를 사용하여 큰 텍스트를 더 작고 관리 가능한 덩어리로 나눕니다.
def get_chunk_text(text): text_splitter = CharacterTextSplitter( separator="\n", chunk_size=1000, chunk_overlap=200, length_function=len ) chunks = text_splitter.split_text(text) return chunks
FAISS를 사용하여 텍스트 청크에 대한 임베딩을 생성하고 이를 벡터 데이터베이스에 저장합니다.
def get_vector_store(text_chunks): embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME) vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings) return vectorstore
벡터 저장소에서 정보를 검색하고 LLM을 통해 사용자와 상호작용하는 체인을 정의합니다.
def get_conversation_chain(vector_store): llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0) memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True) system_template = """ Use the following pieces of context and chat history to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. Context: {context} Chat history: {chat_history} Question: {question} Helpful Answer: """ prompt = PromptTemplate( template=system_template, input_variables=["context", "question", "chat_history"], ) conversation_chain = ConversationalRetrievalChain.from_llm( verbose = True, llm=llm, retriever=vector_store.as_retriever(), memory=memory, combine_docs_chain_kwargs={"prompt": prompt} ) return conversation_chain
사용자 입력을 처리하여 대화 체인에 전달하고 채팅 기록을 업데이트합니다.
def handle_user_input(question): try: response = st.session_state.conversation({'question': question}) st.session_state.chat_history = response['chat_history'] except Exception as e: st.error('Please select PDF and click on Process.')
CSS를 사용하여 사용자와 봇 메시지 모두에 대한 맞춤 채팅 인터페이스를 만들려면 맞춤 템플릿을 디자인하고 CSS로 스타일을 지정하세요.
css = ''' <style> .chat-message { padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem; display: flex } .chat-message.user { background-color: #2b313e } .chat-message.bot { background-color: #475063 } .chat-message .avatar { width: 10%; } .chat-message .avatar img { max-width: 30px; max-height: 30px; border-radius: 50%; object-fit: cover; } .chat-message .message { width: 90%; padding: 0 1rem; color: #fff; } ''' bot_template = ''' <div> <h3> Displaying chat history </h3> <p>Show the user and AI conversation history in a reverse order with HTML templates for formatting.<br> </p> <pre class="brush:php;toolbar:false">def display_chat_history(): if st.session_state.chat_history: reversed_history = st.session_state.chat_history[::-1] formatted_history = [] for i in range(0, len(reversed_history), 2): chat_pair = { "AIMessage": reversed_history[i].content, "HumanMessage": reversed_history[i + 1].content } formatted_history.append(chat_pair) for i, message in enumerate(formatted_history): st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True) st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True)
파일 업로드, 질문 입력, 채팅 기록 표시를 위한 기본 앱 인터페이스를 설정합니다.
def main(): st.set_page_config(page_title='Chat with PDFs', page_icon=':books:') st.write(css, unsafe_allow_html=True) if "conversation" not in st.session_state: st.session_state.conversation = None if "chat_history" not in st.session_state: st.session_state.chat_history = None st.header('Chat with PDFs :books:') question = st.text_input("Ask anything to your PDF:") if question: handle_user_input(question) if st.session_state.chat_history is not None: display_chat_history() with st.sidebar: st.subheader("Upload your Documents Here: ") pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True) if pdf_files and st.button("Process"): with st.spinner("Processing your PDFs..."): try: # Get PDF Text raw_text = get_pdf_text(pdf_files) # Get Text Chunks text_chunks = get_chunk_text(raw_text) # Create Vector Store vector_store = get_vector_store(text_chunks) st.success("Your PDFs have been processed successfully. You can ask questions now.") # Create conversation chain st.session_state.conversation = get_conversation_chain(vector_store) except Exception as e: st.error(f"An error occurred: {e}") if __name__ == '__main__': main()
다음은 PDF 채팅 애플리케이션의 전체 코드 구현입니다. 환경 변수 설정, 텍스트 추출, 벡터 저장 및 RAG 기능을 간소화된 솔루션에 통합합니다.
from dotenv import load_dotenv import os load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME") OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME") import streamlit as st from PyPDF2 import PdfReader from langchain.text_splitter import CharacterTextSplitter from langchain.prompts import PromptTemplate from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import FAISS from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationalRetrievalChain from langchain_community.chat_models import ChatOpenAI from htmlTemplates import bot_template, user_template, css def get_pdf_text(pdf_files): text = "" for pdf_file in pdf_files: reader = PdfReader(pdf_file) for page in reader.pages: text += page.extract_text() return text def get_chunk_text(text): text_splitter = CharacterTextSplitter( separator="\n", chunk_size=1000, chunk_overlap=200, length_function=len ) chunks = text_splitter.split_text(text) return chunks def get_vector_store(text_chunks): embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME) vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings) return vectorstore def get_conversation_chain(vector_store): llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0) memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True) system_template = """ Use the following pieces of context and chat history to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. Context: {context} Chat history: {chat_history} Question: {question} Helpful Answer: """ prompt = PromptTemplate( template=system_template, input_variables=["context", "question", "chat_history"], ) conversation_chain = ConversationalRetrievalChain.from_llm( verbose = True, llm=llm, retriever=vector_store.as_retriever(), memory=memory, combine_docs_chain_kwargs={"prompt": prompt} ) return conversation_chain def handle_user_input(question): try: response = st.session_state.conversation({'question': question}) st.session_state.chat_history = response['chat_history'] except Exception as e: st.error('Please select PDF and click on OK.') def display_chat_history(): if st.session_state.chat_history: reversed_history = st.session_state.chat_history[::-1] formatted_history = [] for i in range(0, len(reversed_history), 2): chat_pair = { "AIMessage": reversed_history[i].content, "HumanMessage": reversed_history[i + 1].content } formatted_history.append(chat_pair) for i, message in enumerate(formatted_history): st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True) st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True) def main(): st.set_page_config(page_title='Chat with PDFs', page_icon=':books:') st.write(css, unsafe_allow_html=True) if "conversation" not in st.session_state: st.session_state.conversation = None if "chat_history" not in st.session_state: st.session_state.chat_history = None st.header('Chat with PDFs :books:') question = st.text_input("Ask anything to your PDF:") if question: handle_user_input(question) if st.session_state.chat_history is not None: display_chat_history() with st.sidebar: st.subheader("Upload your Documents Here: ") pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True) if pdf_files and st.button("Process"): with st.spinner("Processing your PDFs..."): try: # Get PDF Text raw_text = get_pdf_text(pdf_files) # Get Text Chunks text_chunks = get_chunk_text(raw_text) # Create Vector Store vector_store = get_vector_store(text_chunks) st.success("Your PDFs have been processed successfully. You can ask questions now.") # Create conversation chain st.session_state.conversation = get_conversation_chain(vector_store) except Exception as e: st.error(f"An error occurred: {e}") if __name__ == '__main__': main()
다음 명령을 사용하여 Streamlit으로 앱을 실행합니다.
streamlit run app.py
다음과 같이 출력됩니다.
이 글을 읽어주셔서 감사합니다!!
콘텐츠를 검토해 주신 Gowri M Bhatt에게 감사드립니다.
이 기사가 마음에 드셨다면 하트 버튼♥을 눌러 다른 사람들이 찾을 수 있도록 공유해주세요!
이 튜토리얼의 전체 소스 코드는 여기에서 확인할 수 있습니다.
codemaker2015/pdf-chat-using-RAG | github.com
위 내용은 검색 증강 생성(RAG)에 대한 궁극적인 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!