벡터 스토어의 개념과 구현: LangChain과 ChromaDB를 활용한 실습

GoGoComputer·2024년 10월 31일
1

LangChain Basics

목록 보기
17/40
post-thumbnail

이번 강의에서는 벡터 스토어의 개념부터 실제 구현까지 자세하고 쉽게 설명해드리겠습니다. 마지막에는 작동 가능한 전체 실습 코드를 제공하겠습니다.


📌 벡터 스토어란 무엇일까요?

1. 벡터 스토어의 개념

  • 벡터 스토어는 문서나 텍스트 데이터를 벡터(수치화된 표현)로 저장하고 관리하는 데이터베이스입니다.
  • 벡터화된 데이터는 컴퓨터가 텍스트의 의미를 이해하고 비교할 수 있게 해줍니다.

2. 왜 벡터 스토어를 사용할까요?

  • 영구 저장: 메모리에 저장된 데이터는 컴퓨터를 종료하면 사라집니다. 벡터 스토어를 사용하면 데이터를 디스크나 클라우드에 영구적으로 저장할 수 있습니다.
  • 효율적인 검색: 코사인 유사도 등의 수학적 방법을 사용하여 유사한 문서를 빠르게 검색할 수 있습니다.
  • 확장성: 대량의 데이터에서도 효율적으로 작동합니다.
  • 데이터 관리 용이성: 벡터와 해당 문서를 추가, 업데이트, 삭제할 수 있습니다.

📌 벡터 스토어의 핵심 속성

  1. 고차원 벡터 저장: 잠재적으로 큰 차원의 벡터를 저장할 수 있어야 합니다.
  2. 인덱싱 및 매핑: 벡터를 인덱싱하여 해당하는 문자열이나 문서에 연결할 수 있어야 합니다.
  3. 쿼리 기능: 새로운 벡터와 저장된 벡터 사이의 유사성을 계산하여 유사한 문서를 검색할 수 있어야 합니다.
  4. 데이터 관리 기능: 벡터와 문서를 추가, 업데이트, 삭제할 수 있어야 합니다.

📌 벡터 스토어의 활용 방법

1. 문서 로딩

  • 다양한 형식의 문서(텍스트 파일, PDF, CSV 등)를 로드합니다.
  • 예를 들어, 연설문, 기사, 책 등을 로드할 수 있습니다.

2. 문서 분할

  • 큰 문서를 작은 조각으로 나눕니다.
  • 이렇게 하면 검색 효율이 높아지고, 모델의 입력 길이 제한에 대응할 수 있습니다.

3. 벡터화(Embedding)

  • 각 문서 조각을 벡터로 변환합니다.
  • OpenAI Embedding 모델 등을 사용하여 텍스트를 수치화합니다.

4. 벡터 스토어에 저장

  • 벡터와 해당 문서를 벡터 스토어에 저장합니다.
  • 이를 통해 빠르고 효율적인 검색이 가능합니다.

5. 유사성 검색

  • 새로운 쿼리를 벡터화하고, 저장된 벡터들과 비교하여 유사한 문서를 찾습니다.
  • 예를 들어, "링컨이 노예제에 대해 뭐라고 말했나요?"라는 질문에 관련된 문서를 찾을 수 있습니다.

📌 LangChain과 ChromaDB 소개

LangChain

  • 대형 언어 모델(LLM)과의 통합을 돕는 프레임워크입니다.
  • 다양한 벡터 스토어와 통합이 가능합니다.

ChromaDB

  • 오픈 소스이면서 무료인 벡터 스토어입니다.
  • LangChain과의 통합이 잘 되어 있어 쉽게 사용할 수 있습니다.

📌 실습 코드: LangChain과 ChromaDB를 사용한 벡터 스토어 구축

1. 필요한 패키지 설치

pip install langchain==0.0.235
pip install chromadb==0.3.26
pip install openai==0.27.10
pip install tiktoken==0.4.0
pip install python-dotenv==1.0.0

참고: 버전 호환성을 위해 명시된 버전으로 설치하는 것이 좋습니다.

2. OpenAI API 키 설정

  • OpenAI의 Embedding 모델을 사용하기 위해 API 키가 필요합니다.
  • 안전한 관리를 위해 .env 파일을 사용하겠습니다.

.env 파일 생성 및 설정

  1. 프로젝트 디렉토리에 .env 파일을 생성합니다.
  2. 아래와 같이 작성합니다:
OPENAI_API_KEY=여러분의_OpenAI_API_키

3. 코드 구현

(1) 필요한 라이브러리 불러오기

import os
from dotenv import load_dotenv

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')

from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.document_loaders import TextLoader

(2) OpenAI API 키 설정

# OpenAI API 키 설정
os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY

(3) 문서 로드

