Search
Duplicate
🐥

ChatGPT에게 내 논문을 가르치자 - Langchain을 활용한 간단한 retrieval-augmented generation (RAG)

어느날 ChatGPT가 내 논문의 내용을 알고 있을지 궁금해져서, ChatGPT에게 “Chromoformer가 뭐야?” 라고 물어보았다. (Chromoformer는 히스톤 코드와 유전자 발현량 사이의 관계를 모델링한 필자의 연구에서 만들어진 모델 이름이다.)
from langchain_openai import ChatOpenAI OPENAI_API_KEY = "..." # 발급받아서 채워넣자. llm = ChatOpenAI(mobdel_name='gpt-4o-mini', temperature=0, api_key=OPENAI_API_KEY) llm.invoke("What is chromoformer?")
Python
복사
참고) 위 코드를 실행하기 위한 패키지 설치 사전 준비
돌아오는 답변은 역시 시원찮았다.
As of my last knowledge update in October 2023, "chromoformer" does not appear to be a widely recognized term in scientific literature or common usage. It is possible that it could refer to a specific concept, technology, or product that has emerged more recently or is niche in nature. If you meant "chromoformer" in a specific context, such as a scientific field (like genetics, biochemistry, or materials science), or if it is a brand name or a term from a particular industry, please provide more details. This will help me give you a more accurate and relevant response.
Plain Text
복사
정리하면 “2023년 10월 기준으로 그런 모델은 없거나, 널리 알려져 있지는 않다” 라는 거다. 2022년 10월에 출판된 논문이지만, 워낙 세부적인 분야의 논문이다보니 학습 데이터에 포함되어 있지 않았거나, 학습이 되었다고 해도 이를 다시 불러오지 못하고 있다고 추측해볼 수 있다.

Retrieval-augmented generation (RAG)

위 예와 같이, ChatGPT에게 조금 지엽적인 분야의 질문을 던지면 대개 그리 만족스러운 답변을 얻지 못한다. 하지만 다행히 ChatGPT는 꽤 좋은 이해력을 가지고 있어서, 모델이 학습될 때는 접하지 못한 분야라 할지라도 모델에게 쿼리를 날릴 때 (질문을 할 때) 적절한 사전 정보를 함께 제공하기만 하면 비교적 만족스러운 답변을 준다고 알려져 있다. 이러한 패러다임을 retrieval-augmented generation (RAG)라 부르며, 보다 질 좋은 답변을 얻고자 할 때나, 사내 문서 등 지엽적이거나 보안 유지가 중요한 시스템에서 LLM을 활용하고자 할 때 사용하곤 한다.

Langchain을 활용한 PDF 기반 RAG

RAG의 개념을 이해했으니, 이제 어떻게 모델에게 “적절한 사전 정보”를 전달하는지 알아보자. 필자의 경우에는 필자의 논문 내에 사전 정보들이 존재하고 있을 것이고, 이 논문은 PDF (혹은 저널 웹사이트의 HTML) 형태로 웹 상에 존재하고 있다. 여기서는 PDF 기반의 RAG를 시도해보고자 한다.
논문 PDF 파일의 URL을 입력으로 넣어서, 어떻게든 거기서 적절한 사전 정보를 추출한 다음 좋은 답변을 내놓을 수 있다면 아주 간단하고 좋을 것이다. 고맙게도 langchain을 활용하면 이 모든 작업을 코드 몇 줄로 해결할 수 있다!

사전 준비

모델에 추가적으로 제공될 사전 정보들이 포함된 문서를 langchain에서는 Document 라 부르며, 다양한 형태의 문서들을 파싱하여 불러올 수 있게 다양한 DocumentLoader 들이 존재한다. 여기서 우리는 PyPDFLoader를 활용할 것이다. (어떤 포맷의 문서를 활용할 수 있는지 더 알아보려면 langchain 공식 문서를 참고하자)
PyPDFLoader를 사용하기 위해서는 아래 패키지를 추가적으로 설치해주어야 한다.
$ pip install pypdf
Bash
복사

Document loading

설치가 되었다면, 아래를 실행해서 논문 PDF 파일을 파싱하자.
from langchain_community.document_loaders import PyPDFLoader # link to my paper url = 'https://www.nature.com/articles/s41467-022-34152-5.pdf' loader = PyPDFLoader(url) docs = loader.load() # len(docs) = 19 (= # PDF pages of my paper)
Python
복사
그 결과, 19개의 Document object로 구성된 리스트가 반환된다. 필자의 논문 페이지 수가 총 19페이지인 것으로 미루어 볼 때, loader는 PDF를 페이지 단위로 문서화하고 있음을 알 수 있다.
어쨌거나 사전 정보의 뭉치를 PDF 링크 하나만을 이용하여 아주 쉽게 얻는 데에 성공했다!

