๐Ÿ“Œ ๋ฒกํ„ฐ DB ์ €์žฅํ•˜๊ธฐ: ChromaDB ํ™œ์šฉ

๋‚˜๋‚˜'s Brainยท2025๋…„ 3์›” 18์ผ
0

๊ฐœ๋…Study

๋ชฉ๋ก ๋ณด๊ธฐ
19/21
post-thumbnail

LLM ๊ธฐ๋ฐ˜์˜ RAG(Retrieval-Augmented Generation) ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ๋•Œ, ๋Œ€ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(Vector DB)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ChromaDB๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฒกํ„ฐ DB์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•œ๋‹ค. ๐Ÿ˜ญ๐Ÿ‘ฉโ€๐Ÿ’ป

๐Ÿ“Œ RAG ์‹œ์Šคํ…œ์—์„œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ ํƒํ•˜๊ธฐ

RAG(Retrieval-Augmented Generation) ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋ ค๋ฉด, ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ๋†’์ด๊ณ  ํšจ์œจ์ ์ธ ๋ฌธ์„œ ๊ฒ€์ƒ‰์„ ์œ„ํ•ด ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(Vector DB)๊ฐ€ ํ•„์ˆ˜๋‹ค.

๐Ÿ“Š ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ ํƒ ๊ธฐ์ค€

โœ” ๋ฐ์ดํ„ฐ ๊ทœ๋ชจ โ†’ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€
โœ” ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ โ†’ ๋น ๋ฅธ ์œ ์‚ฌ๋„ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•œ์ง€
โœ” ํ™•์žฅ์„ฑ โ†’ ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ์™€ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•œ์ง€
โœ” ํ˜ธํ™˜์„ฑ โ†’ LangChain๊ณผ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์ž˜ ํ†ตํ•ฉ๋˜๋Š”์ง€

๐Ÿ”Ž ์ฃผ์š” ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋น„๊ต

๋ฐ์ดํ„ฐ๋ฒ ์ด์ŠคํŠน์ง•์žฅ์ ๋‹จ์ 
FAISSFacebook AI ๊ฐœ๋ฐœ, ๋น ๋ฅธ ๊ทผ์‚ฌ ์ตœ๊ทผ์ ‘ ์ด์›ƒ ๊ฒ€์ƒ‰์˜คํ”ˆ์†Œ์Šค, ๋น ๋ฅธ ๊ฒ€์ƒ‰ ์†๋„ํด๋Ÿฌ์Šคํ„ฐ๋ง ๊ธฐ๋Šฅ ๋ถ€์กฑ
ChromaDBLangChain๊ณผ ํ˜ธํ™˜๋˜๋Š” ๋ฒกํ„ฐDB๊ฐ„ํŽธํ•œ ์‚ฌ์šฉ, ์˜คํ”ˆ์†Œ์Šค๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•œ๊ณ„
Pineconeํด๋ผ์šฐ๋“œ ๊ธฐ๋ฐ˜, AI ๊ฒ€์ƒ‰ ์ตœ์ ํ™”ํ™•์žฅ์„ฑ ๋›ฐ์–ด๋‚จ์œ ๋ฃŒ ๋ชจ๋ธ
Elasticsearchํ‚ค์›Œ๋“œ + ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ์ง€์›๋ณตํ•ฉ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ์„ค์ •์ด ๋ณต์žก

๐Ÿ‘‰ ๋‚ด๊ฐ€ ์„ ํƒํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค: ChromaDB

  • LangChain๊ณผ ํ˜ธํ™˜์„ฑ์ด ๋›ฐ์–ด๋‚˜๊ณ ,
  • ๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ,
  • ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•ด ์ดˆ๊ธฐ ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉํ•˜๋‹ค.

โš  ํ•˜์ง€๋งŒ ์ดํ›„ ํ”„๋กœ์ ํŠธ ํ™•์žฅ ์‹œ ๋‹ค๋ฅธ DB๋กœ ๊ต์ฒดํ•  ์ˆ˜๋„ ์žˆ์Œ

1๏ธโƒฃ ๋ฒกํ„ฐ DB ์„ค์ •ํ•˜๊ธฐ

์šฐ์„  ChromaDB๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค. ๋ฒกํ„ฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด Ollama ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ ์ €์žฅ์„ ์œ„ํ•œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

# Chroma ๋ฒกํ„ฐ DB ์„ค์ •
CHROMA_DB_DIR = "vectorstore"
embeddings = OllamaEmbeddings(model="llama3.1-instruct-8b:latest")
os.makedirs(CHROMA_DB_DIR, exist_ok=True)

โœ… ์„ค์ • ์ด์œ 

  • CHROMA_DB_DIR : ๋ฒกํ„ฐ DB ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
  • OllamaEmbeddings : ๋ฒกํ„ฐํ™”๋ฅผ ์œ„ํ•œ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ ์ง€์ •
  • os.makedirs() : ํด๋”๊ฐ€ ์—†์œผ๋ฉด ์ž๋™ ์ƒ์„ฑ

2๏ธโƒฃ ๋ฒกํ„ฐ DB์— ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ

๋ฉ”์‹œ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐํ™”ํ•˜์—ฌ ChromaDB์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž.

# ๋ฒกํ„ฐ DB ์ €์žฅ ํ•จ์ˆ˜
def save_to_vector_db(messages):
    try:
        # ChromaDB ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        vector_db = Chroma(embedding_function=embeddings, persist_directory=CHROMA_DB_DIR)
        
        # ๋ฉ”์‹œ์ง€๋ฅผ ํ•˜๋‚˜์˜ ํ…์ŠคํŠธ๋กœ ๊ฒฐํ•ฉํ•˜์—ฌ ๋ฒกํ„ฐํ™”
        combined_text = " ".join(messages)
        vectors = embeddings.embed_documents([combined_text])

        # ๊ณ ์œ  ID ์ƒ์„ฑ (๋ฌธ์„œ ๋‚ด์šฉ์˜ ํ•ด์‹œ๊ฐ’ ์‚ฌ์šฉ)
        doc_id = str(hash(combined_text))
        
        # Document ๊ฐ์ฒด ์ƒ์„ฑ
        document = Document(page_content=combined_text, metadata={"id": doc_id})
        
        # ChromaDB์— ์ €์žฅ
        vector_db.add_documents(
            documents=[document],
            embeddings=vectors,
            ids=[doc_id]
        )
        
        logger.info("๋ฒกํ„ฐ DB์— ๋ฉ”์‹œ์ง€ ์ €์žฅ ์„ฑ๊ณต")
    except Exception as e:
        logger.error(f"๋ฒกํ„ฐ DB ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")

โœ… ํ•ต์‹ฌ ๊ฐœ๋…

  • ๋ฒกํ„ฐํ™”(Embedding): ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์น˜ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜
  • ๊ณ ์œ  ID: ํ•ด์‹œ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต ์ €์žฅ ๋ฐฉ์ง€
  • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ: ๋ฌธ์„œ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์ €์žฅํ•˜์—ฌ ๊ฒ€์ƒ‰ ์‹œ ํ™œ์šฉ

3๏ธโƒฃ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ํ™•์ธํ•˜๊ธฐ

๋ฐ์ดํ„ฐ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ €์žฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

save_to_vector_db(input_data.messages)  # ๋ฉ”์‹œ์ง€ ์ €์žฅ ์‹คํ–‰

๐Ÿ“Œ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ํ™•์ธ ๋ฐฉ๋ฒ•

logger.info(f"Document saved: {doc_id}, Message: {message}")
documents = vector_db.get()
logger.info(f"์ „์ฒด ์กฐํšŒ: {documents}")

๋ฒกํ„ฐ DB ์ €์žฅ ํ™•์ธ

โœ… ๋ฒกํ„ฐ DB ์กฐํšŒ ๋ฐฉ๋ฒ•

  • ์ €์žฅ๋œ ๋ฌธ์„œ์˜ ID์™€ ๋‚ด์šฉ์„ ํ™•์ธ ๊ฐ€๋Šฅ
  • ์ „์ฒด ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๊ทธ๋กœ ์ถœ๋ ฅํ•˜์—ฌ ์ €์žฅ ์ƒํƒœ ํ™•์ธ ๊ฐ€๋Šฅ

4๏ธโƒฃ ํ™•์žฅ์„ฑ ๊ณ ๋ ค: ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

์ถ”ํ›„ ๊ฒ€์ƒ‰๊ณผ ๊ด€๋ฆฌ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด, ๋ฌธ์„œ ํƒ€์ž…(ํ…์ŠคํŠธ, PDF, ์›น ๋ฐ์ดํ„ฐ ๋“ฑ)์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

# ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ (๋ฌธ์„œ ํƒ€์ž… ๋ฐ ์ถœ์ฒ˜)
metadata = {
    "id": doc_id,
    "type": document_type,  # 'message', 'pdf', 'web'
    "source": "user_input"
}

OCR ๋ฉ”์‹œ์ง€ ๋ฒกํ„ฐํ™”

