티스토리 뷰

1. Vector DB 구성

 

1)  Vector DB 정의: 대규모 텍스트 데이터 및 임베딩 벡터를 저장, 검색용

 

 

2) Vector DB 과정

텍스트 추출: Loader

다양한 문서로부터 텍스트 추출하기

 

= >

 

텍스트 분할: Splitter

chunk 단위로 분할

Document 객체로 만들기

 

=> 

 

텍스트 벡터화: Text Embedding

 

=>

 

Vector DB로 저장: Vector Store

 

2. 벡터 디비 구성과정

 

1) Loader

다양한 소스에서 문서를 불러오고 처리하는 과정을 담당

 

from langchain.document_loaders import TextLoader

# 텍스트 파일 경로 지정
file_path = "상록수.txt"

# TextLoader를 이용하여 문서 로드
loader = TextLoader(path+file_path)
documents = loader.load()

# 로드된 문서 출력
print(documents)

 

print(type(documents))
print(len(documents))
print(type(documents[0]))

 

- 내용만 불러오기

documents[0].page_content[:1000]

 

- Document: LangChain에서 텍스트 데이터를 구조적으로 표현하는 기본 단위

Document의 기본속성은 metadata, page_content

metadata: 문서의 출처, 태그, 카테고리 등의 부가정보

page_content: 문서의 실제 텍스트 내용

 

doc.metadata
doc.page_content

 

 

2) Splitter

 

긴 문서를 작은 단위인 청크로 나누는 텍스트 분리 도구

텍스트를 분리하는 작업: 청킹

 

청킹을 하는 이유: 

- LLM 모델의 입력 토큰의 개수가 정해져있기 때문이다.

- 텍스트가 너무 긴 경우에는 핵심 정보 이외에 불필요한 정보들이 많이 포함

- 핵심 정보가 유지 될 수 있는 적절한 크기로 나누는 것이 매우 중요

 

# 청크 사이즈를 500 단위로 자르고 아무런 기준 없이 무조건 단위 단위로 잘라라

split_texts[:5] => 처음 5개 청크만 출력해라

 

- 글자 단위

from langchain.text_splitter import CharacterTextSplitter

text_splitter = CharacterTextSplitter(
    chunk_size = 500
    chunk_overlap = 100,
    separator = ' ',
)

split_texts = text_splitter.split_text(text)

for i, chunk in enumerate(split_texts[:5]):
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\n")

 

- 문장 단위

text_splitter = CharacterTextSplitter(
    chunk_size=500,             #청크의 최대 글자수
    chunk_overlap=100,          #겹치는 글자수
    separator="."               # 문장 단위로 분할
)

split_texts = text_splitter.split_text(text)

# 결과 확인
for i, chunk in enumerate(split_texts[:5]):  # 처음 5개 청크만 출력
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\n")

 

- 줄 바꿈 단위

text_splitter = CharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100,
    separator='\n',
)
split_texts = text_splitter.split_text(text)

for i, chunk in enumerate(split_texts[:5]):
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\n")

 

 

3) Embedding & Store

임베딩: 텍스트 데이터를 숫자로 이루어진 벡터로 변환하는 과정

 

임베딩 목적: 벡터 표현을 사용하면, 텍스트 데이터를 벡터 공간 내에서 수학적으로 다룰 수 있게 됨

텍스트 간의 유사성을 계산 가능

 

임베딩 모델 사용: text-embedding-ada-002, text-embedding-3-small, e5-large-v2

 

벡터 저장소:벡터 형태로 표현된 데이터 즉 임베딩 벡터들을 효율적으로 저장하고 검색할 수 있는 DB

Vector DB => Chroma, FAISS

 

- 임베딩 모델 선언

from langchain.embeddings import OpenAIEmbeddings

embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")

 

sample_text1="농촌 계몽운동은 한국 근대화의 중요한 과정이었다."
vector1 = embedding_model.embed_query(sample_text1)

print(f"임베딩 벡터 길이: {len(vector1)}")
print(f"첫 10개 벡터 값: {vector1[:10]}")

 

그럼 텍스트에서 이거와 관련된 벡터들을 정의해주고 순서대로 정렬해준다.

 

- ChromaDB 저장

 

split_texts: 청크 단위로 분리된 텍스트

embedding_model: 임베딩 모델 선언한거

persist_directory: 어느 경로에 저장?

from langchain.vectorstores import Chroma

vectorstore = Chroma.from_texts(split_texts, embedding_model, persist_directory="./chroma_db")

 

- 유사도 검색

유사도를 기준으로 3문장만 뽑아서 page_content만 가져오

query = "농촌 계몽운동에 대한 내용"
retrieved_docs = vectorstore.similarity_search(query, k=3)

# 결과 출력
print("검색 결과:")
for doc in retrieved_docs:
    print(doc.page_content)
    print('-'*200)

 

3. RAG 파이프라인 만들기

 

- Retriever 선언: Vector DB에서 사용자의 질문과 가장 유사한 청크를 검색 = > 코사인 유사도 기반

- LLM 모델지정: 검색된 문서와 함께 질문을 받아 답변 생성할 LLM 모델 지정

retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k":5})
llm = ChatOpenAI(model_name="gpt-4o-mini")

 

- 메모리 선언: 대화의 흐름을 유지하고, 이전 질문을 기억하여 문맥을 제공

- 체인 함수로 엮기: Retriever + LLM + Memory를 하나의 체인으로 연결하여 질문-응답 시스템 완성

ConversationBufferMemory
ConversationalRetrievalChain.from_llm

 

 

'Data science > RAG' 카테고리의 다른 글

[RAG] 2. 벡터 DB구성과 RAG 파이프라인 구축2  (1) 2025.05.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함