반응형
Notice
Recent Posts
Recent Comments
Link
«   2025/11   »
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
Tags more
Archives
Today
Total
관리 메뉴

아톨러브

벡터DB, Qdrant를 활용한 벡터 검색 워크플로우 정리 본문

AI, 클라우드, 문서, 자동화

벡터DB, Qdrant를 활용한 벡터 검색 워크플로우 정리

아톨 2025. 7. 20. 19:29
반응형

세 가지 Python 코드는 Qdrant 벡터 데이터베이스를 활용한 기본적인 벡터 검색 워크플로우를 보여줍니다. 각 코드가 어떤 역할을 하는지, 그리고 전체적인 흐름은 어떻게 되는지 상세히 정리합니다.

전체 워크플로우 개요

이 세 가지 코드는 다음과 같은 순서로 실행되어야 하며, 각기 다른 역할을 수행합니다.

  1. 첫 번째 코드: Qdrant에 벡터를 저장할 **컬렉션(Collection)**을 생성합니다.
  2. 두 번째 코드: OpenAI 임베딩 모델을 사용하여 텍스트를 벡터로 변환한 후, 이 벡터들을 생성된 컬렉션에 **삽입(Upsert)**합니다.
  3. 세 번째 코드: 새로운 텍스트를 벡터로 변환한 후, 이 쿼리 벡터와 가장 유사한 벡터들을 컬렉션에서 **검색(Query)**합니다.

이 과정은 RAG(Retrieval Augmented Generation) 시스템의 "Retrieval" 부분의 핵심적인 동작 방식과 유사합니다.

1. 첫 번째 코드 해설: Qdrant 컬렉션 생성

이 코드는 Qdrant 서버에 데이터를 저장할 공간인 '컬렉션'을 정의하고 생성합니다.

from qdrant_client import QdrantClient # Qdrant 서버와 통신하기 위한 클라이언트 라이브러리
from qdrant_client.models import Distance, VectorParams # Qdrant 모델 정의 (거리 측정 방식, 벡터 파라미터)

client = QdrantClient(host="localhost", port=6333) # Qdrant 클라이언트 초기화. 로컬 Qdrant 서버에 연결합니다.

collection_name = "test3" # 생성할 컬렉션의 이름을 'test3'으로 정의합니다.

response = client.create_collection( # Qdrant 클라이언트를 통해 컬렉션을 생성합니다.
    collection_name = collection_name, # 컬렉션 이름 지정
    vectors_config = VectorParams(size = 1536, distance=Distance.COSINE) # 벡터 저장소 설정
    # size = 1536: 이 컬렉션에는 1536차원의 벡터만 저장할 수 있습니다.
    #              이는 OpenAI의 'text-embedding-3-small' 모델이 기본적으로 1536차원 벡터를 생성하기 때문에 이에 맞춰 설정한 것입니다.
    # distance=Distance.COSINE: 벡터 간의 유사도를 코사인 유사도 방식으로 측정합니다.
)

print(response) # 컬렉션 생성 작업의 성공 여부를 출력합니다. (성공 시 True)

코드의 역할:

  • Qdrant에 test3라는 이름의 빈 컬렉션을 만듭니다.
  • 이 컬렉션은 1536차원의 벡터만 저장할 수 있으며, 벡터 유사도 계산에는 코사인 유사도 방식이 사용됩니다.
  • 실행 전제: Qdrant 서버가 localhost:6333에서 실행 중이어야 합니다.
  • 실행 결과: 성공 시 True를 출력합니다. (만약 이미 test3 컬렉션이 존재하면 에러가 발생할 수 있으므로, 실제 환경에서는 client.recreate_collection을 사용하는 것이 더 안전합니다.)

2. 두 번째 코드 해설: 텍스트 임베딩 및 Qdrant에 데이터 삽입 (Upsert)

