티스토리 뷰
2025.08.16 - [RAG] - [LangChain] 문서 로딩과 전처리 가이드
이전 글(문서 로딩·전처리)에서 만든 docs/chunks를 이어서 사용합니다. 이 글에서는 벡터화(Vectorization) 원리, 벡터 데이터베이스 개요, 그리고 FAISS · Pinecone · Weaviate로 인덱싱/검색/리트리버를 구성하는 전 과정을 실습 코드로 정리합니다.
0. 설치
# 공통
pip install -U langchain langchain-community langchain-openai langchain-text-splitters
# FAISS (로컬)
pip install faiss-cpu # Mac/리눅스. (윈도우는 'faiss-cpu' 미지원 → conda 권장)
# Pinecone (매니지드)
pip install -U pinecone-client langchain-pinecone
# Weaviate (클라우드/자가호스팅)
pip install -U weaviate-client langchain-weaviate
임베딩은 예시로 OpenAI를 사용합니다. (Hugging Face 임베딩으로 교체해도 동일한 흐름)
from langchain_openai import OpenAIEmbeddings
EMBED_MODEL = "text-embedding-3-small" # 1536차원, 비용 대비 효율
emb = OpenAIEmbeddings(model=EMBED_MODEL) # 환경변수 OPENAI_API_KEY 필요
1. 벡터화(Vectorization) 원리 빠르게 이해하기
목표: 사용자 질문과 문서 청크를 같은 벡터 공간에 임베딩해서, 가까운 것(유사한 것)을 빠르게 찾는 것.
- 청킹(Chunking): 긴 문서를 일정 길이(예: 500~1,000자)로 나눔 (이전 글 참고)
- 임베딩(Embedding): 각 청크 → 고정 길이 벡터(예: 1536-D)
- 인덱싱(Indexing): 벡터 DB에 저장 (ANN: HNSW, IVF-PQ 등 근사 최근접 탐색)
- 질의(Query): 사용자의 질문을 임베딩 → DB에서 가까운 벡터 k개 검색
- 후처리: 메타데이터 필터, 리랭킹, 중복 제거 등
- 생성(Generation): 검색 결과 컨텍스트를 프롬프트에 넣어 LLM으로 답변 생성
거리/유사도 지표
- cosine(코사인 거리), dot(내적), L2(유클리드). 모델/플랫폼별 기본값이 다릅니다.
- 같은 데이터·질문이라도 임베딩 모델/거리함수 조합에 따라 검색 결과가 달라질 수 있습니다.
ANN 인덱스
- FAISS: IVF, HNSW, PQ 등 다양한 인덱스 타입 제공 (로컬)
- Pinecone: 관리형 ANN 인프라 (서버리스/Pod), 필터/Namespace 등 운영 기능 강력
- Weaviate: 그래프형 스키마 + HNSW, 필터/하이브리드 벡터라이저(옵션)
2. FAISS — 로컬 개발/파일 배포에 적합

장점: 빠르고 무료. 간단히 파일로 저장/배포.
단점: 서버리스가 아님(스케일링/동시성 한계), 멀티리전/권한관리 없음.
2-1. 인덱싱: 문서 → 벡터 DB
from langchain_community.vectorstores import FAISS
# chunks: 이전 글에서 전처리/청킹한 Document 리스트
faiss_store = FAISS.from_documents(documents=chunks, embedding=emb)
# 로컬 저장(필수 권한 경로)
faiss_store.save_local("indexes/faiss_kb")
2-2. 질의: 리트리버로 사용
# (다시 로드 가능)
faiss_store = FAISS.load_local(
"indexes/faiss_kb", emb, allow_dangerous_deserialization=True
)
retriever = faiss_store.as_retriever(search_kwargs={"k": 4})
results = retriever.invoke("예약 취소 규정이 어떻게 되나요?")
for i, d in enumerate(results, 1):
print(i, d.metadata.get("source"), d.page_content[:120])
팁: similarity_search_with_score(query, k=4)로 점수까지 확인 가능. 파일 배포 시 index.faiss + index.pkl 두 파일을 함께 배포하세요.
3. Pinecone — 매니지드 벡터 DB (서버리스/운영 편의)