# 문서 로더를 사용하여 문서 로드
loader = TextLoader("data/FDR_State_of_Union_1944.txt")
documents = loader.load()
  • "data/FDR_State_of_Union_1944.txt"는 분석하고자 하는 텍스트 파일입니다.
  • 자신의 파일 경로로 변경하세요.

(4) 문서 분할

# 문서를 작은 조각으로 분할
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=500, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
  • chunk_size=500: 각 조각의 길이를 500 토큰으로 설정합니다.
  • chunk_overlap=0: 조각 간에 겹침이 없도록 합니다.

(5) 벡터화

# OpenAI Embeddings 초기화
embedding_function = OpenAIEmbeddings()

(6) 벡터 스토어 생성 및 저장

# 벡터 스토어에 문서와 벡터 저장
persist_directory = 'db/speech_embedding_db'
vectordb = Chroma.from_documents(docs, embedding_function, persist_directory=persist_directory)

# 데이터베이스 저장
vectordb.persist()
  • persist_directory: 벡터 스토어를 저장할 디렉토리입니다.
  • vectordb.persist(): 데이터베이스를 디스크에 저장합니다.

(7) 벡터 스토어 로드

# 저장된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)
  • 컴퓨터를 재시작해도 저장된 데이터를 로드할 수 있습니다.

(8) 유사성 검색

# 유사성 검색 예시
query = "루스벨트가 식품법의 비용에 대해 뭐라고 말했나요?"
results = vectordb.similarity_search(query)
  • similarity_search: 쿼리와 유사한 문서를 검색합니다.

(9) 결과 출력

# 결과 출력
for idx, doc in enumerate(results):
    print(f"결과 {idx+1}:\n{doc.page_content}\n")
  • 검색된 문서의 내용을 출력합니다.

4. 새로운 문서 추가 및 검색

벡터 스토어에 새로운 문서를 추가하고 검색하는 방법입니다.

(1) 새로운 문서 로드 및 분할

# 새로운 문서 로드
loader_new = TextLoader("data/Lincoln_State_of_Union_1862.txt")
documents_new = loader_new.load()

# 문서 분할
docs_new = text_splitter.split_documents(documents_new)

(2) 벡터 스토어에 문서 추가

# 기존 벡터 스토어에 새로운 문서 추가
vectordb.add_documents(docs_new)
vectordb.persist()
  • add_documents: 새로운 문서를 기존 벡터 스토어에 추가합니다.
  • vectordb.persist(): 변경 사항을 저장합니다.

(3) 업데이트된 벡터 스토어 로드

# 업데이트된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)

(4) 새로운 쿼리로 유사성 검색

# 새로운 쿼리로 유사성 검색
query_new = "링컨이 노예제에 대해 뭐라고 말했나요?"
results_new = vectordb.similarity_search(query_new)

(5) 결과 출력

# 결과 출력
for idx, doc in enumerate(results_new):
    print(f"결과 {idx+1}:\n{doc.page_content}\n")

📌 전체 코드

아래는 위의 모든 내용을 합친 전체 코드입니다.

import os
from dotenv import load_dotenv

# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')

from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.document_loaders import TextLoader

# OpenAI API 키 설정
os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY

# 문서 로더를 사용하여 문서 로드
loader = TextLoader("data/FDR_State_of_Union_1944.txt")
documents = loader.load()

# 문서를 작은 조각으로 분할
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=500, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

# OpenAI Embeddings 초기화
embedding_function = OpenAIEmbeddings()

# 벡터 스토어에 문서와 벡터 저장
persist_directory = 'db/speech_embedding_db'
vectordb = Chroma.from_documents(docs, embedding_function, persist_directory=persist_directory)

# 데이터베이스 저장
vectordb.persist()

# 저장된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)

# 유사성 검색 예시
query = "루스벨트가 식품법의 비용에 대해 뭐라고 말했나요?"
results = vectordb.similarity_search(query)

# 결과 출력
for idx, doc in enumerate(results):
    print(f"결과 {idx+1}:\n{doc.page_content}\n")

# 새로운 문서 로드 및 분할
loader_new = TextLoader("data/Lincoln_State_of_Union_1862.txt")
documents_new = loader_new.load()
docs_new = text_splitter.split_documents(documents_new)

# 기존 벡터 스토어에 새로운 문서 추가
vectordb.add_documents(docs_new)
vectordb.persist()

# 업데이트된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)

# 새로운 쿼리로 유사성 검색
query_new = "링컨이 노예제에 대해 뭐라고 말했나요?"
results_new = vectordb.similarity_search(query_new)

# 결과 출력
for idx, doc in enumerate(results_new):
    print(f"결과 {idx+1}:\n{doc.page_content}\n")

📌 추가 설명

