관리 메뉴

피터의 개발이야기

[AI] Weaviate Usage - VectorDB를 “검색 엔진”이 아니라 “의미 저장소”로 쓰는 법 본문

AI/AI이론 | 공부

[AI] Weaviate Usage - VectorDB를 “검색 엔진”이 아니라 “의미 저장소”로 쓰는 법

기록하는 백앤드개발자 2026. 2. 8. 16:03
반응형

 

 

[AI] LLM 학습 노트 공개 - Transformer부터 RAG까지, 그리고 운영 가능한 AI 시스템을 향해

 

ㅁ 들어가며

앞선 글에서 Embedding, Vector Similarity, HNSW까지 정리했다면,
이제 실제 VectorDB를 어떻게 쓰는지가 남는다.

이번 글에서는 Weaviate를 기준으로,

  • 스키마 설계
  • 데이터 삽입 흐름
  • 벡터 검색
  • 하이브리드 검색(BM25 + Vector)

을 정리한다.

 

중요한 점은 이것이다.

  Weaviate는 단순한 벡터 저장소가 아니라,
  “의미 기반 데이터 모델링 + 검색 엔진” 에 가깝다.

 

ㅁ 왜 Weaviate인가

VectorDB는 많다.
Qdrant, Milvus, Pinecone 등 선택지는 충분하다.

일전에 [AI] RAG구성을 위한 FAISS란?에서 FAISS를 정리하기도 하였다.

[AI] IntentFlow 프로젝트 회고 및 소개에서 실제로 사용해 보기도 하였다.

 

Weaviate의 특징은 다음이다.

  • 스키마 기반 데이터 모델
  • GraphQL 중심 쿼리
  • 자동 벡터화 모듈
  • 하이브리드 검색을 네이티브로 지원

특히 RAG 관점에서는
  BM25 + Vector를 자연스럽게 섞을 수 있다는 점이 크다.

 

즉,

  키워드 검색과 의미 검색을
  “둘 중 하나”가 아니라
  “같이” 가져갈 수 있다.

 

ㅁ 기본 구조 이해하기

Weaviate관계형 DB처럼 Class 기반 스키마를 가진다.

 

개념을 간단히 정리하면:

  • Class: 테이블
  • Property: 컬럼
  • Object: 로우
  • Vectorizer: 자동 임베딩 모듈

RAG용 문서 저장 시 보통 이런 구조를 쓴다.

  • content (텍스트)
  • source (파일명)
  • chunk_id (청크 번호)

즉, Chunk 단위 객체를 저장하는 방식이다.

 

ㅁ 로컬 실행 (Docker)

version: '3.4'

services:
  weaviate:
    image: semitechnologies/weaviate:1.24.1
    ports:
      - "8080:8080"
    environment:
      QUERY_DEFAULTS_LIMIT: 25
      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
      PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
      DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'
      ENABLE_MODULES: 'text2vec-openai,generative-openai'
      OPENAI_APIKEY: ${OPENAI_API_KEY}
      CLUSTER_HOSTNAME: 'node1'
    volumes:
      - weaviate_data:/var/lib/weaviate

volumes:
  weaviate_data:

 

실행:

docker-compose up -d

 

확인:

curl http://localhost:8080/v1/meta

 

ㅁ Python 클라이언트 연결

import weaviate

client = weaviate.Client("http://localhost:8080")
print(client.is_ready())

 

ㅁ 스키마 정의

RAG용 Document 클래스 예시는 다음과 같다.

class_obj = {
    "class": "Document",
    "vectorizer": "text2vec-openai",
    "properties": [
        {
            "name": "content",
            "dataType": ["text"]
        },
        {
            "name": "source",
            "dataType": ["string"]
        },
        {
            "name": "chunk_id",
            "dataType": ["int"]
        }
    ]
}

client.schema.create_class(class_obj)

여기서 핵심은:

  content 필드는 자동으로 임베딩된다.

 

즉, 애플리케이션에서 직접 embedding을 만들지 않아도 된다.

 

ㅁ 데이터 삽입

단일 삽입도 가능하지만, 실무에서는 반드시 batch를 쓴다.

with client.batch as batch:
    batch.batch_size = 100
    for doc in documents:
        batch.add_data_object(
            data_object={
                "content": doc["content"],
                "source": doc["source"],
                "chunk_id": doc["chunk_id"]
            },
            class_name="Document"
        )

이 단계에서 Weaviate는:

  • 텍스트 벡터화
  • HNSW 인덱싱
  • 객체 저장

을 자동으로 처리한다.

 

ㅁ 벡터 검색

result = (
    client.query
    .get("Document", ["content", "source"])
    .with_near_text({"concepts": ["RAG system architecture"]})
    .with_limit(5)
    .do()
)

질문을 넣으면:

  1. 쿼리를 벡터화
  2. HNSW로 근접 벡터 탐색
  3. Top-K 반환

전형적인 Dense Retrieval 흐름이다.

 

ㅁ 하이브리드 검색 (BM25 + Vector)

Weaviate의 핵심 기능.

result = (
    client.query
    .get("Document", ["content", "source"])
    .with_hybrid(
        query="RAG pipeline",
        alpha=0.5
    )
    .with_limit(5)
    .do()
)

alpha 의미:

  • 0.0 → BM25 only
  • 1.0 → Vector only
  • 0.5 → 균형

실무에서는 보통 0.4~0.6 사이에서 시작한다.

 

이 방식의 장점은:

  • 키워드 정확도 유지
  • 의미 검색 보완

즉,
  Sparse + Dense를 자연스럽게 결합한다.

 

 

ㅁ 메타데이터 필터링

.with_where({
    "path": ["source"],
    "operator": "Equal",
    "valueString": "rag_guide.md"
})

RAG에서는 보통:

  • source
  • doc_type
  • tenant

같은 필드를 함께 필터링한다.

  Retriever는 항상 “의미 + 조건”을 동시에 고려해야 한다.

 

 

ㅁ 운영 관점 팁

실무에서 중요한 포인트만 정리하면:

  • 반드시 batch insert 사용
  • HNSW ef 값 튜닝
  • 자주 쓰는 필드는 필터 인덱싱
  • alpha는 온라인 실험으로 결정
  • 벡터는 파생 데이터로 취급 (원본 문서가 SSOT)

VectorDB는 검색 엔진이 아니다.

의미 공간 인덱스다.

 

ㅁ RAG 파이프라인에서 Weaviate의 위치

전체 흐름은 항상 같다.

Document
  → Chunk
  → Weaviate 저장
  → Hybrid Retrieval
  → Rerank
  → LLM

 

Weaviate는 이 중 “의미 좌표계 + 후보 생성” 을 담당한다.

최종 품질은 RerankerPrompt에서 결정되지만,
  Retriever 품질이 바닥이면 그 위는 아무 의미가 없다.

 

 

ㅁ 마무리

Weaviate를 써보면서 느낀 점은 이것이다.

  VectorDB는 데이터베이스가 아니라 의미 인프라다.

  RAG 품질은 모델보다,

  Embedding보다,

  Chunking보다,

  Retriever 설계에서 가장 크게 갈린다.

 

그리고 Weaviate
  그 Retriever를 꽤 높은 수준으로 구성할 수 있게 해준다.

반응형
Comments