장점: 자동 확장/고가용성, 메타데이터 필터, 네임스페이스(멀티테넌시), 서버리스 요금제.
단점: 유료, 리전/사양 고려 필요.
3-1. 인덱스 준비
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="<PINECONE_API_KEY>")
index_name = "kb-emb3-small"
# OpenAI text-embedding-3-small = 1536차원
if index_name not in [i.name for i in pc.list_indexes()]:
pc.create_index(
name=index_name,
dimension=1536,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)
# 핸들
pc_index = pc.Index(index_name)
3-2. LangChain VectorStore로 업서트/검색
from langchain_pinecone import PineconeVectorStore
# ids는 재업서트/삭제를 고려해 명시적으로 관리 권장
ids = [d.metadata.get("id", f"doc-{i}") for i, d in enumerate(chunks)]
p_store = PineconeVectorStore(index_name=index_name, embedding=emb)
p_store.add_documents(documents=chunks, ids=ids)
# 메타데이터 필터 예시(서버리스에서는 Mongo식 연산자 사용: $eq, $in, ...)
retriever = p_store.as_retriever(
search_kwargs={"k": 4, "filter": {"doc_type": {"$eq": "kb"}}}
)
docs = retriever.invoke("현금영수증 발급 기준 알려줘")
for d in docs:
print(d.metadata.get("doc_type"), d.metadata.get("source"))
팁: 네임스페이스(namespace) 로 고객/언어/버전별 데이터 격리 가능. 대량 적재는 upsert 배치 사이즈를 조절하세요.
4. Weaviate — 스키마 지향 + 하이브리드 검색

장점: 스키마/필터 강력, 오픈소스 + 클라우드, 하이브리드(키워드+벡터) 지원.
단점: 운영/스키마 설계가 처음엔 낯설 수 있음.
4-1. 클라이언트 연결
import weaviate
client = weaviate.Client(
url="https://<YOUR-WEAVIATE-ENDPOINT>",
auth_client_secret=weaviate.AuthApiKey(api_key="<WCS_API_KEY>")
)
4-2. LangChain VectorStore로 적재/검색
from langchain_weaviate import WeaviateVectorStore
w_store = WeaviateVectorStore(
client=client,
index_name="KB", # 클래스명
text_key="text", # page_content가 저장될 필드
embedding=emb,
)
w_store.add_documents(chunks)
# 간단 검색
docs = w_store.similarity_search("포인트 환불 규정", k=4)
for d in docs:
print(d.metadata.get("source"), d.page_content[:100])
팁: Weaviate는 기본 HNSW 인덱스. 외부 임베딩을 쓰면 클래스 스키마의 내장 벡터라이저를 끄고(vectorizer: none) 사용하세요. 하이브리드 검색은 BM25 + 벡터를 혼합해 정확도를 끌어올릴 수 있습니다.
5. Chroma — 빠른 개발·경량 운영(로컬/서버)

장점: 매우 간단한 API, 로컬 퍼시스턴스, Chroma Server(HTTP) 로 멀티 언어/멀티 프로세스 접근 가능.
단점: 대규모/고가용성·멀티리전 요구에는 한계. 동시 쓰기 패턴은 신중히 설계.
5-1. 인덱싱/퍼시스트
# 권장: 별도 패키지
from langchain_chroma import Chroma
# (대안) from langchain_community.vectorstores import Chroma
chroma_store = Chroma(
collection_name="kb",
persist_directory="indexes/chroma_kb", # 로컬 디렉터리로 영속화
embedding_function=emb,
)
# 적재
chroma_store.add_documents(chunks)
chroma_store.persist() # 디스크에 저장
5-2. 검색/리트리버
# 재시작 시에도 같은 persist_directory/collection_name으로 로드 가능
chroma_store = Chroma(
collection_name="kb",
persist_directory="indexes/chroma_kb",
embedding_function=emb,
)
retriever = chroma_store.as_retriever(search_kwargs={"k": 4})
results = retriever.invoke("취소/환불 정책 요약해줘")
for r in results:
print(r.metadata.get("source"), r.page_content[:120])
팁: Chroma Server 모드(HTTP)로 띄우면 여러 서비스/언어에서 공용 접근 가능. 로컬 퍼시스턴스는 백업/락 전략을 함께 고려하세요.
6. Postgres + pgvector — RDB 통합형(권한/트랜잭션 재사용)

장점: SQL/트랜잭션/백업·권한 체계 재활용, 운영팀 친화적.
단점: 전용 벡터 DB 대비 대규모·고QPS에서 성능 한계.
사전 준비: DB에 pgvector 확장 설치
CREATE EXTENSION IF NOT EXISTS vector;
6-1. 인덱싱(적재)
신규 패키지 권장
from langchain_postgres import PGVector
CONN = "postgresql+psycopg2://user:pass@localhost:5432/vecdb"
COLL = "kb"
pg_store = PGVector.from_documents(
documents=chunks,
embedding=emb,
collection_name=COLL,
connection=CONN, # 또는 connection_string=CONN
use_jsonb=True, # 메타데이터를 JSONB로 저장
)
(레거시 대안)
from langchain_community.vectorstores import PGVector
CONN = "postgresql+psycopg2://user:pass@localhost:5432/vecdb"
COLL = "kb"
pg_store = PGVector.from_documents(
documents=chunks,
embedding=emb,
collection_name=COLL,
connection_string=CONN,
)
6-2. 검색/리트리버
retriever = pg_store.as_retriever(
search_kwargs={"k": 4, "filter": {"doc_type": "kb"}}
)
for d in retriever.invoke("포인트 전환 기준은?"):
print(d.metadata.get("source"), d.page_content[:100])
팁: 최신 pgvector는 HNSW 인덱스를 지원합니다. 대량 적재 후 ANALYZE, 인덱스 파라미터(ef_search 등)를 튜닝해 보세요.
7. Redis Vector — 초저지연/TTL 캐시형