โœ… ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ์ด์œ 

  • ๋ฌธ์„œ ๊ตฌ๋ถ„ ๊ฐ€๋Šฅ (ํ…์ŠคํŠธ, PDF, ์›น ๋ฐ์ดํ„ฐ ๋“ฑ)
  • ์ถœ์ฒ˜ ์ •๋ณด ์ถ”๊ฐ€ (์–ด๋–ค ์œ ํ˜•์˜ ๋ฐ์ดํ„ฐ์ธ์ง€ ๊ธฐ๋ก)

5๏ธโƒฃ OCR ๋ฐ์ดํ„ฐ ์ €์žฅ ํ™•์ธ

OCR๋กœ ๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐ DB์— ์ €์žฅํ•  ๊ฒฝ์šฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.

OCR ์ €์žฅ ํ™•์ธ

โœ… OCR ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๋ฐฉ์‹

  • ์ด๋ฏธ์ง€์—์„œ ์ถ”์ถœ๋œ ํ…์ŠคํŠธ๋ฅผ ๋ฒกํ„ฐํ™”ํ•˜์—ฌ ์ €์žฅ
  • ์ผ๋ฐ˜ ํ…์ŠคํŠธ์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ

6๏ธโƒฃ API์—์„œ ๋ฒกํ„ฐ DB ํ™œ์šฉํ•˜๊ธฐ

FastAPI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ๋ฒกํ„ฐ DB๋ฅผ ๋Œ€ํ™”ํ˜• API์— ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

# ๋ฒกํ„ฐ DB๋ฅผ FastAPI ์—”๋“œํฌ์ธํŠธ์— ์ถ”๊ฐ€
async def chat(input: str = Form(...), file: Optional[UploadFile] = File(None),  document_type: str = "message", vector_db: Chroma = Depends(get_vector_db)):

๐Ÿ“Œ FastAPI ์˜์กด์„ฑ ์ฃผ์ž… (Dependency Injection)

# ๋ฒกํ„ฐ DB ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
def get_vector_db():
    global vector_db
    if vector_db is None:
        vector_db = Chroma(embedding_function=embeddings, persist_directory=CHROMA_DB_DIR)
        logger.info("๋ฒกํ„ฐ DB ์—ฐ๊ฒฐ ์™„๋ฃŒ")
    return vector_db

โœ… ์ด์ 

  • FastAPI์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)์„ ํ†ตํ•ด ChromaDB ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
  • API ํ˜ธ์ถœ ์‹œ ์ž๋™์œผ๋กœ ChromaDB ์—ฐ๊ฒฐ ๋ฐ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ

๐Ÿš€ ์ตœ์ข… ๊ตฌํ˜„ ์ •๋ฆฌ

โœ… ํ˜„์žฌ๊นŒ์ง€ ๊ตฌํ˜„๋œ ๊ธฐ๋Šฅ

  • ๋ฒกํ„ฐ DB ์ €์žฅ: ๋ฉ”์‹œ์ง€๋ฅผ ๋ฒกํ„ฐํ™”ํ•˜์—ฌ ChromaDB์— ์ €์žฅ
  • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ถ”๊ฐ€: ๋ฌธ์„œ ์œ ํ˜• ๋ฐ ์ถœ์ฒ˜ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์ €์žฅ
  • API ์—ฐ๋™: FastAPI๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฒกํ„ฐ DB๋ฅผ ํ™œ์šฉํ•œ ๋Œ€ํ™”ํ˜• ์„œ๋น„์Šค ๊ตฌ์ถ•
  • ๋กœ๊ทธ ๊ด€๋ฆฌ: ์ €์žฅ๋œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ ํ™•์ธ ๊ฐ€๋Šฅ

โœ… ๋‹ค์Œ ๋ชฉํ‘œ

  • ์›น ํŽ˜์ด์ง€ ๋ฐ PDF ๋‚ด์šฉ์„ ๋ฒกํ„ฐ DB์— ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • ๋ฒกํ„ฐ DB ์ตœ์ ํ™” ๋ฐ ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • PostgreSQL๊ณผ ์—ฐ๋™ํ•˜์—ฌ AI ์‘๋‹ต์„ ์ €์žฅ ๋ฐ ๊ด€๋ฆฌ

โšก ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๋ฉด์„œ ์ตœ์ ํ™” ๋ฐ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ๊ฐ•ํ™”ํ•ด๋ณด์ž....!!

profile
"๋กœ์ปฌ์—์„  ๋ฌธ์ œ์—†์—ˆ๋Š”๋ฐโ€ฆ?"

0๊ฐœ์˜ ๋Œ“๊ธ€