목차
서론
지난 포스팅에서는 API를 통한 llm 셋팅에 대해서 알아보았다. 이번엔 LangChain을 이용한 RAG 구성에 대해 알아보고자 한다. 이를 위해 langchain은 어떤것인지 알아보고 코드와 함께 결과에 대해 알아보고자 한다.
LangChain이란?
지난 포스팅에서는 API를 통한 llm 셋팅에 대해서 알아보았다. 이번엔 LangChain을 이용한 RAG 구성에 대해 코드와 함께 알아보고자 한다. Langchain은 자체 DB가 있어서 별도 코드 작성 필요 없이 깔끔하게 할 수 있다는 장점이 있다. 프롬프트도 디폴트로하기에 따로 작성하지 않아도 된다. LangChain이 없다면 모든걸 다 직접 작성해야된다고 한다. 문서파싱, 청킹, 임베딩, 질문 다 직접 넘겨야되며, 패키지도 많다. 이 포스팅을 보다보면 embedding = OpenAIEmbeddings(model = 'text-embedding-3-large') <<< 이런 걸 선언하는 과정에서 "..? 내가 다 하는거 같은데?" 라고 생각하겠지만, 그게 langchain이 해주는거라고 보면된다. 다 걔가 지원해 주는 도구라니까....
본 포스팅은 크게 네가지 과정이 있다. 사실 2+3이 한 단락이니 정말 크게보면 3가지 스텝임.
1. 문서의 내용을 읽고, 문서를 쪼갠다.
쪼개는 이유는 1) 토큰수 초과로 답변 생성 못할 수 있고, 2) 문서가 길면 답변 생성이 오래 걸리기 때문.
2. 쪼갠 문서를 임베딩해서, 벡터 데이터 베이스에 저장한다.
3. 질문이 있으면, 벡터 데이터 베이스에서 유사도 검색.
4. 유사도 검색으로 가져온 문서롤 LLM에 질문과 같이 전달.
1. 문서를 읽고 쪼개는 과정.
문서 내용 읽는 건 document loader를 사용할 것임. 그런데,
loader = Docx2txtLoader('./읽을워드파일.docx')
document = loader.load()
단순 이렇게 하면 document의 길이가 1이게 된다. 이걸 text_splitters를 사용해서 쪼개야 됨을 의미한다. langchain-text-splitters를 설치한 뒤, 아래와 같이 스플리터를 만든다. 참고로 splitter는 reculsive랑 character splitter가 자주 쓰이는데, 후자는 구분자를 하나밖에 못넣음. 근데 reculsive는 list로 구분자를 넣기에, 이게 더 성능이 좋다고 한다.
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 1500, # 청크 하나가 갖는 토큰 수
chunk_overlap= 200, # 청크끼리 겹치는 정도 - overlap으로 유사도 검색시 원하는 문서를 가질 수 있는 확률을 높이는 역할을 한다.
)
loader = Docx2txtLoader('./워드파일.docx')
document = loader.load_and_split(text_splitter=text_splitter)
이후 len(document)를 하면 1이 아닌 숫자가 나오는걸 볼 수 있다. 하나의 리스트가 된 셈이다.
2. 쪼갠 문서를 임베딩해서, 벡터 데이터 베이스에 저장한다. 3. 질문이 있으면, 벡터 데이터 베이스에서 유사도 검색.
이제 위에서 쪼갠 문서를 임베딩 할 차례다. 이 과정을 모르면 첫 포스팅에 설명이 되어있다. 거기에 대해 알고 싶다면 여기로 가면 된다.
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings(model = 'text-embedding-3-large')
#디폴트 값(얘도 한국어 지원함)보단 'text-embedding-3-large'가 성능이 더 좋다고 한다.
아무튼 임베딩을 하기 위해 openai의 임베딩을 사용할 것이다. 임베딩한 걸 벡터db에 넣을 차례인 것이다. %pip install langchain-chroma를 통해 크로마를 설치하고,
from langchain_chroma import Chroma
database = Chroma.from_documents(documents = document, embedding = embedding)
다음과 같이 선언해서 데이터 베이스를 선언한다. 이 과정이 우리가 쪼개놓은 리스트를 임베딩을 활용해서 저장하는 중인것이다. 이후 retrived_docs = database.similarity_search('질문') 을 선언하면 유사도 검색을 한다. 데이터 베이스에서 질문과 가장 유사한 것들을 찾아내는 과정인 것이다.
4. 유사도 검색으로 가져온 문서롤 LLM에 질문과 같이 전달.
마지막 스텝이다. 크게 세가지 스텝인데 1)openai 모델을 설정한다. 2) 유사도 검색으로 가져온 retrived_docs를 프롬프트에 넣는다. 3) invoke를 통해서 답변을 가져온다. 해당 과정은 아래와 같다.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model='gpt-4o')
prompt = f"""[Identity]
- 당신은 최고의 ㅇㅇㅇ 입니다.
- [Context]를 참고해서 사용자의 질문에 답변해주세요.
[Context]
{retrived_docs}
Question:{query}
"""
print(llm.invoke(prompt))
만약에 위 코드가 되지 않는다면,
API_KEY를 넣지 않아서라고 판단된다. 알아서 해결하고 오시길.. 이건 내가 해줄수가 없다. https://wikidocs.net/231180 이렇게 하기도 하고, 난 dotenv를 사용해서한다. '.env'파일에 api key를 넣어둔 뒤, load_dotenv()를 선언하는 것이다. 보통 파라미터에 api_key = 'your-api-key' 이렇게 하면 되던데 얘네는 또 모르겠다. 아마 될 듯.
끝으로
다음 포스팅에서는 retrieval을 효과적으로 활용하기 위해 langchain hub를 사용할 예정이다.지난 포스팅을 보려면 여기로 https://quiseol.com/entry/RAG-2
'IT, Computer' 카테고리의 다른 글
티스토리 블로그 애드센스 수익 여정 포스팅 (8) 가치가 없는 콘텐츠 문제 해결 (0) | 2024.11.16 |
---|---|
티스토리 블로그 애드센스 수익 여정 포스팅 (7) (2) | 2024.11.15 |
Retrieval Augmented Generation(RAG) 복습 (2) Gemini API 사용 방법 (0) | 2024.11.08 |
OpenAI Error code: 429 - {'error': {'message': 'You exceeded your current quota 해결 방법 (0) | 2024.11.07 |
Retrieval Augmented Generation(RAG) 복습 (1) RAG의 개념 (2) | 2024.10.21 |