문서 분할의 중요성

  • 왜 분할할까요?

    • 큰 문서를 한 번에 처리하면 검색 결과가 부정확해질 수 있습니다.
    • 작은 조각으로 나누면 특정 주제나 내용에 더 정확하게 매칭됩니다.
    • LLM의 입력 길이 제한에도 대응할 수 있습니다.
  • 분할 방법

    • CharacterTextSplitter를 사용하여 문서를 일정한 길이로 분할합니다.
    • chunk_sizechunk_overlap을 조절하여 분할 크기와 겹침을 설정할 수 있습니다.

벡터화(Embedding)의 이해

  • 벡터화란?

    • 텍스트를 수치 벡터로 변환하는 과정입니다.
    • 이 벡터는 텍스트의 의미를 포함하고 있어, 유사한 의미의 텍스트는 유사한 벡터를 갖습니다.
  • OpenAI Embeddings 사용

    • 강력한 성능을 가진 OpenAI의 Embedding 모델을 사용합니다.
    • API 키가 필요하며, 사용량에 따라 비용이 발생할 수 있습니다.

유사성 검색의 원리

  • 코사인 유사도

    • 벡터 간의 각도를 이용하여 유사성을 계산합니다.
    • 값이 1에 가까울수록 유사도가 높습니다.
  • 검색 과정

    1. 쿼리 텍스트를 벡터화합니다.
    2. 저장된 벡터들과 유사도를 계산합니다.
    3. 유사도가 높은 순서대로 문서를 반환합니다.

벡터 스토어의 지속성

  • 데이터베이스 저장

    • vectordb.persist()를 호출하여 벡터 스토어를 디스크에 저장합니다.
    • 이렇게 하면 컴퓨터를 종료해도 데이터가 유지됩니다.
  • 데이터베이스 로드

    • 저장된 벡터 스토어를 다시 사용할 때는 persist_directoryembedding_function을 지정하여 로드합니다.

문서 추가 및 업데이트

  • 새로운 문서 추가

    • add_documents 메서드를 사용하여 새로운 문서를 추가할 수 있습니다.
    • 추가 후 persist()를 호출하여 변경 사항을 저장합니다.
  • 데이터 관리

    • 벡터 스토어는 벡터와 문서를 추가, 업데이트, 삭제할 수 있는 기능을 제공합니다.

📌 결론

이번 강의에서는 벡터 스토어의 개념부터 실제 구현까지 자세히 알아보았습니다. 벡터 스토어는 대량의 텍스트 데이터를 효율적으로 관리하고 검색할 수 있는 강력한 도구입니다.

  • 장점 요약
    • 영구 저장으로 데이터 손실 방지
    • 효율적인 유사성 검색
    • 확장성과 데이터 관리 용이성

LangChainChromaDB를 사용하면 이러한 벡터 스토어를 쉽게 구축하고 활용할 수 있습니다. 이 실습을 통해 벡터 스토어의 기본적인 사용 방법을 이해하고, 실제로 구현해보았습니다.


📌 참고 자료


📌 추가로 알아보기

  • 다른 벡터 스토어 옵션 탐색

    • 자신의 프로젝트에 더 적합한 벡터 스토어를 찾을 수 있습니다.
    • LangChain은 다양한 벡터 스토어와의 통합을 지원합니다.
  • 고급 기능 활용

    • 메타데이터 관리, 벡터 스토어 최적화 등 고급 기능을 탐색해보세요.

혹시 추가로 궁금한 점이나 더 알고 싶은 내용이 있으시면 언제든지 말씀해주세요! 😊


부록 - chromadb 설치 오류 해결 법

pip install chromadb 오류 발생 시, Python 버전을 낮춰 보세요. 현재 Python 3.13 사용 중.

파이썬 버전을 낮추려면 다음과 같은 단계들을 따르시면 됩니다.

  1. 현재 파이썬 버전 확인:

    python --version
  2. 기존 파이썬 버전 제거 (Linux/macOS 기준):

    • 먼저 기존 파이썬을 삭제해야 합니다. 시스템 파이썬이 아닌 다른 설치된 파이썬을 제거하세요.
    sudo apt remove python3

    또는

    brew uninstall python
  3. 원하는 파이썬 버전 설치:

    • Homebrew를 사용하는 경우:
      brew install python@3.x  # x는 원하는 버전 숫자로 변경하세요.
    • pyenv를 사용해서 특정 버전을 설치하고 관리할 수도 있습니다:
      pyenv install 3.x.y
      pyenv global 3.x.y  # 기본 버전을 새 버전으로 변경합니다.
  4. 버전 확인:

    python --version

이렇게 하면 원하는 파이썬 버전으로 환경을 설정할 수 있습니다. pyenv를 활용하면 여러 버전을 동시에 관리하기 편리하니 참고해 보세요.

profile
IT를 좋아합니다.

0개의 댓글