장점: 인메모리 기반 낮은 지연, TTL/세션/실시간 데이터에 적합(추천/랭킹 캐시 등).
단점: 메모리 비용, 영속성·백업 전략 필요. Redis Stack/Enterprise(벡터 검색 지원) 권장.
7-1. 인덱싱(적재)
from langchain_community.vectorstores import Redis
REDIS_URL = "redis://:password@localhost:6379"
INDEX = "kb"
redis_store = Redis.from_documents(
documents=chunks,
embedding=emb,
index_name=INDEX,
redis_url=REDIS_URL,
distance_metric="COSINE", # 또는 "L2", "IP"
)
7-2. 검색/리트리버
retriever = redis_store.as_retriever(search_kwargs={"k": 4})
for d in retriever.invoke("환불 처리 SLA는?"):
print(d.metadata.get("source"), d.page_content[:120])
팁: TTL 컬렉션으로 세션성 데이터(예: 일시적 문맥)를 저장하면 메모리 회수가 쉬워집니다. 다중 서비스에서 쓰면 Keyspace/Prefix, 백업(RDB/AOF) 정책을 함께 설계하세요.
8. 하이브리드/앙상블 리트리버 (선택)
키워드 매칭이 강한 데이터(정책/규정)에는 BM25 + 벡터를 섞으면 리콜/정확도가 좋아집니다.
from langchain_community.retrievers import BM25Retriever
from langchain.retrievers import EnsembleRetriever
bm25 = BM25Retriever.from_documents(chunks); bm25.k = 4
vec_ret = faiss_store.as_retriever(search_kwargs={"k": 4})
ensemble = EnsembleRetriever(retrievers=[bm25, vec_ret], weights=[0.3, 0.7])
docs = ensemble.get_relevant_documents("체크인 시간 정책")
9. RAG 체인에 연결 (LCEL)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
PROMPT = ChatPromptTemplate.from_template(
"""
너는 고객지원 봇이야. 다음 컨텍스트를 근거로 간결하고 정확히 답해.
컨텍스트:
{context}
질문: {question}
"""
)
def format_docs(docs):
return "
".join(f"[source: {d.metadata.get('source')}]
{d.page_content}" for d in docs)
# 예: 어떤 스토어 리트리버든 교체 가능 (FAISS/Chroma/Pinecone/Weaviate/PG/Redis)
retriever = faiss_store.as_retriever(search_kwargs={"k": 4})
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| PROMPT
| llm
| StrOutputParser()
)
print(rag_chain.invoke("노쇼(No-show) 수수료는?"))
10. 1000명 규모 사내 서비스에서 무엇을 쓸까? (의사결정 가이드)
전제: 월간 수십만 쿼리, 청크 수 50만~수백만, 읽기 중심 + 가끔 업데이트, 사내 인증/접근 제어 필요.
[추천 시나리오]
- 운영 편의/안정성 최우선(권장) → Pinecone Serverless
- 장점: 자동 확장, 고가용성, 손쉬운 메타데이터 필터/네임스페이스, SDK/에코시스템 성숙.
- 내부 1,000명 규모에서 운영 인력 최소화와 SLA를 고려하면 총소유비용(TCO)이 낮아지는 경우가 많습니다.
- 자가 호스팅 우선(보안/데이터 주권) → Qdrant 또는 Milvus
- Qdrant: 비교적 경량·설치/운영 쉬움, HNSW 성능 우수, ACL/샤딩/복제 지원(Cloud도 존재).
- Milvus: 대규모(수억 벡터)·고성능에 강함. 다만 클러스터 운영 복잡도가 높음.
- 경량/팀 자율 운영 + 중소 규모 → Chroma Server 또는 FAISS + (앱)서버 메모리
- QPS가 낮고 데이터가 수십만 청크 이하, 단일 리전·내부 사용이라면 간단히 구축 가능.
- 단, 동시 쓰기/롤백/백업/HA 요구가 높아지면 매니지드/클러스터로 전환을 고려.
- 기존 검색 인프라와 통합 → Elasticsearch/OpenSearch kNN
- 키워드/필터/로그 분석과의 동일 스택 유지. 하이브리드 검색 구성이 용이.
- RDB 선호/간단 통합 → Postgres + pgvector
- 트랜잭션·권한·백업 체계 재활용. 최신버전의 HNSW 인덱스 옵션으로 성능 개선.
- 대규모·고QPS에는 전용 DB 대비 성능 한계가 있음.
- 초저지연/세션 캐시/TTL 데이터 → Redis Vector
- 인메모리 지연이 매우 낮음. 단, 메모리·영속성 비용/전략 필수.
결론(요약)
1000명 규모 사내 서비스에서 운영 인력 최소 + 고가용성을 원하면 Pinecone가 가장 무난합니다.
온프레미스나 비용 최적화/커스텀 컨트롤이 중요하면 Qdrant(간편) → Milvus(초대규모) 순으로 고려.
경량 PoC/중소 규모에는 Chroma(Server) 또는 FAISS도 충분히 실용적입니다.
사내 RDB 재사용이 중요하면 Postgres + pgvector, 초저지연이면 Redis Vector를 보조 저장소로.
11. 기타 주목할 벡터 DB 한눈에 보기
제품배포핵심 포인트언제 추천?
| Qdrant | OSS/Cloud | HNSW, 쉬운 운영, 필터·샤딩·복제 | 자가 호스팅/중대형, 비용·통제 균형 |
| Milvus | OSS/Cloud | 초대규모, 다채로운 인덱스(IVF, HNSW, DiskANN 등) | 억 단위 벡터, 고성능·전담 운영팀 |
| Elasticsearch/OpenSearch kNN | OSS/Cloud | 키워드+벡터, 성숙한 생태계 | 기존 ES 스택과 결합, 로그·필터 풍부 |
| Postgres + pgvector | OSS/Cloud | SQL/트랜잭션·권한·백업 재사용 | 데이터 적당(수십만~수백만), 운영 단순 |
| Redis Vector | OSS/Cloud | 인메모리, 낮은 지연 | 짧은 TTL/실시간 지연 민감 서비스 |
12. 언제 무엇을 쓰나? (업데이트)
| 상황 | 추천 스토어 | 이유 |
| 로컬 PoC/데스크톱/임베디드 | FAISS·Chroma | 빠르고 무료, 퍼시스트 쉬움 |
| 소규모~대규모 운영, 쉬운 스케일 | Pinecone | 서버리스/고가용성/메타필터/Namespace |
| 스키마·복합 질의/자가 호스팅 옵션 | Weaviate | 강력한 스키마/필터, 오픈소스·클라우드 |
| 온프레미스/자체운영 중대형 | Qdrant·Milvus | 비용·통제·성능 균형(운영 복잡도 차등) |
| 기존 검색 스택 유지 | OpenSearch/Elasticsearch | 키워드+벡터 하이브리드 손쉬움 |
| RDB 환경 선호 | Postgres+pgvector | SQL 생태계 재활용, 운영 단순 |
| 초저지연/세션성 | Redis Vector | 인메모리 검색, TTL 캐시/랭킹 등에 적합 |
'RAG' 카테고리의 다른 글
| RAG Bot 만들기: Generation 파트 — Retrieval·LLM 결합, RetrievalQA, 프롬프트 전략, 대화 메모리 (5) | 2025.08.16 |
|---|---|
| 문서 인덱싱과 검색 — 벡터 스토어 구축 · Semantic Search 구현 (3) | 2025.08.16 |
| [LangChain] 문서 로딩과 전처리 가이드 (4) | 2025.08.16 |
| LangSmith로 LangChain 체인/에이전트 관측과 평가하기 (3) | 2025.08.16 |
| LangChain 핵심 모듈 이해: LLMs · Prompts · Chains · Agents (8) | 2025.08.16 |
- Total
- Today
- Yesterday
- chat gpt 한국어 가격
- chat gpt api 비용 계산
- 토치비전
- 로또 ai
- 오블완
- Python
- 기술적분석
- 장고 orm sql문 비교
- 로또 1164회 당첨
- chat gpt 모델별 예산
- 1165회 로또
- 자동매매
- 자동매매로직
- chat gpt 가격 예상
- 주식공부
- chat gpt 4o 예산
- 티스토리챌린지
- Numpy
- 클래스형 뷰
- 1164회 로또
- chat gpt 모델 별 가격
- chat gpt 모델 api 가격 예측
- 케라스
- 주식투자
- 퀀트투자
- 인공지능 로또 예측
- 차트분석
- 주린이탈출
- 재테크
- 골든크로스
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |