🤖 AI/ML

Chroma

ChromaDB - Open Source Embedding Database

오픈소스 임베딩(벡터) 데이터베이스입니다. LangChain, LlamaIndex 등 주요 AI 프레임워크와 쉽게 통합되어 RAG 시스템 구축, 시맨틱 검색, AI 애플리케이션 개발에 널리 활용됩니다.

📖 상세 설명

Chroma(ChromaDB)는 AI 네이티브 오픈소스 임베딩 데이터베이스로, 텍스트, 이미지 등의 데이터를 벡터(임베딩) 형태로 저장하고 유사도 기반 검색을 수행할 수 있게 해주는 시스템입니다. "The AI-native open-source embedding database"라는 슬로건처럼, LLM 기반 애플리케이션 개발에 최적화되어 있으며, 특히 RAG(Retrieval-Augmented Generation) 시스템 구축에 핵심적인 역할을 합니다.

Chroma는 2022년에 설립된 스타트업에서 개발했으며, LLM 애플리케이션의 급격한 성장과 함께 빠르게 인기를 얻었습니다. Apache 2.0 라이선스로 완전히 오픈소스로 제공되며, 로컬 개발부터 프로덕션 배포까지 다양한 환경을 지원합니다. LangChain, LlamaIndex, Haystack 등 주요 AI 프레임워크들과 기본 통합되어 있어 개발자들이 쉽게 도입할 수 있습니다.

Chroma의 핵심 원리는 고차원 벡터 공간에서의 유사도 검색입니다. 텍스트나 이미지를 임베딩 모델을 통해 수백~수천 차원의 벡터로 변환한 후, 코사인 유사도(Cosine Similarity), L2 거리(Euclidean Distance), 내적(Inner Product) 등의 메트릭을 사용해 가장 유사한 항목들을 효율적으로 검색합니다. HNSW(Hierarchical Navigable Small World) 알고리즘을 사용하여 대규모 데이터셋에서도 빠른 검색 성능을 제공합니다.

실무에서 Chroma는 다양한 용도로 활용됩니다. RAG 시스템에서 문서 청크를 저장하고 질문에 관련된 문맥을 검색하는 데 사용되며, 시맨틱 검색 엔진 구축, 추천 시스템, 중복 감지, 클러스터링 등에도 적용됩니다. 메타데이터 필터링을 지원하여 벡터 검색과 전통적인 필터링을 결합할 수 있고, 로컬 인메모리 모드부터 클라이언트-서버 모드, 클라우드 호스팅까지 유연한 배포 옵션을 제공합니다.

💻 코드 예제

Chroma를 사용하여 문서를 저장하고 시맨틱 검색을 수행하는 Python 코드입니다.

Python
# pip install chromadb openai
import chromadb
from chromadb.utils import embedding_functions

# Chroma 클라이언트 생성 (영구 저장소 사용)
client = chromadb.PersistentClient(path="./chroma_db")

# OpenAI 임베딩 함수 설정
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key="your-openai-api-key",
    model_name="text-embedding-3-small"  # 또는 text-embedding-3-large
)

# 컬렉션 생성 또는 가져오기
collection = client.get_or_create_collection(
    name="documents",
    embedding_function=openai_ef,
    metadata={"hnsw:space": "cosine"}  # 유사도 메트릭 설정
)

# 문서 추가
documents = [
    "인공지능은 인간의 학습능력과 추론능력을 컴퓨터로 구현하는 기술입니다.",
    "머신러닝은 데이터로부터 패턴을 학습하여 예측하는 AI의 하위 분야입니다.",
    "딥러닝은 인공 신경망을 사용하여 복잡한 패턴을 학습하는 기법입니다.",
    "자연어 처리(NLP)는 컴퓨터가 인간의 언어를 이해하고 생성하는 기술입니다.",
    "RAG는 검색과 생성을 결합하여 LLM의 응답 품질을 높이는 기법입니다."
]

# 메타데이터와 함께 문서 추가
collection.add(
    documents=documents,
    metadatas=[
        {"category": "AI", "level": "basic"},
        {"category": "ML", "level": "intermediate"},
        {"category": "DL", "level": "advanced"},
        {"category": "NLP", "level": "intermediate"},
        {"category": "RAG", "level": "advanced"}
    ],
    ids=[f"doc_{i}" for i in range(len(documents))]
)

print(f"컬렉션에 {collection.count()}개의 문서가 저장되었습니다.")

# 시맨틱 검색 수행
def semantic_search(query: str, n_results: int = 3, filter_dict: dict = None):
    """
    시맨틱 검색을 수행하는 함수

    Args:
        query: 검색 쿼리
        n_results: 반환할 결과 수
        filter_dict: 메타데이터 필터 (예: {"category": "AI"})

    Returns:
        검색 결과
    """
    results = collection.query(
        query_texts=[query],
        n_results=n_results,
        where=filter_dict,  # 메타데이터 필터링
        include=["documents", "metadatas", "distances"]
    )

    return results

# 검색 예시 1: 일반 시맨틱 검색
print("\n=== 검색: '신경망과 학습' ===")
results = semantic_search("신경망과 학습")
for doc, meta, dist in zip(
    results['documents'][0],
    results['metadatas'][0],
    results['distances'][0]
):
    print(f"[유사도: {1-dist:.4f}] {doc[:50]}... ({meta['category']})")

# 검색 예시 2: 메타데이터 필터링과 함께
print("\n=== 검색: 'AI 기술' (고급 수준만) ===")
results = semantic_search(
    "AI 기술",
    n_results=2,
    filter_dict={"level": "advanced"}
)
for doc, meta in zip(results['documents'][0], results['metadatas'][0]):
    print(f"[{meta['level']}] {doc[:50]}...")

# LangChain 통합 예시
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# LangChain용 Chroma 벡터스토어
vectorstore = Chroma(
    collection_name="langchain_docs",
    embedding_function=OpenAIEmbeddings(),
    persist_directory="./langchain_chroma_db"
)

# 리트리버로 사용
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

🗣️ 실무 대화 예시

팀장 "RAG 시스템에 사용할 벡터 데이터베이스를 정해야 하는데, Chroma와 Pinecone 중 어떤 게 좋을까요?"
개발자 "프로토타입이나 소규모 프로젝트라면 Chroma가 좋습니다. 오픈소스에 로컬에서 바로 실행 가능하고, LangChain 통합도 간단해요. 비용도 없고요."
팀장 "프로덕션에서 대규모로 쓸 때는 어떤가요?"
개발자 "대규모라면 Pinecone이나 Weaviate 같은 관리형 서비스가 안정적이에요. 하지만 Chroma도 서버 모드로 배포 가능하고, 백만 단위 문서까지는 충분히 커버합니다. 비용 대비 성능을 따져보고 결정하죠."
면접관 "Chroma에서 HNSW 알고리즘이 어떻게 동작하는지 설명해주세요."
지원자 "HNSW는 계층적 그래프 구조를 사용합니다. 상위 레이어에서 빠르게 대략적인 위치를 찾고, 하위 레이어로 내려가며 정밀하게 탐색해요. 전체 벡터를 스캔하지 않고도 근사 최근접 이웃을 O(log N) 수준으로 찾을 수 있습니다."
면접관 "정확도와 속도 사이의 트레이드오프는 어떻게 조절하나요?"
지원자 "ef_search 파라미터로 조절합니다. 값이 클수록 더 많은 노드를 탐색해서 정확도가 높아지지만 속도는 느려져요. 또한 인덱스 생성 시 ef_construction과 M 값으로 그래프의 연결성을 조절할 수 있습니다."
시니어 "매 요청마다 PersistentClient를 새로 생성하고 있네요. 이건 비효율적이에요."
주니어 "아, 클라이언트를 전역으로 한 번만 생성하고 재사용해야 하는 거군요. 싱글톤 패턴으로 바꾸겠습니다."
시니어 "맞아요. 그리고 collection.add()에서 중복 ID 체크가 없어요. 같은 문서를 다시 추가하면 upsert가 아니라 에러가 납니다. get()으로 존재 여부 확인하거나 upsert()를 사용하세요."
주니어 "collection.upsert()로 변경하고, 배치 사이즈도 조절해서 대량 삽입 시 메모리 이슈도 방지하겠습니다."

⚠️ 주의사항

🔗 관련 용어

📚 더 배우기