이전에 문서 로드 및 분할 방법에 대해 다루었으며, 이번에는 벡터 저장소와 임베딩 기술을 중심으로 설명합니다.
LangChain을 사용하여 외부 데이터와 상호작용하는 과정은 다음과 같은 단계로 이루어집니다:
- 문서 로딩 (Document Loading)
- 분할 (Splitting)
- 저장 (Storage)
- 검색 (Retrieval)
- 출력 (Output)
지난 포스트에서 문서 로드 및 분할에 대해 설명했으므로, 이제 벡터화 및 저장 단계를 살펴보겠습니다.
문서 로드 및 분할
먼저 CS229 머신러닝 강의 자료 PDF 파일을 로드합니다:
from langchain.document_loaders import PyPDFLoader
pdf_loaders = [
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"),
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"), # 중복 확인용
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture02.pdf"),
PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture03.pdf")
]
document_list = []
for loader in pdf_loaders:
document_list.extend(loader.load())
다음으로 문서를 분할합니다:
from langchain.text_splitter import RecursiveCharacterTextSplitter
split_config = RecursiveCharacterTextSplitter(
chunk_size=1500,
chunk_overlap=150
)
chunked_docs = split_config.split_documents(document_list)
print(f"총 {len(chunked_docs)} 개의 청크 생성됨")
임베딩 처리
텍스트 임베딩은 자연어를 고차원 벡터 공간으로 변환하는 작업입니다. OpenAI 임베딩 모델을 사용해보겠습니다:
from langchain.embeddings.openai import OpenAIEmbeddings
import numpy as np
embedder = OpenAIEmbeddings()
sentences = [
"나는 강아지를 좋아한다.",
"나는 작은 동물을 좋아한다.",
"오늘 기분이 좋지 않다."
]
vectors = [embedder.embed_query(s) for s in sentences]
# 유사도 계산
similarity_1_2 = np.dot(vectors[0], vectors[1])
similarity_1_3 = np.dot(vectors[0], vectors[2])
similarity_2_3 = np.dot(vectors[1], vectors[2])
print(f"문장 1과 2의 유사도: {similarity_1_2:.2f}")
print(f"문장 1과 3의 유사도: {similarity_1_3:.2f}")
print(f"문장 2와 3의 유사도: {similarity_2_3:.2f}")
벡터 데이터베이스 구성
Chroma 벡터 데이터베이스를 생성하고 청크된 문서들을 저장합니다:
from langchain.vectorstores import Chroma
db_path = 'docs/chroma/'
vector_db = Chroma.from_documents(
documents=chunked_docs,
embedding=embedder,
persist_directory=db_path
)
print(f"데이터베이스 내 문서 수: {vector_db._collection.count()}")
유사도 검색 수행
질문에 대한 관련 문서를 검색합니다:
query = "도움을 요청할 수 있는 이메일 주소가 있나요?"
relevant_docs = vector_db.similarity_search(query, k=3)
print(f"검색 결과 문서 수: {len(relevant_docs)}")
print("첫 번째 문서 내용:")
print(relevant_docs[0].page_content)
데이터베이스 영속화
생성된 벡터 데이터베이스를 로컬에 저장합니다:
vector_db.persist()
검색 실패 사례
중복 문서로 인한 문제:
duplicate_query = "MATLAB에 대해 어떤 언급이 있었나요?"
duplicate_results = vector_db.similarity_search(duplicate_query, k=5)
# 중복 문서 확인
for idx, doc in enumerate(duplicate_results[:2]):
print(f"문서 {idx+1} 메타데이터: {doc.metadata}")
특정 문서 제한 검색 실패:
specific_query = "세 번째 강의에서 회귀 분석에 대해 어떤 내용이 있었나요?"
filtered_results = vector_db.similarity_search(specific_query, k=5)
for doc in filtered_results:
print(f"문서 출처: {doc.metadata['source']}")