이 코드는 OpenAI 임베딩 모델을 사용하여 텍스트를 고차원 벡터로 변환하고, 이 벡터들과 원본 텍스트 정보를 Qdrant의 test3 컬렉션에 저장합니다.

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct # PointStruct: Qdrant에 저장될 데이터(ID, 벡터, 페이로드) 구조 정의
import openai # OpenAI API와 통신하기 위한 라이브러리
from dotenv import load_dotenv # .env 파일에서 환경 변수를 로드하기 위한 라이브러리
import os # 운영체제 환경 변수에 접근하기 위한 모듈

load_dotenv() # .env 파일(예: .env)에 정의된 환경 변수들을 현재 스크립트의 환경 변수로 로드합니다.
openai_api_key = os.getenv("OPENAI_API_KEY") # 환경 변수에서 OpenAI API 키를 가져옵니다.
# if not openai_api_key: # API 키가 없는 경우 에러를 발생시키는 로직 (원래 코드에는 없지만 추가 권장)
#     raise ValueError("OPENAI_API_KEY 환경 변수가 설정되지 않았습니다.")

client = QdrantClient(host= "localhost", port=6333) # Qdrant 클라이언트 초기화
openai_client = openai.OpenAI(api_key= openai_api_key) # OpenAI 클라이언트 초기화. API 키를 사용하여 OpenAI 서비스에 접근합니다.

# 첫 번째 텍스트 리스트를 임베딩합니다.
response = openai_client.embeddings.create(
    input = ["한국인, 미국인, 프랑스인"], # 임베딩할 텍스트입니다. 리스트 형태로 여러 텍스트를 한 번에 임베딩할 수 있습니다.
    model = "text-embedding-3-small", # 사용할 OpenAI 임베딩 모델입니다. 이 모델은 1536차원 벡터를 생성합니다.
)
# 두 번째 텍스트 리스트를 임베딩합니다.
response2 = openai_client.embeddings.create(
    input = ["독일인, 중국인"],
    model = "text-embedding-3-small",
)

points =[ # Qdrant에 저장할 포인트(PointStruct) 리스트를 정의합니다.
    PointStruct( # 첫 번째 포인트: ID 1번
        id = 1, # 포인트의 고유 ID
        vector = response.data[0].embedding, # 첫 번째 임베딩 결과의 벡터 (response.data[0].embedding은 1536차원 벡터)
        payload = {"name": "한국인, 미국인, 프랑스인"}, # 벡터와 연결된 메타데이터. 원본 텍스트를 저장하여 검색 후 활용할 수 있습니다.
    ),
    PointStruct( # 두 번째 포인트: ID 2번
        id =2,
        vector = response2.data[0].embedding, # 두 번째 임베딩 결과의 벡터
        payload ={"name": "독일인, 중국인"},
    ),
]

response = client.upsert( # Qdrant 클라이언트를 통해 정의된 포인트들을 컬렉션에 삽입하거나 업데이트합니다.
    collection_name = "test3", # 포인트를 삽입할 대상 컬렉션 (첫 번째 코드에서 생성한 'test3' 컬렉션)
    points= points, # 삽입할 포인트 리스트
)
# print(response) # upsert 작업의 성공 여부를 출력할 수 있습니다. (성공 시 status: ok)

코드의 역할:

  • OPENAI_API_KEY 환경 변수를 로드합니다.
  • OpenAI의 text-embedding-3-small 모델을 사용하여 두 개의 텍스트("한국인, 미국인, 프랑스인", "독일인, 중국인")를 각각 1536차원 벡터로 변환합니다.
  • 변환된 벡터와 원본 텍스트를 페이로드로 포함하는 두 개의 PointStruct 객체를 생성합니다.
  • 이 포인트들을 test3 컬렉션에 upsert (삽입 또는 업데이트)합니다.
  • 실행 전제:
    • test3 컬렉션이 첫 번째 코드를 통해 미리 생성되어 있어야 합니다.
    • .env 파일에 OPENAI_API_KEY가 올바르게 설정되어 있어야 합니다.
    • openaipython-dotenv 라이브러리가 설치되어 있어야 합니다 (pip install openai python-dotenv).
  • 실행 결과: test3 컬렉션에 두 개의 벡터 데이터가 저장됩니다.

3. 세 번째 코드 해설: Qdrant 컬렉션에서 벡터 검색 (Query)