Embedding

이제 사용자의 질문에 ‘적절한’ 사전 정보를 골라 오는 로직을 고민해 보아야 한다. 즉, 입력 질문과 가장 관련이 있는 정보를 문서에서 찾아내는 방법이 필요하다. RAG에서는 입력 질문과 문서를 같은 embedding 공간에 투영한 뒤 유사도를 측정하는 방법을 취하는데, 이 역시 매우 간단히 구현이 가능하다. 문서의 embedding을 사전에 모아 놓은 집합을 ‘vector store’라 한다. Chroma 기반의 vector store를 활용하기 위해서는 아래 패키지의 추가 설치가 필요하다. (Chroma 외에도, FAISS 등 vector store를 위한 다른 옵션도 존재한다. 더 알아보기)
$ pip install langchain-chroma
Bash
복사
이제 준비가 끝났다. 아래 코드를 이용하여 OpenAI의 embedding 모델을 이용하여 문서를 vector store화 시킬 수 있다.
from langchain_openai import OpenAIEmbeddings from langchain.vectorstores import Chroma embeddings_model = OpenAIEmbeddings(api_key=OPENAI_API_KEY) db = Chroma.from_documents(docs, embeddings_model)
Python
복사

Retriever

이제 이렇게 구축된 vector store 내에서, 사용자의 질문과 가장 유사한 문서를 골라서 내놓은 뒤 (retrieve) 이를 바탕으로 답변을 하게 하면 될 것이다. langchain에서는 아래처럼 vector store 오브젝트 자체를 “retriever”로써 활용할 수 있게 쉽게 구현해 두었다.
관련 정보를 잘 찾아낼 수 있는지 테스트해보기 위해, “What is chromoformer?”라는 질문과 유사한 문서들이 어떻게 뽑히는지 알아보자.
retriever = db.as_retriever() query = "What is chromoformer?" context_docs = retriever.get_relevant_documents(query) # len(context_docs) = 4
Python
복사
총 19개의 페이지 중 4개 페이지로 관련 정보들을 추려냈음을 확인할 수 있다. 실제로 어떤 페이지들이 선택되었는지 알기 위해서는, context_docs 내의 각 document의 metadata를 확인하면 된다.
[doc.metadata for doc in context_docs]
Python
복사
[{'page': 4, 'source': 'https://www.nature.com/articles/s41467-022-34152-5.pdf'}, {'page': 2, 'source': 'https://www.nature.com/articles/s41467-022-34152-5.pdf'}, {'page': 0, 'source': 'https://www.nature.com/articles/s41467-022-34152-5.pdf'}, {'page': 11, 'source': 'https://www.nature.com/articles/s41467-022-34152-5.pdf'}]
JSON
복사
페이지 수로 따진다면, 1, 3, 5, 12 페이지가 선택된 셈이다. 실제로 1, 3, 5 페이지는 논문의 배경과 모델의 전체적인 개요를 설명하는 부분이고, 12 페이지는 “Discussion” 섹션이 있는 페이지이다. 꽤 의미 있는 선택으로 보인다!

RetrievalQA

Langchain에는 retriever로 전환된 vector store를 입력으로 받아서, RAG를 내부적으로 수행해주는 RetrievalQA 라는 Chain이 존재한다. 이를 활용하여 원하는 답변을 얻어보자!
from langchain.chains import RetrievalQA from langchain_openai import ChatOpenAI llm = ChatOpenAI(model_name='gpt-4o-mini', temperature=0, api_key=OPENAI_API_KEY) qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type='stuff', retriever=retriever) qa_chain.invoke("What is chromoformer?")
Python
복사
{'query': 'What is chromoformer?', 'result': 'Chromoformer is a transformer-based deep learning architecture designed to model the quantitative role of histone codes in the regulation of gene expression. It improves the performance of gene expression prediction by capturing the three-level hierarchy of cis-regulation involving core promoters and putative cis-regulatory elements (pCREs). Chromoformer utilizes attention mechanisms to understand distant dependencies in genomic sequences and to learn how information mediated by histone modifications is propagated from pCREs to core promoters through three-dimensional chromatin folding. The model has three variants: Chromoformer-classifier (for predicting binary gene expression labels), Chromoformer-regressor (for predicting expression levels), and Chromoformer-diff (for predicting log2 fold-change of gene expression between different cell types).'}
JSON
복사
드디어, 아주 마음에 드는 답변을 내놓게 되었다!