본문 바로가기
Natural Language Processing

[SeSac] LangChain 6 - RAG(Retrieval-Augmented Generation)

by 자몽먹은토끼 2024. 7. 15.
728x90
반응형
!pip install -q pypdf
!pip install -q langchain_community
!pip install chromadb
import os
os.environ['OPENAI_API_KEY'] = 'OPENAI_API_KEY'
문서 로드
from langchain_community.document_loaders import PyPDFLoader

pdf_filepath = 'disable.pdf'
loader = PyPDFLoader(pdf_filepath)
pages = loader.load()

# document 객체의 개수
len(pages)

 

 

텍스트 분리
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 300,
    chunk_overlap  = 30,
    length_function = len,
)

splits= text_splitter.split_documents(pages)
# texts= text_splitter.split_text(pages[0].page_content)

len(texts)

 

 

임베딩 및 벡터 저장소
# Indexing (Texts -> Embedding -> Store)
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_community.embeddings import HuggingFaceEmbeddings

# 허깅페이스 모델 사용시
# embeddings_model = HuggingFaceEmbeddings(
#     model_name='jhgan/ko-sroberta-nli',    # 한국어 자연어 추론(Natural Language Inference, NLI)에 최적화된 ko-sroberta 모델
#     model_kwargs={'device':'cpu'},         # 'cuda' 로 변경 가능
#     encode_kwargs={'normalize_embeddings':True},# 임베딩을 정규화하여 모든 벡터가 같은 범위의 값을 갖도록 
# )


# vectorstore = Chroma.from_texts(texts=texts,
#                                     embedding=OpenAIEmbeddings())

vectorstore = Chroma.from_documents(documents=splits,
                                    embedding=OpenAIEmbeddings())

 

 

검색 및 생성
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

# Prompt
template = '''Answer the question based only on the following context:
{context}

Question: {question}
'''

prompt = ChatPromptTemplate.from_template(template)

# LLM
model = ChatOpenAI(model='gpt-3.5-turbo-0125', temperature=0)

# Rretriever
retriever = vectorstore.as_retriever()

# Combine Documents
def format_docs(dd):
    return '\n\n'.join(doc.page_content for doc in dd)

# RAG Chain 연결
rag_chain = (
    {'context': retriever | format_docs, 'question': RunnablePassthrough()}
    | prompt
    | model
    | StrOutputParser()
)

# Chain 실행
rag_chain.invoke("장애가 유전인가요?")

> 사용자의 질문(question)을 기반으로 retriever를 통해 관련된 문맥을 vectorstore에서 추출한다.

 

 

- 명시적 할당 없음: context 변수에 명시적으로 값이 할당되지 않았을 때, retriever는 전체 입력 데이터를 이용하여 필요한 값을 추출합니다.
- 자동 데이터 추출: LangChain은 입력 데이터에서 필요한 값을 자동으로 추출하여 적절한 컴포넌트에 전달합니다.
- 체인 구성: 체인의 각 구성 요소는 입력 데이터의 특정 필드를 명시적으로 할당받지 못하더라도, 전체 입력 데이터를 기반으로 필요한 값을 추출할 수 있습니다.

>> 따라서, retriever와 같은 컴포넌트는 체인 구성에서 명시적으로 할당된 값이 없더라도, 전체 입력 데이터를 활용하여 적절한 작업을 수행합니다. 이는 LangChain의 유연한 데이터 흐름 처리 방식 덕분입니다.
만약 명시적 할당이 된 변수가 두개 이상이라면, 그 중에 어떤 변수의 값을 retriever로 가져갈 것인가?

>> context변수가 명시적으로 정의되지 않았다면, LangChain은 retriever에 전달할 문맥을 유추하기 위해 모든 입력 데이터를 종합적으로 사용할 수 있습니다. LangChain은 입력 데이터를 분석하고 각 구성 요소에 필요한 값들을 동적으로 할당함으로써 유연성을 제공합니다. 이는 프롬프트에서 필요한 변수들을 명시적으로 모두 지정하지 않아도, LangChain이 적절히 동작할 수 있도록 합니다.
728x90
반응형