이 코드는 새로운 질의 텍스트를 벡터로 변환한 후, test3 컬렉션에 저장된 벡터들 중에서 이 질의 벡터와 가장 유사한 벡터들을 찾아 반환합니다.

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct # 필요한 모델 임포트
import openai
from dotenv import load_dotenv
import os

load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key: # API 키가 없는 경우 에러 발생
    raise ValueError("OPENAI_API_KEY 환경 변수가 설정되지 않았습니다.")
openai_client = openai.OpenAI(api_key=openai_api_key) # OpenAI 클라이언트 초기화

client = QdrantClient(host="localhost", port = 6333) # Qdrant 클라이언트 초기화
try:
    collections = client.get_collections() # Qdrant 서버에 연결하여 현재 존재하는 컬렉션 목록을 가져옵니다.
    print("Qdrant 클라이언트 연결 및 컬렉션 정보 가져오기 성공:", collections) # 연결 성공 메시지와 컬렉션 목록 출력
except Exception as e:
    print(f"Qdrant 클라이언트 연결 또는 작업 중 오류 발생: {e}") # 연결 실패 시 오류 메시지 출력

# 검색할 질의 텍스트를 임베딩합니다.
response = openai_client.embeddings.create(
    input ="한국인이 들어있는 POINT", # 검색 질의 텍스트
    model = "text-embedding-3-small", # 임베딩 모델은 데이터 삽입 시 사용한 모델과 동일해야 합니다.
)
query_vector = response.data[0].embedding # 생성된 쿼리 벡터를 가져옵니다.

search_response = client.query_points( # Qdrant 클라이언트를 사용하여 벡터 유사도 검색을 수행합니다.
    collection_name = "test3", # 검색 대상 컬렉션
    query = query_vector,     # 검색 기준이 되는 쿼리 벡터
    limit = 2,                # 가장 유사한 상위 2개의 결과만 반환
    with_payload = True,      # 검색 결과에 페이로드(메타데이터) 포함
)

print(search_response) # 검색 결과 객체 전체를 출력합니다.
# 이 객체는 search_response.points 속성에 검색된 PointStruct 리스트를 포함합니다.
# 각 PointStruct는 id, vector, payload, score 속성을 가집니다.

코드의 역할:

  • OPENAI_API_KEY를 로드하고 OpenAI 클라이언트를 초기화합니다.
  • Qdrant 서버에 연결하여 컬렉션 목록을 확인합니다 (연결 상태 확인용).
  • 질의 텍스트 "한국인이 들어있는 POINT"를 OpenAI 임베딩 모델로 1536차원 벡터로 변환합니다.
  • 변환된 쿼리 벡터를 사용하여 test3 컬렉션에서 가장 유사한 상위 2개의 포인트를 검색합니다.
  • 검색된 포인트의 ID, 벡터, 페이로드, 유사도 점수를 포함하는 search_response 객체를 출력합니다.
  • 실행 전제:
    • 첫 번째 코드와 두 번째 코드가 성공적으로 실행되어 test3 컬렉션이 생성되고 데이터가 삽입되어 있어야 합니다.
    • openaipython-dotenv 라이브러리가 설치되어 있어야 합니다.
  • 실행 결과: query_vector와 가장 유사한 test3 컬렉션 내의 포인트들이 반환됩니다. query_vector = "한국인이 들어있는 POINT""한국인, 미국인, 프랑스인" 벡터와 더 유사할 것이므로, id=1인 포인트가 더 높은 점수로 검색될 것입니다.

실행 순서 요약

이 세 가지 코드를 순서대로 실행해야 전체 워크플로우가 정상적으로 작동합니다.

  1. 1.py (컬렉션 생성 코드) 실행:
  2. python 1.py
  3. 2.py (데이터 삽입 코드) 실행:
  4. python 2.py
  5. 3.py (데이터 검색 코드) 실행:
  6. python 3.py

이 과정을 통해 Qdrant를 이용한 벡터 데이터베이스의 기본 동작 방식(컬렉션 생성 - 데이터 삽입 - 데이터 검색)을 이해하실 수 있을 것입니다.

반응형