만약 LLM(Large Language Model)이 자체 지식 외에도 검색을 통해 더 넓은 세상의 정보를 가져올 수 있다면, LLM 기반 애플리케이션을 만들 때 훨씬 더 다양한 옵션을 활용할 수 있겠죠. 외부 소스에서 데이터를 검색하는 이 기술을 Retrieval-Augmented Generation(RAG)이라고 불러요.
RAG 애플리케이션은 LLM 기반 애플리케이션 개발을 위한 대표적인 프레임워크인 LangChain을 사용해서 구축할 수 있어요. LangChain은 대부분의 LLM 제공업체와 데이터베이스를 통합 인터페이스에 통합해서 개발 과정을 단순화해주죠. LangChain 라이브러리의 Neo4j vector index를 사용하면, 개발자는 Vector Embedding을 효율적으로 저장하고 검색하기 위한 고급 vector indexing을 쉽게 구현할 수 있답니다.
이번 블로그 포스팅에서는 LangChain과 Neo4j vector index를 사용해서 Wikipedia 기사 정보를 기반으로 질문에 효과적으로 답변할 수 있는 간단한 RAG 애플리케이션을 구축하는 방법을 보여드릴게요. 다음 단계를 함께 살펴볼까요?
Wikipedia 기사를 읽고 Chunking하기
Neo4j를 사용해서 텍스트를 저장하고 Indexing하기
Vector Similarity Search 수행하기
질의 응답 워크플로우 구현하기
Retrieval-Augmented Generation 워크플로우
언제나처럼, 코드는 에서 확인하실 수 있어요.
Neo4j 환경 설정
이 블로그 포스팅의 예제를 따라 하시려면 Neo4j 5.11 이상을 설정해야 해요. 가장 쉬운 방법은 Neo4j AuraDB에서 무료 인스턴스를 시작하는 건데요, Neo4j 데이터베이스의 클라우드 인스턴스를 제공해준답니다. 아니면 Neo4j Desktop을 다운로드해서 로컬 Neo4j 데이터베이스를 설정하고 애플리케이션을 생성해서 로컬 데이터베이스 인스턴스를 만들 수도 있어요.
1. Wikipedia 기사 읽기 및 Chunking
먼저 Wikipedia 기사를 읽고 Chunk로 나누는 것부터 시작해볼게요. LangChain이 Wikipedia 문서 로더와 텍스트 Chunking 모듈을 통합했기 때문에 과정은 아주 간단해요.
from langchain.document_loaders import WikipediaLoader
from langchain.text_splitter import CharacterTextSplitter
# Read the wikipedia article
raw_documents = WikipediaLoader(query="Leonhard Euler").load()
# Define chunking strategy
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=1000, chunk_overlap=20
)
# Chunk the document
documents = text_splitter.split_documents(raw_documents)
# Remove summary from metadata
for d in documents:
del d.metadata['summary']
Neo4j는 Graph Database이니까, 그래프 이론의 아버지인 Leonhard Euler에 대한 Wikipedia 기사를 사용하는 게 딱 어울리겠죠?
다음으로, OpenAI에서 만든 토크나이저인 을 사용해서 기사를 Chunk로 분할하는 텍스트 Chunking 모듈을 사용할 건데요, Chunk 크기는 *1000* 토큰으로 설정할 거예요. 이 글에서 텍스트 Chunking 전략에 대해 더 자세히 알아볼 수 있어요.
LangChain의 WikipediaLoader는 기본적으로 각 Chunk에 요약을 추가하는데, 저는 추가된 요약이 약간 중복된다고 생각했어요. Vector Similarity Search를 사용해서 상위 3개 결과를 검색하면 요약이 세 번 반복되니까요. 그래서 데이터세트에서 요약을 제거하기로 결정했답니다.
2. Neo4j로 텍스트 저장 및 Indexing
Neo4j vector index는 LangChain vector store로 래핑되어 있어요. 그래서 다른 벡터 데이터베이스와 상호 작용하는 데 사용되는 구문을 그대로 사용할 수 있답니다.
from_documents 메서드는 Neo4j 데이터베이스에 연결해서 문서를 가져오고, 임베딩하고, Vector Index를 생성해요. 데이터는 기본적으로 청크 Node로 표현되죠. 앞서 말씀드린 것처럼 데이터를 저장하는 방법과 반환할 데이터를 사용자 정의할 수 있어요.
데이터가 채워진 기존 Vector Index가 이미 있다면 from_existing_index 메서드를 사용할 수 있어요.