목차
0. 개요
Retriever를 사용하기 위해서는 검색 대상이 되는 벡터스토어(VectorStore)를 먼저 만들어야 한다.
벡터스토어(VectorStore)란 문서(텍스트 등)를 벡터 형태로 변환해서 저장하고, 유사도를 기반으로 빠르게 검색할 수 있게 해주는 구조이다.
일반적으로 문서를 검색할 때 키워드 매칭(예: Elasticsearch)을 많이 사용한다. 하지만 GPT와 같은 대규모 언어 모델(LLM)과 결합해 좀 더 ‘의미’ 기반의 검색, 즉 “유사한 문장을 찾는” 등의 기능을 위해서는 단어 자체가 아닌, 문장의 의미를 담고 있는 벡터(embedding)가 필요하다.
벡터스토어의 핵심 기능은 다음과 같다.
- 삽입(Insertion): 텍스트를 받아 임베딩으로 변환한 후, 벡터 형태로 DB(혹은 인덱스)에 저장
- 검색(Search): 질의문(query)을 임베딩으로 변환해, 저장된 벡터들과 유사도(코사인 유사도 등)를 계산. 그 결과값(상위 유사도 문서)을 반환
벡터 스토어의 종류는 아래와 같다.
상황에 맞게 골라 사용하면 되겠다.
- 간단한 로컬 테스트: FAISS, Chroma
- 대규모 클라우드 서비스 / 완전관리형: Pinecone, Weaviate(Managed), Qdrant(Cloud)
- 오픈소스 + 대용량 확장: Milvus, Weaviate, Qdrant
- 기존 Elasticsearch 사용 중: Elasticsearch 벡터 기능
- PostgreSQL 환경: pgvector (Supabase)
1. FAISS
1.1. FAISS 설명
FAISS(Facebook AI Similarity Search)는 고차원 벡터 데이터를 효율적으로 검색하기 위한 라이브러리
장점
- 빠른 벡터 검색, 근사 최근접 이웃(ANN) 검색
- GPU 지원
- 오픈소스 & 사용 용이
단점
- 데이터 영구 저장 기능이 없음 → 별도로 저장해야 함 (faiss.write_index(), faiss.read_index())
- 실시간 삽입/삭제 기능 부족 → 일괄 삽입 후 검색하는 구조
- 대규모 클러스터링 기능 부족 → Pinecone, Weaviate가 더 적합
1.2. FAISS 사용 방법
FAISS 생성
import faiss
from langchain_community.docstore.in_memory import InMemoryDocstore
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# 사용할 임베딩 정의
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
# faiss index 정의
index = faiss.IndexFlatL2(len(embeddings.embed_query("hello world")))
# 벡터스토어 정의
vector_store = FAISS(
embedding_function=embeddings,
index=index,
docstore=InMemoryDocstore(),
index_to_docstore_id={},
)
데이터 저장
- vector_store.add_documents()
from uuid import uuid4
from langchain_core.documents import Document
document_1 = Document(
page_content="I had chocalate chip pancakes and scrambled eggs for breakfast this morning.",
metadata={"source": "tweet"},
)
document_2 = Document(
page_content="The weather forecast for tomorrow is cloudy and overcast, with a high of 62 degrees.",
metadata={"source": "news"},
)
# 데이터 정리
documents = [
document_1,
document_2,
]
# 키값 생성
uuids = [str(uuid4()) for _ in range(len(documents))]
# 데이터 저장
vector_store.add_documents(documents=documents, ids=uuids)
데이터 삭제
- vector_store.delete()
vector_store.delete(ids=[uuids[-1]])
쿼리 벡터 생성 및 유사 벡터 검색
- vector_store.similarity_search()
- 메타데이터를 필터링 가능
results = vector_store.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
filter={"source": "tweet"},
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
필터링을 사용한 쿼리
- $eq (equals)
- $neq (not equals)
- $gt (greater than)
- $lt (less than)
- $gte (greater than or equal)
- $lte (less than or equal)
- $in (membership in list)
- $nin (not in list)
- $and (all conditions must match)
- $or (any condition must match)
- $not (negation of condition)
results = vector_store.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
filter={"source": {"$eq": "tweet"}},
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
리트리버로 쿼리 검색
retriever = vector_store.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("Stealing from the bank is a crime", filter={"source": "news"})
벡터스토어 저장하기(Saving)
vector_store.save_local("faiss_index")
벡터스토어 불러오기(Loading)
new_vector_store = FAISS.load_local(
"faiss_index", embeddings, allow_dangerous_deserialization=True
)
2. ElasticSearch
2.1. ElasticSearch 설명
문서 검색 + 유사도 검색(키워드 + 벡터 기반 검색 가능)
대용량 데이터 처리 가능
자연어 검색(NLP) 및 벡터 검색을 혼합 가능
2.1. ElasticSearch 실행하기
먼저, ElasticSearch 서버를 실행하도록 한다.
예를 들어 Docker로 실행하면 아래와 같다.
docker run -d --name elasticsearch \
-p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
docker.elastic.co/elasticsearch/elasticsearch:8.6.0
다음으로 Kibana를 실행해서 ElasticSearch를 제어할 수 있는 화면을 실행한다.
Kibana가 설치되어 있다면, 브라우저에서 http://localhost:5601로 접속
만약 Kibana가 실행되지 않았다면, Docker로 실행해 보자
docker run -d --name kibana --link elasticsearch:elasticsearch -p 5601:5601 docker.elastic.co/kibana/kibana:8.6.0
다음으로 Dev Tool로 이동한다.
다음으로, index를 생성해 준다. (데이터베이스의 테이블과 비슷한 것)
- Elasticsearch에서 "langchain_vectorstore"라는 인덱스를 생성
- settings : 인덱스 설정
- number_of_shards : 데이터 분할을 위한 샤드 개수 (1개 설정)
- number_of_replicas : 복제본(replica) 개수 (0개 설정)
- mappings : 데이터 필드 정의
- text : 필트 이름 text, { "type": "text" } → 이 필드는 일반적인 검색을 위한 텍스트 필드
- embedding : 필트 이름 embedding, type: "dense_vector" → 벡터 데이터를 저장하기 위한 필드, "dims": 1536 → 이 벡터는 1536차원 (OpenAI Embedding 모델과 호환)
PUT langchain_vectorstore
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"text": { "type": "text" },
"embedding": { "type": "dense_vector", "dims": 1536 }
}
}
}
2.3. 사용 방법
벡터스토어 정의
from langchain_openai import OpenAIEmbeddings
from langchain_elasticsearch import ElasticsearchStore
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
elastic_vector_search = ElasticsearchStore(
es_url="http://localhost:9200",
index_name="langchain_index",
embedding=embeddings,
es_user="elastic",
es_password="changeme",
)
저장
vector_store.add_documents(documents=documents, ids=uuids)
삭제
vector_store.delete(ids=["id1", "id2"])
필터링을 사용한 쿼리
results = vector_store.similarity_search(
query="LangChain provides abstractions to make working with LLMs easy",
k=2,
filter=[{"term": {"metadata.source.keyword": "tweet"}}],
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
점수를 포함한 쿼리
results = vector_store.similarity_search_with_score(
query="Will it be hot tomorrow",
k=1,
filter=[{"term": {"metadata.source.keyword": "news"}}],
)
for doc, score in results:
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
리트리버로 전환하여 쿼리
retriever = vector_store.as_retriever(
search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.2}
)
retriever.invoke("Stealing from the bank is a crime")
3. 결론
세팅 자체는 어렵지 않다.
언제나 그렇듯이 데이터 전처리가 어려울 뿐...ㅎ
'자연어처리 > Langchain' 카테고리의 다른 글
[Langchain] Tools 사용하기 (1) (1) | 2025.03.18 |
---|---|
[Langchain] Custom Retriever 만들기 (0) | 2025.03.09 |
[langchain] 유저 채팅 토픽 분석 with BERTopic (1) | 2025.03.08 |
[Langchain] RAG 성능 평가 with Regas (0) | 2025.03.07 |
[Langchain] 임베딩(Embedding)과 유사도 검색 방법 for Retriever (0) | 2025.03.06 |