🧠 LangChain + Chroma + t-SNE로 문서 임베딩 시각화하기
문서를 벡터로 변환하고 시각화하여 RAG 검색의 기반을 시각적으로 이해해 보는 실습입니다.
🔌 9. 벡터 임베딩 모델 설정
이 코드는 각 문서 청크를 의미 기반 벡터로 변환해서 벡터 저장소에 넣기 위한 사전 준비 단계입니다.
# 🧠 문서 청크들을 벡터 임베딩으로 변환하여 벡터 저장소(Vector Store)에 넣기 위한 준비
embeddings = OpenAIEmbeddings()
# 🔹 OpenAI의 임베딩 모델 사용 설정
# - 각 텍스트 청크를 의미 기반 벡터로 변환
# - 이 벡터는 RAG 검색에서 유사도 비교 기준으로 사용됨
# - OpenAI API 키가 필요하며, 비용이 발생할 수 있음
# 💡 참고: HuggingFace의 무료 오픈소스 임베딩 모델을 사용하고 싶다면 아래 코드로 교체 가능
# - 비용 걱정 없이 로컬에서 사용할 수 있음
# - "all-MiniLM-L6-v2"는 가볍고 속도 빠른 대표 모델
# from langchain.embeddings import HuggingFaceEmbeddings
# embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
📝 요약하면:
OpenAIEmbeddings → 사용이 간편하지만 유료 (정확도는 우수)
HuggingFaceEmbeddings → 무료이지만 설치와 리소스가 더 필요함 (오프라인 실행 가능)
🧹 10. 기존 Chroma DB 초기화 (있다면 삭제)
이 코드는 기존에 저장된 Chroma 벡터 데이터베이스가 있을 경우 초기화(삭제)하는 역할을 합니다.
# 🔄 기존 Chroma 벡터 데이터베이스 초기화 (있을 경우만)
# - 이전 실행에서 생성된 벡터 저장소가 이미 존재하면, 새로 시작하기 위해 삭제함
# - 즉, 같은 db_name 경로가 있으면 해당 컬렉션을 지우고 새로 생성하게 됨
if os.path.exists(db_name):
# 🗃️ 기존 Chroma 인스턴스를 생성하고, 연결된 컬렉션 삭제
# - persist_directory: 저장 위치 (db_name 변수로 지정됨)
# - embedding_function: 텍스트 → 벡터 변환에 사용할 임베딩 모델
Chroma(
persist_directory=db_name,
embedding_function=embeddings
).delete_collection()
💡 이 코드는 특히 실험하거나 문서가 자주 바뀌는 경우에 유용해요.
기존 벡터들을 유지하지 않고 항상 처음부터 시작할 수 있게 해주기 때문입니다.
🏗️ 11. Chroma 벡터 저장소 생성
이 코드는 문서 청크들을 실제로 벡터 저장소(Chroma)에 저장하는 중요한 단계입니다.
# - 각 문서 청크(chunks)를 벡터로 변환하고 Chroma DB에 저장함
# - persist_directory를 지정해 디스크에 저장 → 나중에도 재사용 가능
vectorstore = Chroma.from_documents(
documents=chunks, # 📄 우리가 청크로 나눈 문서 리스트
embedding=embeddings, # 🧠 텍스트를 벡터로 변환할 임베딩 모델
persist_directory=db_name # 💾 벡터 저장 위치 (예: 'vector_db')
)
# 📊 저장된 문서 개수 출력 (내부적으로 몇 개의 벡터가 저장되었는지 확인)
print(f"Vectorstore created with {vectorstore._collection.count()} documents")
# 예: Vectorstore created with 132 documents
💡 Chroma.from\_documents()
는 내부적으로:
- 각 문서의 텍스트를 임베딩(벡터화)하고,
- 그것을 벡터 저장소에 저장하고,
- 로컬 디스크에 영구적으로 보관해줍니다.
이제부터는 이 저장소를 활용해서 RAG 검색이나 질문 응답 시스템에 활용할 수 있어요!
🔎 12. 임베딩 벡터의 차원 수 확인
이 코드는 벡터 저장소에 저장된 벡터 중 하나를 꺼내서, 그 벡터가 몇 차원(dimension)인지 확인하는 용도입니다.
벡터 차원 수는 나중에 시각화나 모델 선택에 중요한 기준이 됩니다.
# 🔍 저장된 벡터 중 하나를 가져와서 차원 수(dimension)를 확인
collection = vectorstore._collection
# 👉 내부적으로 관리되는 벡터 컬렉션 객체를 직접 가져옴
sample_embedding = collection.get(limit=1, include=["embeddings"])["embeddings"][0]
# 📌 저장된 벡터 중 첫 번째 하나를 가져옴 (limit=1)
# - include=["embeddings"]: 텍스트나 메타데이터는 제외하고, 임베딩만 가져오겠다는 의미
dimensions = len(sample_embedding)
# 📏 벡터의 차원 수 확인
# - 예: 1536차원, 768차원 등 (임베딩 모델마다 다름)
print(f"The vectors have {dimensions:,} dimensions")
# 🖨️ 결과 예시: The vectors have 1,536 dimensions
💡 참고:
gpt-3.5-turbo
임베딩 모델은 1,536차원- HuggingFace의
all-MiniLM-L6-v2
는 384차원
이 차원 수는 나중에 시각화(tsne 등) 또는 유사도 계산에 영향을 줍니다.
🧼 13. 시각화를 위한 벡터 데이터 전처리
이 코드는 벡터 시각화를 위한 데이터 전처리(Prework) 단계입니다.
문서와 관련된 벡터, 메타데이터를 가져오고, 시각화에 사용할 색상까지 정리하고 있어요.
# 🗂️ 시각화를 위한 데이터 전처리
result = collection.get(include=['embeddings', 'documents', 'metadatas'])
# 🔍 저장소에서 모든 벡터(임베딩), 원본 문서 내용, 메타데이터 가져오기
# - 'embeddings': 의미를 나타내는 수치 벡터
# - 'documents': 실제 문서 텍스트
# - 'metadatas': 폴더 이름 등 문서 유형 정보 포함
vectors = np.array(result['embeddings'])
# ➗ 벡터 데이터를 넘파이 배열로 변환 (수학 계산, 시각화 용이)
documents = result['documents']
# 📄 원본 문서 내용만 추출
doc_types = [metadata['doc_type'] for metadata in result['metadatas']]
# 🏷️ 각 문서의 유형(doc_type)을 리스트로 저장
# 예: ['products', 'products', 'contracts', 'employees', ...]
colors = [
['blue', 'green', 'red', 'orange'][['products', 'employees', 'contracts', 'company'].index(t)]
for t in doc_types
]
# 🎨 각 문서 유형에 따라 시각화 색상을 지정
# - products → blue, employees → green, contracts → red, company → orange
# - 색상은 나중에 2D 그래프에서 문서 그룹을 시각적으로 구분하는 데 사용됨
💡 이 단계 덕분에, tsne 같은 차원 축소 후 문서들이 어떤 주제별로 모여 있는지 시각적으로 파악하기 쉬워집니다.
📉 14. 2D 벡터 시각화 (t-SNE + Plotly)
이 코드는 벡터 임베딩을 2차원으로 줄여서 시각화하는 핵심 단계입니다.
# 🧠 우리는 시각적으로 2D(2차원)가 가장 이해하기 쉬움!
# - 벡터는 보통 384~1536차원이지만, 시각화를 위해 2차원으로 축소함
# - t-SNE는 고차원 벡터 간의 상대적 거리(유사도)를 보존하는 차원 축소 기법
tsne = TSNE(n_components=2, random_state=42)
# 🎯 n_components=2 → 2차원으로 줄이겠다는 의미
# - random_state를 고정하면 매번 같은 결과가 나와 재현 가능함
reduced_vectors = tsne.fit_transform(vectors)
# 📉 벡터들을 2D 공간으로 축소하여 시각화 준비 완료
# 📊 2차원 산점도(scatter plot) 만들기 (Plotly 사용)
fig = go.Figure(data=[go.Scatter(
x=reduced_vectors[:, 0], # x축 좌표
y=reduced_vectors[:, 1], # y축 좌표
mode='markers', # 마커 형태 (점만 표시)
marker=dict(
size=5, # 점 크기
color=colors, # 문서 유형별로 색상 지정
opacity=0.8 # 살짝 투명하게
),
# 🧾 마우스 오버 시 표시될 텍스트: 문서 유형 + 일부 내용
text=[f"Type: {t}<br>Text: {d[:100]}..." for t, d in zip(doc_types, documents)],
hoverinfo='text' # 마우스 오버 시 text 항목만 보여줌
)])
# 🧩 차트 레이아웃 설정
fig.update_layout(
title='Chroma 벡터 저장소의 2차원 시각화', # 제목
scene=dict(xaxis_title='x', yaxis_title='y'), # 축 제목 (2D여도 넣어줌)
width=800, height=600, # 그래프 크기
margin=dict(r=20, b=10, l=10, t=40) # 여백 설정
)
fig.show()
# 📌 최종 그래프를 화면에 출력 (인터랙티브하게 마우스 오버/확대 가능!)
💡 이 시각화를 통해 문서들이 주제별로 얼마나 잘 그룹핑되었는지 직관적으로 볼 수 있어요.
문서 유형별로 뭉쳐 있는가, 흩어져 있는가를 확인하면서 임베딩 품질도 평가할 수 있어요!
🧊 15. 3D 벡터 시각화 (t-SNE + Plotly)
이번에는 벡터를 3차원으로 시각화해서 더 입체적으로 문서들의 군집 구조를 살펴보는 단계입니다.
# 🎲 3D 시각화에 도전!
# - 고차원 벡터를 3차원으로 줄여서 더 입체적으로 문서 구조를 살펴봄
tsne = TSNE(n_components=3, random_state=42)
# 🧠 t-SNE로 차원을 3D로 축소
# - 2D보다 더 복잡한 구조나 숨겨진 군집 관계를 더 잘 볼 수 있음
reduced_vectors = tsne.fit_transform(vectors)
# 📉 실제 벡터들을 3차원으로 변환
# 📊 3차원 산점도 (Scatter3d) 생성
fig = go.Figure(data=[go.Scatter3d(
x=reduced_vectors[:, 0], # x축 좌표
y=reduced_vectors[:, 1], # y축 좌표
z=reduced_vectors[:, 2], # z축 좌표
mode='markers', # 마커 형태 (점으로 표시)
marker=dict(
size=5, # 점 크기
color=colors, # 문서 유형별 색상 구분
opacity=0.8 # 반투명 처리로 겹침 완화
),
text=[f"Type: {t}<br>Text: {d[:100]}..." for t, d in zip(doc_types, documents)],
# 🧾 마우스 오버 시 표시될 문서 정보 (유형 + 앞부분 내용)
hoverinfo='text'
)])
# 🧩 3D 그래프 레이아웃 설정
fig.update_layout(
title='Chroma 벡터 저장소의 3차원 시각화', # 제목
scene=dict(
xaxis_title='x',
yaxis_title='y',
zaxis_title='z'
),
width=900, height=700, # 그래프 크기
margin=dict(r=20, b=10, l=10, t=40) # 여백 설정
)
fig.show()
# 📌 결과 출력: 인터랙티브 3D 그래프 → 마우스로 회전, 확대 가능!
💡 이 3D 시각화는 문서 벡터들이 유형별로 어떻게 분포되어 있는지, 군집(클러스터)이 뚜렷한지 등을 더 입체적으로 탐색할 수 있는 방법입니다!
'🧠 LLM 엔지니어링' 카테고리의 다른 글
문서 기반 챗봇 만들기: RAG 실습 with OpenAI, FAISS, Gradio 02 (0) | 2025.04.29 |
---|---|
문서 기반 챗봇 만들기: RAG 실습 with OpenAI, FAISS, Gradio 01 (1) | 2025.04.28 |
LangChain과 Chroma를 활용한 문서 임베딩 시각화 실습 01 (1) | 2025.04.26 |
LLM 문서에서 특정 키워드 추출하는 방법 02 (Shopwise 지식기반 예제) (1) | 2025.04.25 |
LLM 문서에서 특정 키워드 추출하는 방법 01 (Shopwise 지식기반 예제) (1) | 2025.04.24 |